logjam_agent 0.37.1 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 742e6f9309275b7812a62a148595786476ca341a7082b95e1befda8e2e5ab695
4
- data.tar.gz: c83bd0d0ec3d9c5c48b551b2c1f21d11f70fc2bb770a64ee945f63385a57515b
3
+ metadata.gz: ca457f9e8f19c2915d63445f3c7f63bfccb4cc61d260b5e164cd80e5440c5659
4
+ data.tar.gz: 2b58eeaa872b742b11faac8156354e551cce37c4dd15a33d594e2e05c794bbe9
5
5
  SHA512:
6
- metadata.gz: 25885e7f6b4471efe71c4b94faffdd2722f9148664eb97a9793b72a41a2db018b0d71a5e7bf3cb0a04e151389d29084be515f2ba3bd65db5b5aa449e6922e853
7
- data.tar.gz: 44bf35a0e932444aaac1c0152520d23b62c4208ac56154470ebd5eb7f259275e9bd05d7ee9c0577a4c7a6c9ef648041a6a969a6ae7843ec6249c90367f8eaa67
6
+ metadata.gz: 0ca5aead4424e9cb01dfaf099f889a772099f3320173ba6af6d4d8aa80bd2972173cdfba69c8a3555f55caef723799871c916332b9e52b62ea516e941c7e6961
7
+ data.tar.gz: 855bb281cfadd0485df1a2e2d2a446d502687ce03d35a5ab0fca80ad4d3a520296c1ff4650addc4c2a3149094a1834b897c1f8e2e7bc5efe5bdfb3fd4332b329
data/README.md CHANGED
@@ -182,6 +182,26 @@ Using one of the logjam helpers `LogjamAgent.logjam_only` or
182
182
  `LogjamAgent.logdevice_only` it is possible to send information to
183
183
  only one of those log line sinks for the duration of a given block.
184
184
 
185
+ ## JSON Logging
186
+
187
+ When `LogjamAgent.log_format` is set to `:json`, the logjam agent
188
+ logger will make sure that the content of line logged to the log
189
+ device is converted to JSON.
190
+
191
+ ```ruby
192
+ Rails.logger.info("foobar is great!")
193
+ # ----->
194
+ { "message": "foobar is great!"}
195
+
196
+ Rails.logger.info(message: "foobar", user: 5)
197
+ # ----->
198
+ { "message": "foobar", "user": 5 }
199
+
200
+ e = Standard::Error.new()
201
+ Rails.logger.info(e)
202
+ # ----->
203
+ { "message": "#{e.message}", "error": <execption with formatted backtrace> }
204
+ ```
185
205
 
186
206
  ## Troubleshooting
187
207
 
@@ -47,25 +47,16 @@ module LogjamAgent
47
47
  progname = nil
48
48
  message ||= block.call || '' if block
49
49
  request = LogjamAgent.request
50
- if message.is_a?(Exception)
51
- request.add_exception(message.class.to_s, severity) if request
52
- message = format_exception(message)
53
- else
54
- message = message.to_s
55
- if request && severity >= Logger::ERROR && (e = detect_logged_exception(message))
56
- request.add_exception(e)
57
- end
58
- end
59
- log_to_log_device = LogjamAgent.log_to_log_device?(severity, message)
60
- log_to_log_device = false if request && request.ignored?
61
- attributes = formatter.render_attributes
62
- message = "[#{attributes}] #{message}" if attributes
50
+ logjam_message = format_message_for_logjam(message, request, severity)
63
51
  time = Time.now
52
+ request.add_line(severity, time, logjam_message) if request && !SelectiveLogging.logdevice_only?
53
+ log_to_log_device = LogjamAgent.log_to_log_device?(severity, logjam_message)
54
+ log_to_log_device = false if request && request.ignored?
64
55
  if log_to_log_device && !SelectiveLogging.logjam_only?
65
- formatted_message = formatter.call(format_severity(severity), time, progname, message)
56
+ device_message = format_message_for_log_device(message)
57
+ formatted_message = formatter.call(format_severity(severity), time, progname, device_message)
66
58
  @logdev.write(formatted_message) if @logdev
67
59
  end
68
- request.add_line(severity, time, message) if request && !SelectiveLogging.logdevice_only?
69
60
  message
70
61
  end
71
62
 
@@ -93,11 +84,61 @@ module LogjamAgent
93
84
  def format_exception(exception)
94
85
  msg = "#{exception.class}(#{exception.message})"
95
86
  if backtrace = exception.backtrace
96
- backtrace = Rails.backtrace_cleaner.clean(backtrace, :all) if defined?(Rails)
87
+ backtrace = Rails.backtrace_cleaner.clean(backtrace, :all) if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
97
88
  msg << ":\n #{backtrace.join("\n ")}"
98
89
  else
99
90
  msg
100
91
  end
101
92
  end
