lumberjack_data_dog_device 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 60c74e54590298ee33cfbb9d042360094f58277417e7ce3827fd3c65d26a0f0d
4
+ data.tar.gz: 772bed3d6c5f1908b9929e55dae07479ae02ce04942cd515b6c587cc1792b044
5
+ SHA512:
6
+ metadata.gz: f542690e1f9b8ad79c0673d59ab4fbf42f6733e98fda5f4845c00aad05fbb5da2a7b8db67bd19452a5b31269d48cafe015733539669527bd05e6cfc65fe4e3b7
7
+ data.tar.gz: 760efdee4a408fa4b52c123a0da1f7daee2a123c657c75cf145770e19959e1e62e734d902aa54dfb86deeb5dfa926d69ab50b2d244fdace2c5b4833a35a4e8ee
@@ -0,0 +1,3 @@
1
+ # 1.0.0
2
+
3
+ * Initial release
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2020 Brian Durand
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,37 @@
1
+ # Lumberjack DataDog Device
2
+
3
+ [![Build Status](https://travis-ci.org/bdurand/lumberjack_data_dog_device.svg?branch=master)](https://travis-ci.org/bdurand/lumberjack_data_dog_device)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/372103b5d762c765a16e/maintainability)](https://codeclimate.com/github/bdurand/lumberjack_data_dog_device/maintainability)
5
+
6
+ This gem provides a logging device that produces JSON output that matches the standard fields defined for [DataDog logging](https://docs.datadoghq.com/logs/processing/attributes_naming_convention/).
7
+
8
+ * The time will be sent as "timestamp" with a precision in microseconds.
9
+
10
+ * The severity will be sent as "status" with a string label (DEBUG, INFO, WARN, ERROR, FATAL).
11
+
12
+ * The progname will be sent as "logger.name"
13
+
14
+ * The pid will be sent as "pid".
15
+
16
+ * The message will be sent as "message". In addition, if the message is an exception, the error message, class, and backtrace will be sent as "error.message", "error.kind", and "error.trace".
17
+
18
+ * If the "error" tag contains an exception, it will be sent as "error.message", "error.kind", and "error.trace".
19
+
20
+ * A duration can be sent as a number of seconds in the "duration" tag or as a number of milliseconds in the "duration_ms" tag or as a number of microsectons in the "duration_micros" tag or as a number of nanoseconds in the "duration_ns" tag.
21
+
22
+ * All other tags are sent as is. If a tag name includes a dot, it will be sent as a nested JSON structure.
23
+
24
+ This device extends from [`Lumberjack::JsonDevice`](). It is not tied to Data Dog in any way other than that it is opinionated about how to map and format some log tags. It can be used with other services or pipelines without issue.
25
+
26
+ ## Example
27
+
28
+ You could log an HTTP request to some of the DataDog standard fields like this:
29
+
30
+ ```ruby
31
+ logger.tag("http.method" => request.method, "http.url" => request.url) do
32
+ logger.info("#{request.method} #{request.path} finished in #{elapsed_time} seconds",
33
+ duration: elapsed_time,
34
+ "http.status_code" => response.status
35
+ )
36
+ end
37
+ ```
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "lumberjack_json_device"
4
+
5
+ module Lumberjack
6
+ # This Lumberjack device logs output to another device as JSON formatted text that maps fields
7
+ # to the standard JSON payload for DataDog log collection.
8
+ #
9
+ # See https://docs.datadoghq.com/logs/log_collection
10
+ class DataDogDevice < JsonDevice
11
+
12
+ module ExceptionHash
13
+
14
+ protected
15
+
16
+ def exception_hash(exception, device)
17
+ hash = {"kind" => exception.class.name}
18
+ hash["message"] = exception.message unless exception.message.nil?
19
+ trace = exception.backtrace
20
+ if trace && device && device.respond_to?(:backtrace_cleaner) && device.backtrace_cleaner
21
+ trace = device.backtrace_cleaner.call(trace)
22
+ end
23
+ hash["trace"] = trace if trace
24
+ hash
25
+ end
26
+ end
27
+
28
+ # Formatter to format a messge as an error if it is an exception.
29
+ class MessageExceptionFormatter
30
+ include ExceptionHash
31
+
32
+ def initialize(device = nil)
33
+ @device = device
34
+ end
35
+
36
+ def call(object)
37
+ if object.is_a?(Exception)
38
+ {
39
+ "message" => object.inspect,
40
+ "error" => exception_hash(object, @device)
41
+ }
42
+ else
43
+ { "message" => object }
44
+ end
45
+ end
46
+ end
47
+
48
+ # Formatter to remove empty tag values and expand the error tag if it is an exception.
49
+ class DataDogTagsFormatter
50
+ include ExceptionHash
51
+
52
+ def initialize(device = nil)
53
+ @device = device
54
+ end
55
+
56
+ def call(tags)
57
+ copy = {}
58
+ tags.each do |name, value|
59
+ value = remove_empty_values(value)
60
+ next if value.nil?
61
+
62
+ if name == "error" && value.is_a?(Exception)
63
+ copy[name] = exception_hash(value, @device)
64
+ elsif name.include?(".")
65
+ names = name.split(".")
66
+ next_value_in_hash(copy, names, value)
67
+ else
68
+ copy[name] = value
69
+ end
70
+ end
71
+ copy
72
+ end
73
+
74
+ private
75
+
76
+ def remove_empty_values(value)
77
+ if value.is_a?(String)
78
+ value unless value.empty?
79
+ elsif value.is_a?(Hash)
80
+ new_hash = {}
81
+ value.each do |key, val|
82
+ val = remove_empty_values(val)
83
+ new_hash[key] = val unless val.nil?
84
+ end
85
+ new_hash unless new_hash.empty?
86
+ elsif value.is_a?(Array)
87
+ new_array = value.collect { |val| remove_empty_values(val) }
88
+ new_array unless new_array.empty?
89
+ else
90
+ value
91
+ end
92
+ end
93
+
94
+ def next_value_in_hash(hash, keys, value)
95
+ key = keys.first
96
+ if keys.size == 1
97
+ hash[key] = value
98
+ else
99
+ current = hash[key]
100
+ unless current.is_a?(Hash)
101
+ current = {}
102
+ hash[key] = current
103
+ end
104
+ next_value_in_hash(current, keys[1, keys.size], value)
105
+ end
106
+ end
107
+ end
108
+
109
+ class DurationFormatter
110
+ def initialize(multiplier)
111
+ @multiplier = multiplier
112
+ end
113
+
114
+ def call(value)
115
+ if value.is_a?(Numeric)
116
+ value = (value.to_f * @multiplier).round
117
+ end
118
+ { "duration" => value }
119
+ end
120
+ end
121
+
122
+ # You can specify a backtrace cleaner that will be called with exception backtraces before they
123
+ # are added to the payload. You can use this to remove superfluous lines, compress line length, etc.
124
+ # One use for it is to keep stack traces clean and prevent them from overflowing the limit on
125
+ # the payload size for an individual log entry.
126
+ attr_accessor :backtrace_cleaner
127
+
128
+ def initialize(stream_or_device, backtrace_cleaner: nil)
129
+ super(stream_or_device, mapping: data_dog_mapping)
130
+ self.backtrace_cleaner = backtrace_cleaner
131
+ end
132
+
133
+ private
134
+
135
+ def data_dog_mapping
136
+ {
137
+ time: "timestamp",
138
+ severity: "status",
139
+ progname: ["logger", "name"],
140
+ pid: "pid",
141
+ message: MessageExceptionFormatter.new(self),
142
+ duration: DurationFormatter.new(1_000_000_000),
143
+ duration_ms: DurationFormatter.new(1_000_000),
144
+ duration_micros: DurationFormatter.new(1_000),
145
+ duration_ns: "duration",
146
+ tags: DataDogTagsFormatter.new(self)
147
+ }
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,33 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'lumberjack_data_dog_device'
3
+ spec.version = File.read(File.expand_path("../VERSION", __FILE__)).strip
4
+ spec.authors = ['Brian Durand']
5
+ spec.email = ['bbdurand@gmail.com']
6
+
7
+ spec.summary = "A logging device for sending logs to DataDog in JSON format."
8
+ spec.homepage = "https://github.com/bdurand/lumberjack_data_dog_device"
9
+ spec.license = "MIT"
10
+
11
+ # Specify which files should be added to the gem when it is released.
12
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
13
+ ignore_files = %w(
14
+ .gitignore
15
+ .travis.yml
16
+ Appraisals
17
+ Gemfile
18
+ Gemfile.lock
19
+ Rakefile
20
+ gemfiles/
21
+ spec/
22
+ )
23
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
24
+ `git ls-files -z`.split("\x0").reject{ |f| ignore_files.any?{ |path| f.start_with?(path) } }
25
+ end
26
+
27
+ spec.require_paths = ['lib']
28
+
29
+ spec.add_dependency "lumberjack_json_device", ">=1.0"
30
+
31
+ spec.add_development_dependency("rspec", ["~> 3.0"])
32
+ spec.add_development_dependency "rake"
33
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lumberjack_data_dog_device
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Durand
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lumberjack_json_device
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description:
56
+ email:
57
+ - bbdurand@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGE_LOG.md
63
+ - MIT_LICENSE
64
+ - README.md
65
+ - VERSION
66
+ - lib/lumberjack_data_dog_device.rb
67
+ - lumberjack_data_dog_device.gemspec
68
+ homepage: https://github.com/bdurand/lumberjack_data_dog_device
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.0.3
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: A logging device for sending logs to DataDog in JSON format.
91
+ test_files: []