logjam_agent 0.37.1 → 0.38.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 742e6f9309275b7812a62a148595786476ca341a7082b95e1befda8e2e5ab695
4
- data.tar.gz: c83bd0d0ec3d9c5c48b551b2c1f21d11f70fc2bb770a64ee945f63385a57515b
3
+ metadata.gz: 47422acd5b4e45b015b0409e1c92cbe469fe883f6d7ae92eaa213434822f460c
4
+ data.tar.gz: 204958e60d5036f5d63c779b7af46dd2705aa6a0ba2be0145bb7c8780c72b849
5
5
  SHA512:
6
- metadata.gz: 25885e7f6b4471efe71c4b94faffdd2722f9148664eb97a9793b72a41a2db018b0d71a5e7bf3cb0a04e151389d29084be515f2ba3bd65db5b5aa449e6922e853
7
- data.tar.gz: 44bf35a0e932444aaac1c0152520d23b62c4208ac56154470ebd5eb7f259275e9bd05d7ee9c0577a4c7a6c9ef648041a6a969a6ae7843ec6249c90367f8eaa67
6
+ metadata.gz: b55dd07ab0d558ca83236a7971d7cd45116418b026ecf8bb9bc05fb435facd5896584f1f8f9d9e4cc657571001ed2613a4bbadcbd12c253af07cbf96fbba30bb
7
+ data.tar.gz: 53288566b7cb06d28a5129f71b4bc236569f0f259595ad14a603baa07085d93ebb25ac031e634096206409ec4b0da6b2d4e332f1ff8dfece3ddf89818eb01d23
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,62 @@ 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
+ message = message.to_s
126
+ if request && severity >= Logger::ERROR && (e = detect_logged_exception(message))
127
+ request.add_exception(e)
128
+ end
129
+ end
130
+ prepend_attribute_tags(message)
131
+ end
132
+
133
+ def prepend_attribute_tags(message)
134
+ attributes = formatter.render_attributes
135
+ message = "[#{attributes}] #{message}" if attributes
136
+ message
137
+ end
138
+
139
+ def encode_log_message(message_hash)
140
+ attrs = formatter.non_nil_attributes.to_h
141
+ msg = attrs.merge(message_hash)
142
+ LogjamAgent.json_encode_payload(msg)
143
+ end
102
144
  end
103
145
  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.1"
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,121 @@
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
+ def test_can_log_arrays_as_text
104
+ LogjamAgent.log_format = :text
105
+ @logger.error([1, 2])
106
+ assert_equal 1, @lines.size
107
+ assert_equal([1, 2].to_s, @lines.first.last)
108
+ assert_equal 1, @device.lines.size
109
+ assert_match(/ERROR -- : \[1, 2\]\n/, @device.lines.first)
110
+ end
111
+
112
+ def test_can_log_arrays_as_json
113
+ LogjamAgent.log_format = :json
114
+ @logger.error([1, 2])
115
+ assert_equal 1, @lines.size
116
+ assert_equal([1, 2].to_s, @lines.first.last)
117
+ assert_equal 1, @device.lines.size
118
+ assert_match(/ERROR -- : \{"message":"\[1, 2\]"\}\n/, @device.lines.first)
119
+ end
120
+ end
121
+ 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,14 +1,14 @@
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.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefan Kaes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-25 00:00:00.000000000 Z
11
+ date: 2022-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -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