93
+
94
+ def format_message_for_log_device(message, format: LogjamAgent.log_format)
95
+ case message
96
+ when Exception
97
+ if format == :json
98
+ encode_log_message(message: message.message, error: format_exception(message))
99
+ else
100
+ prepend_attribute_tags(format_exception(message))
101
+ end
102
+ when Hash
103
+ if format == :json
104
+ encode_log_message(message)
105
+ else
106
+ prepend_attribute_tags(LogjamAgent.json_encode_payload(message))
107
+ end
108
+ else
109
+ if format == :json
110
+ encode_log_message(message: message.to_s)
111
+ else
112
+ prepend_attribute_tags(message)
113
+ end
114
+ end
115
+ end
116
+
117
+ def format_message_for_logjam(message, request, severity)
118
+ case message
119
+ when Exception
120
+ request.add_exception(message.class.to_s, severity) if request
121
+ message = format_exception(message)
122
+ when Hash
123
+ message = LogjamAgent.json_encode_payload(message)
124
+ else
125
+ if request && severity >= Logger::ERROR && (e = detect_logged_exception(message))
126
+ request.add_exception(e)
127
+ end
128
+ end
129
+ prepend_attribute_tags(message)
130
+ end
131
+
132
+ def prepend_attribute_tags(message)
133
+ attributes = formatter.render_attributes
134
+ message = "[#{attributes}] #{message}" if attributes
135
+ message
136
+ end
137
+
138
+ def encode_log_message(message_hash)
139
+ attrs = formatter.non_nil_attributes.to_h
140
+ msg = attrs.merge(message_hash)
141
+ LogjamAgent.json_encode_payload(msg)
142
+ end
102
143
  end
103
144
  end
@@ -25,9 +25,13 @@ module LogjamAgent
25
25
  end
26
26
 
27
27
  def render_attributes
28
- attrs = attributes.select{|k,v| !k.nil? }
28
+ attrs = non_nil_attributes
29
29
  attrs.empty? ? nil : attrs.map{|k,v| "#{k}=#{v}"}.join(" ")
30
30
  end
31
31
 
32
+ def non_nil_attributes
33
+ attributes.select{|k,v| !k.nil? }
34
+ end
35
+
32
36
  end
33
37
  end
@@ -162,7 +162,11 @@ module LogjamAgent
162
162
  logjam_request.log_info[:status] = status
163
163
  logjam_request.log_info[:duration] = run_time_ms
164
164
  # logjam_request.log_info[:metrics] = TimeBandits.metrics.reject{|k,v| v.zero?}
165
- info "Completed: #{logjam_request.log_info.to_json}"
165
+ if LogjamAgent.log_format == :json
166
+ info message: "Completed #{http_status}", **logjam_request.log_info
167
+ else
168
+ info "Completed: #{logjam_request.log_info.to_json}"
169
+ end
166
170
  end
167
171
  end
168
172
 
@@ -1,3 +1,3 @@
1
1
  module LogjamAgent
2
- VERSION = "0.37.1"
2
+ VERSION = "0.38.0"
3
3
  end
data/lib/logjam_agent.rb CHANGED
@@ -28,6 +28,9 @@ module LogjamAgent
28
28
  mattr_accessor :logger
29
29
  self.logger = nil
30
30
 
31
+ mattr_accessor :log_format
32
+ self.log_format = :text
33
+
31
34
  mattr_accessor :forwarding_error_logger
32
35
  self.forwarding_error_logger = nil
33
36
 
@@ -0,0 +1,104 @@
1
+ require_relative "test_helper.rb"
2
+
3
+ module LogjamAgent
4
+ class JsonLoggingTest < MiniTest::Test
5
+ def setup
6
+ @request = LogjamAgent.request = Request.new("app", "env", {})
7
+ @lines = @request.instance_variable_get :@lines
8
+ @logger = BufferedLogger.new(File::NULL)
9
+ @device = MockLogDev.new
10
+ @logger.logdev = @device
11
+ end
12
+
13
+ def teardown
14
+ LogjamAgent.log_format = :text
15
+ LogjamAgent.request = nil
16
+ LogjamAgent.selective_logging_enabled = true
17
+ end
18
+
19
+ def test_can_log_strings_in_json
20
+ LogjamAgent.log_format = :json
21
+ @logger.info("a silly string")
22
+ assert_equal 1, @lines.size
23
+ assert_equal "a silly string", @lines.first.last
24
+ assert_equal 1, @device.lines.size
25
+ assert_match(/"message":"a silly string"}\n/, @device.lines.first)
26
+ end
27
+
28
+ def test_can_log_hashes_in_json
29
+ LogjamAgent.log_format = :json
30
+ @logger.info({a: 1})
31
+ assert_equal 1, @lines.size
32
+ assert_equal '{"a":1}', @lines.first.last
33
+ assert_equal 1, @device.lines.size
34
+ assert_match(/\{"a":1\}\n/, @device.lines.first)
35
+ end
36
+
37
+ def test_can_log_exceptions_in_json
38
+ LogjamAgent.log_format = :json
39
+ @logger.error(StandardError.new("look ma, an exeption!"))
40
+ assert_equal 1, @lines.size
41
+ assert_equal 'StandardError(look ma, an exeption!)', @lines.first.last
42
+ assert_equal 1, @device.lines.size
43
+ assert_match(/ERROR -- : \{"message":"look ma, an exeption!","error":"StandardError\(look ma, an exeption!\)"\}\n/, @device.lines.first)
44
+ end
45
+
46
+ def test_can_log_exceptions_with_backtrace_as_json
47
+ LogjamAgent.log_format = :json
48
+ e = raise "murks" rescue $!
49
+ @logger.error(e)
50
+ assert_equal 1, @lines.size
51
+ assert_match(/RuntimeError\(murks\):(\n.*\.rb:\d+:in\s.*)+/, @lines.first.last)
52
+ assert_equal 1, @device.lines.size
53
+ assert_match(/ERROR -- : {"message":"murks","error":"RuntimeError\(murks\):(\\n.*\.rb:\d+:in\s.*)+"}\n/, @device.lines.first)
54
+ end
55
+
56
+ def test_log_syntax_in_json
57
+ LogjamAgent.log_format = :json
58
+ h = {a: 1}
59
+ @logger.info(message: "foo", **h)
60
+ assert_equal 1, @lines.size
61
+ assert_equal '{"message":"foo","a":1}', @lines.first.last
62
+ assert_equal 1, @device.lines.size
63
+ assert_match(/\{"message":"foo","a":1\}\n/, @device.lines.first)
64
+ end
65
+
66
+ def test_can_log_strings_as_text
67
+ LogjamAgent.log_format = :text
68
+ @logger.info("a silly string")
69
+ assert_equal 1, @lines.size
70
+ assert_equal "a silly string", @lines.first.last
71
+ assert_equal 1, @device.lines.size
72
+ assert_match(/INFO -- : a silly string\n/, @device.lines.first)
73
+ end
74
+
75
+ def test_can_log_hashes_as_text
76
+ LogjamAgent.log_format = :text
77
+ @logger.info({a: 1})
78
+ assert_equal 1, @lines.size
79
+ assert_equal '{"a":1}', @lines.first.last
80
+ assert_equal 1, @device.lines.size
81
+ assert_match(/\{"a":1\}\n/, @device.lines.first)
82
+ end
83
+
84
+ def test_can_log_exceptions_as_text
85
+ LogjamAgent.log_format = :text
86
+ @logger.error(StandardError.new("look ma, an exeption!"))
87
+ assert_equal 1, @lines.size
88
+ assert_equal 'StandardError(look ma, an exeption!)', @lines.first.last
89
+ assert_equal 1, @device.lines.size
90
+ assert_match(/ERROR -- : StandardError\(look ma, an exeption!\)\n/, @device.lines.first)
91
+ end
92
+
93
+ def test_can_log_exceptions_with_backtrace_as_text
94
+ LogjamAgent.log_format = :text
95
+ e = raise "murks" rescue $!
96
+ @logger.error(e)
97
+ assert_equal 1, @lines.size
98
+ assert_match(/RuntimeError\(murks\):(\n.*\.rb:\d+:in\s.*)+/, @lines.first.last)
99
+ assert_equal 1, @device.lines.size
100
+ assert_match(/ERROR -- : RuntimeError\(murks\):(\n.*\.rb:\d+:in\s.*)+/, @device.lines.first)
101
+ end
102
+
103
+ end
104
+ end
@@ -2,16 +2,6 @@ require_relative "test_helper.rb"
2
2
 
3
3
  module LogjamAgent
4
4
  class SelectiveLoggingTest < MiniTest::Test
5
- class MockLogDev
6
- attr_reader :lines
7
- def initialize
8
- @lines = []
9
- end
10
- def write(s)
11
- @lines << s
12
- end
13
- end
14
-
15
5
  def setup
16
6
  @request = LogjamAgent.request = Request.new("app", "env", {})
17
7
  @lines = @request.instance_variable_get :@lines
data/test/test_helper.rb CHANGED
@@ -14,3 +14,13 @@ require "logjam_agent/receiver"
14
14
 
15
15
  # for Sinatra
16
16
  ENV['RACK_ENV'] = "test"
17
+
18
+ class MockLogDev
19
+ attr_reader :lines
20
+ def initialize
21
+ @lines = []
22
+ end
23
+ def write(s)
24
+ @lines << s
25
+ end
26
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logjam_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.1
4
+ version: 0.38.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Kaes
@@ -251,6 +251,7 @@ files:
251
251
  - lib/logjam_agent/util.rb
252
252
  - lib/logjam_agent/version.rb
253
253
  - lib/logjam_agent/zmq_forwarder.rb
254
+ - test/json_logging_test.rb
254
255
  - test/request_test.rb
255
256
  - test/selective_logging_test.rb
256
257
  - test/sinatra_app.rb
@@ -292,4 +293,5 @@ test_files:
292
293
  - test/zmq_forwarder_test.rb
293
294
  - test/util_test.rb
294
295
  - test/test_helper.rb
296
+ - test/json_logging_test.rb
295
297
  - test/sinatra_test.rb