semantic_logger 3.4.1 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -0
  3. data/Rakefile +4 -8
  4. data/lib/semantic_logger.rb +2 -31
  5. data/lib/semantic_logger/appender.rb +76 -0
  6. data/lib/semantic_logger/appender/bugsnag.rb +3 -8
  7. data/lib/semantic_logger/appender/file.rb +1 -1
  8. data/lib/semantic_logger/appender/honeybadger.rb +1 -1
  9. data/lib/semantic_logger/appender/http.rb +1 -1
  10. data/lib/semantic_logger/appender/mongodb.rb +30 -28
  11. data/lib/semantic_logger/appender/sentry.rb +2 -2
  12. data/lib/semantic_logger/appender/splunk_http.rb +4 -4
  13. data/lib/semantic_logger/appender/syslog.rb +2 -2
  14. data/lib/semantic_logger/appender/tcp.rb +9 -5
  15. data/lib/semantic_logger/appender/udp.rb +1 -0
  16. data/lib/semantic_logger/base.rb +73 -140
  17. data/lib/semantic_logger/core_ext/thread.rb +4 -1
  18. data/lib/semantic_logger/formatters/color.rb +7 -0
  19. data/lib/semantic_logger/formatters/default.rb +7 -0
  20. data/lib/semantic_logger/formatters/syslog.rb +1 -1
  21. data/lib/semantic_logger/log.rb +115 -12
  22. data/lib/semantic_logger/logger.rb +6 -215
  23. data/lib/semantic_logger/metrics/new_relic.rb +1 -1
  24. data/lib/semantic_logger/metrics/statsd.rb +5 -1
  25. data/lib/semantic_logger/metrics/udp.rb +80 -0
  26. data/lib/semantic_logger/processor.rb +235 -0
  27. data/lib/semantic_logger/semantic_logger.rb +36 -65
  28. data/lib/semantic_logger/subscriber.rb +2 -2
  29. data/lib/semantic_logger/version.rb +1 -1
  30. data/test/appender/bugsnag_test.rb +10 -9
  31. data/test/appender/elasticsearch_test.rb +3 -2
  32. data/test/appender/graylog_test.rb +4 -3
  33. data/test/appender/honeybadger_test.rb +2 -2
  34. data/test/appender/http_test.rb +3 -2
  35. data/test/appender/mongodb_test.rb +24 -23
  36. data/test/appender/new_relic_test.rb +15 -8
  37. data/test/appender/sentry_test.rb +2 -2
  38. data/test/appender/splunk_http_test.rb +8 -7
  39. data/test/appender/splunk_test.rb +6 -5
  40. data/test/appender/tcp_test.rb +3 -4
  41. data/test/appender/udp_test.rb +4 -5
  42. data/test/appender/wrapper_test.rb +37 -38
  43. data/test/concerns/compatibility_test.rb +2 -2
  44. data/test/loggable_test.rb +1 -1
  45. data/test/logger_test.rb +149 -528
  46. data/test/measure_test.rb +249 -0
  47. data/test/semantic_logger_test.rb +257 -0
  48. metadata +24 -16
@@ -85,13 +85,13 @@ class CompatibilityTest < Minitest::Test
85
85
  end
86
86
 
87
87
  it '#formatter NOOP' do
88
- assert_equal nil, @logger.formatter
88
+ assert_nil @logger.formatter
89
89
  @logger.formatter = 'blah'
90
90
  assert_equal 'blah', @logger.formatter
91
91
  end
92
92
 
93
93
  it '#datetime_format NOOP' do
94
- assert_equal nil, @logger.datetime_format
94
+ assert_nil @logger.datetime_format
95
95
  @logger.datetime_format = 'blah'
96
96
  assert_equal 'blah', @logger.datetime_format
97
97
  end
@@ -42,7 +42,7 @@ class AppenderFileTest < Minitest::Test
42
42
 
43
43
  it 'should give child objects their own logger' do
44
44
  subclass = Subclass.new
45
- base = Base.new
45
+ base = Base.new
46
46
  assert_equal subclass.class.name, subclass.logger.name
47
47
  assert_equal base.class.name, base.logger.name
48
48
  assert_equal subclass.class.name, subclass.logger.name
data/test/logger_test.rb CHANGED
@@ -3,593 +3,214 @@ require_relative 'test_helper'
3
3
  # Unit Test for SemanticLogger::Logger
4
4
  class LoggerTest < Minitest::Test
5
5
  describe SemanticLogger::Logger do
6
- describe '.add_appender' do
7
- before do
8
- @appender = nil
9
- end
10
-
11
- after do
12
- SemanticLogger.remove_appender(@appender)
13
- File.delete('sample.log') if File.exist?('sample.log')
14
- end
15
-
16
- it 'adds file appender' do
17
- @appender = SemanticLogger.add_appender(file_name: 'sample.log')
18
- assert @appender.is_a?(SemanticLogger::Appender::File)
19
- assert SemanticLogger.appenders.include?(@appender)
20
- assert @appender.formatter.is_a?(SemanticLogger::Formatters::Default)
21
- end
22
-
23
- it 'adds file appender with json format' do
24
- @appender = SemanticLogger.add_appender(file_name: 'sample.log', formatter: :json)
25
- assert @appender.is_a?(SemanticLogger::Appender::File)
26
- assert SemanticLogger.appenders.include?(@appender)
27
- assert @appender.formatter.is_a?(SemanticLogger::Formatters::Json)
28
- end
29
-
30
- it 'adds stream appender' do
31
- @appender = SemanticLogger.add_appender(io: STDOUT)
32
- assert @appender.is_a?(SemanticLogger::Appender::File)
33
- assert SemanticLogger.appenders.include?(@appender)
34
- end
35
-
36
- it 'adds symbol appender' do
37
- @appender = SemanticLogger.add_appender(appender: :wrapper, logger: Logger.new(STDOUT))
38
- assert @appender.is_a?(SemanticLogger::Appender::Wrapper), -> { @appender.ai }
39
- assert SemanticLogger.appenders.include?(@appender)
40
- end
41
-
42
- it 'adds symbol appender with underscores' do
43
- @appender = SemanticLogger.add_appender(appender: :new_relic)
44
- assert @appender.is_a?(SemanticLogger::Appender::NewRelic), -> { @appender.ai }
45
- assert SemanticLogger.appenders.include?(@appender)
46
- end
47
-
48
- it 'adds logger wrapper appender' do
49
- @appender = SemanticLogger.add_appender(logger: ::Logger.new(STDOUT))
50
- assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
51
- assert @appender.logger.is_a?(::Logger)
52
- assert SemanticLogger.appenders.include?(@appender)
53
- assert @appender.formatter.is_a?(SemanticLogger::Formatters::Default)
54
- end
55
-
56
- it 'adds logger wrapper appender with color formatter' do
57
- @appender = SemanticLogger.add_appender(logger: ::Logger.new(STDOUT), formatter: :color)
58
- assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
59
- assert @appender.logger.is_a?(::Logger)
60
- assert SemanticLogger.appenders.include?(@appender)
61
- assert @appender.formatter.is_a?(SemanticLogger::Formatters::Color)
62
- end
63
-
64
- it 'adds appender' do
65
- @appender = SemanticLogger.add_appender(appender: SemanticLogger::Appender::File.new(io: STDOUT))
66
- assert @appender.is_a?(SemanticLogger::Appender::File), @appender.ai
67
- assert SemanticLogger.appenders.include?(@appender)
68
- end
69
-
70
- it 'fails to add invalid logger appender' do
71
- assert_raises do
72
- SemanticLogger.add_appender(logger: 'blah')
73
- end
74
- end
6
+ before do
7
+ # Use a mock logger that just keeps the last logged entry in an instance
8
+ # variable
9
+ SemanticLogger.default_level = :trace
10
+ SemanticLogger.backtrace_level = nil
11
+ @mock_logger = MockLogger.new
12
+ @appender = SemanticLogger.add_appender(logger: @mock_logger)
13
+
14
+ # Use this test's class name as the application name in the log output
15
+ @logger = SemanticLogger[LoggerTest]
16
+ @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
17
+ @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
18
+ @thread_name = Thread.current.name
19
+ @file_name_reg_exp = ' logger_test.rb:\d+'
20
+
21
+ assert_equal [], SemanticLogger.tags
22
+ assert_equal 65535, SemanticLogger.backtrace_level_index
75
23
  end
76
24
 
77
- describe '.add_appender DEPRECATED' do
78
- after do
79
- SemanticLogger.remove_appender(@appender) if @appender
80
- File.delete('sample.log') if File.exist?('sample.log')
81
- end
82
-
83
- it 'adds file appender' do
84
- @appender = SemanticLogger.add_appender('sample.log')
85
- assert @appender.is_a?(SemanticLogger::Appender::File)
86
- assert SemanticLogger.appenders.include?(@appender)
87
- end
88
-
89
- it 'adds stream appender' do
90
- @appender = SemanticLogger.add_appender(STDOUT)
91
- assert @appender.is_a?(SemanticLogger::Appender::File)
92
- assert SemanticLogger.appenders.include?(@appender)
93
- end
94
-
95
- it 'adds appender' do
96
- @appender = SemanticLogger.add_appender(SemanticLogger::Appender::File.new(io: STDOUT))
97
- assert @appender.is_a?(SemanticLogger::Appender::File), @appender.ai
98
- assert SemanticLogger.appenders.include?(@appender)
99
- end
100
-
101
- it 'adds logger wrapper appender' do
102
- @appender = SemanticLogger.add_appender(::Logger.new(STDOUT))
103
- assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
104
- assert @appender.logger.is_a?(::Logger)
105
- assert SemanticLogger.appenders.include?(@appender)
106
- end
107
-
108
- it 'fails to add invalid logger appender' do
109
- assert_raises do
110
- SemanticLogger.add_appender(logger: 'blah')
111
- end
112
- end
25
+ after do
26
+ SemanticLogger.remove_appender(@appender)
113
27
  end
114
28
 
115
- # Test each filter
116
- [nil, /\ALogger/, Proc.new { |l| (/\AExclude/ =~ l.message).nil? }].each do |filter|
117
- describe "filter: #{filter.class.name}" do
118
- before do
119
- # Use a mock logger that just keeps the last logged entry in an instance
120
- # variable
121
- SemanticLogger.default_level = :trace
122
- SemanticLogger.backtrace_level = nil
123
- @mock_logger = MockLogger.new
124
- @appender = SemanticLogger.add_appender(logger: @mock_logger)
125
- @appender.filter = filter
126
-
127
- # Add mock metric subscriber
128
- $last_metric = nil
129
- SemanticLogger.on_metric do |log|
130
- $last_metric = log.dup
131
- end
132
-
133
- # Use this test's class name as the application name in the log output
134
- @logger = SemanticLogger[LoggerTest]
135
- @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
136
- @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
137
- @thread_name = Thread.current.name
138
- @file_name_reg_exp = ' logger_test.rb:\d+'
139
-
140
- assert_equal [], @logger.tags
141
- assert_equal 65535, SemanticLogger.backtrace_level_index
142
- end
143
-
144
- after do
145
- SemanticLogger.remove_appender(@appender)
146
- end
147
-
148
- # Ensure that any log level can be logged
149
- SemanticLogger::LEVELS.each do |level|
150
- level_char = level.to_s.upcase[0]
151
-
152
- describe level do
153
- it 'logs' do
154
- @logger.send(level, 'hello world', @hash) { 'Calculations' }
155
- SemanticLogger.flush
156
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
157
- end
158
-
159
- it 'exclude log messages using Proc filter' do
160
- if filter.is_a?(Proc)
161
- @logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
162
- SemanticLogger.flush
163
- assert_nil @mock_logger.message
164
- end
165
- end
166
-
167
- it 'exclude log messages using RegExp filter' do
168
- if filter.is_a?(Regexp)
169
- logger = SemanticLogger::Logger.new('NotLogger', :trace, filter)
170
- logger.send(level, 'Ignore all log messages from this class', @hash) { 'Calculations' }
171
- SemanticLogger.flush
172
- assert_nil @mock_logger.message
173
- end
174
- end
175
-
176
- it 'logs with backtrace' do
177
- SemanticLogger.stub(:backtrace_level_index, 0) do
178
- @logger.send(level, 'hello world', @hash) { 'Calculations' }
179
- SemanticLogger.flush
180
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
181
- end
182
- end
183
-
184
- it 'logs with backtrace and exception' do
185
- SemanticLogger.stub(:backtrace_level_index, 0) do
186
- exc = RuntimeError.new('Test')
187
- @logger.send(level, 'hello world', exc)
188
- SemanticLogger.flush
189
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] LoggerTest -- hello world -- Exception: RuntimeError: Test/, @mock_logger.message)
190
- end
191
- end
192
-
193
- it 'logs payload' do
194
- hash = {tracking_number: '123456', even: 2, more: 'data'}
195
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
196
- @logger.send(level, 'Hello world', hash)
197
- SemanticLogger.flush
198
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
199
- end
200
-
201
- it 'does not log an empty payload' do
202
- hash = {}
203
- @logger.send(level, 'Hello world', hash)
204
- SemanticLogger.flush
205
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
206
- end
207
-
208
- describe 'hash only argument' do
209
- it 'logs message' do
210
- @logger.send(level, message: 'Hello world')
211
- SemanticLogger.flush
212
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
213
- end
214
-
215
- it 'logs payload and message' do
216
- @logger.send(level, message: 'Hello world', tracking_number: '123456', even: 2, more: 'data')
217
- hash = {tracking_number: '123456', even: 2, more: 'data'}
218
- SemanticLogger.flush
219
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
220
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
221
- end
222
-
223
- it 'logs payload and message from block' do
224
- @logger.send(level) { {message: 'Hello world', tracking_number: '123456', even: 2, more: 'data'} }
225
- hash = {tracking_number: '123456', even: 2, more: 'data'}
226
- SemanticLogger.flush
227
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
228
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
229
- end
230
-
231
- it 'logs payload only' do
232
- hash = {tracking_number: '123456', even: 2, more: 'data'}
233
- @logger.send(level, hash)
234
- SemanticLogger.flush
235
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
236
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- #{hash_str}/, @mock_logger.message)
237
- end
238
-
239
- it 'logs duration' do
240
- @logger.send(level, duration: 123.45, message: 'Hello world', tracking_number: '123456', even: 2, more: 'data')
241
- hash = {tracking_number: '123456', even: 2, more: 'data'}
242
- SemanticLogger.flush
243
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
244
- duration_match = defined?(JRuby) ? '\(123ms\)' : '\(123\.5ms\)'
245
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] #{duration_match} LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
246
- end
247
-
248
- it 'does not log when below min_duration' do
249
- @logger.send(level, min_duration: 200, duration: 123.45, message: 'Hello world', tracking_number: '123456', even: 2, more: 'data')
250
- SemanticLogger.flush
251
- assert_nil @mock_logger.message
252
- end
253
-
254
- it 'logs metric' do
255
- metric_name = '/my/custom/metric'
256
- @logger.send(level, metric: metric_name, duration: 123.45, message: 'Hello world', tracking_number: '123456', even: 2, more: 'data')
257
- hash = {tracking_number: '123456', even: 2, more: 'data'}
258
- SemanticLogger.flush
259
- hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
260
- duration_match = defined?(JRuby) ? '\(123ms\)' : '\(123\.5ms\)'
261
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] #{duration_match} LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
262
- assert metric_name, $last_metric.metric
263
- end
264
-
265
- end
29
+ # Ensure that any log level can be logged
30
+ SemanticLogger::LEVELS.each do |level|
31
+ level_char = level.to_s.upcase[0]
266
32
 
33
+ describe "##{level}" do
34
+ describe 'positional parameter' do
35
+ it 'logs message' do
36
+ @logger.send(level, 'hello world')
37
+ SemanticLogger.flush
38
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- hello world/, @mock_logger.message)
267
39
  end
268
- end
269
40
 
270
- describe '#tagged' do
271
- it 'add tags to log entries' do
272
- @logger.tagged('12345', 'DJHSFK') do
273
- @logger.info('Hello world')
274
- SemanticLogger.flush
275
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[12345\] \[DJHSFK\] LoggerTest -- Hello world/, @mock_logger.message)
276
- end
41
+ it 'adds message from block' do
42
+ @logger.send(level, 'hello world') { 'Calculations' }
43
+ SemanticLogger.flush
44
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations/, @mock_logger.message)
277
45
  end
278
46
 
279
- it 'add embedded tags to log entries' do
280
- @logger.tagged('First Level', 'tags') do
281
- @logger.tagged('Second Level') do
282
- @logger.info('Hello world')
283
- SemanticLogger.flush
284
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[First Level\] \[tags\] \[Second Level\] LoggerTest -- Hello world/, @mock_logger.message)
285
- end
286
- assert_equal 2, @logger.tags.count, @logger.tags
287
- assert_equal 'First Level', @logger.tags.first
288
- assert_equal 'tags', @logger.tags.last
289
- end
47
+ it 'logs message and payload' do
48
+ hash = {tracking_number: '123456', even: 2, more: 'data'}
49
+ hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
50
+ @logger.send(level, 'Hello world', hash)
51
+ SemanticLogger.flush
52
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
290
53
  end
291
- end
292
54
 
293
- describe '#with_payload' do
294
- it 'logs tagged payload' do
295
- hash = {tracking_number: '123456', even: 2, more: 'data'}
296
- hash_str = hash.inspect.sub("{", "\\{").sub("}", "\\}")
297
- @logger.with_payload(tracking_number: '123456') do
298
- @logger.with_payload(even: 2, more: 'data') do
299
- @logger.info('Hello world')
300
- SemanticLogger.flush
301
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
302
- end
303
- end
55
+ it 'does not log an empty payload' do
56
+ hash = {}
57
+ @logger.send(level, 'Hello world', hash)
58
+ SemanticLogger.flush
59
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
304
60
  end
305
- end
306
61
 
307
- describe '#fast_tag' do
308
- it 'add string tag to log entries' do
309
- @logger.fast_tag('12345') do
310
- @logger.info('Hello world')
62
+ it 'logs with backtrace' do
63
+ SemanticLogger.stub(:backtrace_level_index, 0) do
64
+ @logger.send(level, 'hello world', @hash) { 'Calculations' }
311
65
  SemanticLogger.flush
312
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[12345\] LoggerTest -- Hello world/, @mock_logger.message)
66
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
313
67
  end
314
68
  end
315
- end
316
69
 
317
- describe 'Ruby Logger level' do
318
- # Ensure that any log level can be logged
319
- Logger::Severity.constants.each do |level|
320
- it "log Ruby logger #{level} info" do
321
- @logger.level = Logger::Severity.const_get(level)
322
- if level.to_s == 'UNKNOWN'
323
- assert_equal Logger::Severity.const_get('ERROR')+1, @logger.send(:level_index)
324
- else
325
- assert_equal Logger::Severity.const_get(level)+1, @logger.send(:level_index)
326
- end
70
+ it 'logs with backtrace and exception' do
71
+ SemanticLogger.stub(:backtrace_level_index, 0) do
72
+ exc = RuntimeError.new('Test')
73
+ @logger.send(level, 'hello world', exc)
74
+ SemanticLogger.flush
75
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] LoggerTest -- hello world -- Exception: RuntimeError: Test/, @mock_logger.message)
327
76
  end
328
77
  end
329
78
  end
330
79
 
331
- describe 'measure' do
332
- # Ensure that any log level can be measured and logged
333
- SemanticLogger::LEVELS.each do |level|
334
- level_char = level.to_s.upcase[0]
335
-
336
- describe 'direct method' do
337
- it "log #{level} info" do
338
- assert_equal 'result', @logger.send("measure_#{level}".to_sym, 'hello world') { 'result' } # Measure duration of the supplied block
339
- SemanticLogger.flush
340
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
341
- end
342
-
343
- it "log #{level} info with payload" do
344
- assert_equal 'result', @logger.send("measure_#{level}".to_sym, 'hello world', payload: @hash) { 'result' } # Measure duration of the supplied block
345
- SemanticLogger.flush
346
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- #{@hash_str}/, @mock_logger.message)
347
- end
348
-
349
- it "not log #{level} info when block is faster than :min_duration" do
350
- assert_equal 'result', @logger.send("measure_#{level}".to_sym, 'hello world', min_duration: 500) { 'result' } # Measure duration of the supplied block
351
- SemanticLogger.flush
352
- assert_nil @mock_logger.message
353
- end
354
-
355
- it "log #{level} info when block duration exceeds :min_duration" do
356
- assert_equal 'result', @logger.send("measure_#{level}".to_sym, 'hello world', min_duration: 200, payload: @hash) { sleep 0.5; 'result' } # Measure duration of the supplied block
357
- SemanticLogger.flush
358
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- #{@hash_str}/, @mock_logger.message)
359
- end
360
-
361
- it "log #{level} info with an exception" do
362
- assert_raises RuntimeError do
363
- @logger.send("measure_#{level}", 'hello world', payload: @hash) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
364
- end
365
- SemanticLogger.flush
366
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
367
- end
368
-
369
- it "change log #{level} info with an exception" do
370
- assert_raises RuntimeError do
371
- @logger.send("measure_#{level}", 'hello world', payload: @hash, on_exception_level: :fatal) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
372
- end
373
- SemanticLogger.flush
374
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ F \[\d+:#{@thread_name}#{@file_name_reg_exp}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
375
- end
376
-
377
- it "log #{level} info with metric" do
378
- metric_name = '/my/custom/metric'
379
- assert_equal 'result', @logger.send("measure_#{level}".to_sym, 'hello world', metric: metric_name) { 'result' } # Measure duration of the supplied block
380
- SemanticLogger.flush
381
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
382
- assert metric_name, $last_metric.metric
383
- end
384
-
385
- it "log #{level} info with backtrace" do
386
- SemanticLogger.stub(:backtrace_level_index, 0) do
387
- assert_equal 'result', @logger.send("measure_#{level}".to_sym, 'hello world') { 'result' }
388
- SemanticLogger.flush
389
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
390
- end
391
- end
392
- end
393
-
394
- describe 'generic method' do
395
- it "log #{level} info" do
396
- assert_equal 'result', @logger.measure(level, 'hello world') { 'result' } # Measure duration of the supplied block
397
- SemanticLogger.flush
398
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
399
- end
400
-
401
- it "log #{level} info with payload" do
402
- assert_equal 'result', @logger.measure(level, 'hello world', payload: @hash) { 'result' } # Measure duration of the supplied block
403
- SemanticLogger.flush
404
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- #{@hash_str}/, @mock_logger.message)
405
- end
406
-
407
- it "not log #{level} info when block is faster than :min_duration" do
408
- assert_equal 'result', @logger.measure(level, 'hello world', min_duration: 500) { 'result' } # Measure duration of the supplied block
409
- SemanticLogger.flush
410
- assert_nil @mock_logger.message
411
- end
412
-
413
- it "log #{level} info when block duration exceeds :min_duration" do
414
- assert_equal 'result', @logger.measure(level, 'hello world', min_duration: 200, payload: @hash) { sleep 0.5; 'result' } # Measure duration of the supplied block
415
- SemanticLogger.flush
416
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- #{@hash_str}/, @mock_logger.message)
417
- end
418
-
419
- it "log #{level} info with an exception" do
420
- assert_raises RuntimeError do
421
- @logger.measure(level, 'hello world', payload: @hash) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
422
- end
423
- SemanticLogger.flush
424
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
425
- end
426
-
427
- it "log #{level} info with metric" do
428
- metric_name = '/my/custom/metric'
429
- assert_equal 'result', @logger.measure(level, 'hello world', metric: metric_name) { 'result' } # Measure duration of the supplied block
430
- SemanticLogger.flush
431
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
432
- assert metric_name, $last_metric.metric
433
- end
434
-
435
- it "log #{level} info with backtrace" do
436
- SemanticLogger.stub(:backtrace_level_index, 0) do
437
- assert_equal 'result', @logger.measure(level, 'hello world') { 'result' }
438
- SemanticLogger.flush
439
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}#{@file_name_reg_exp}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
440
- end
441
- end
442
- end
443
- end
444
-
445
- it 'log when the block performs a return' do
446
- assert_equal 'Good', function_with_return(@logger)
80
+ describe 'named parameters' do
81
+ it 'logs message' do
82
+ @logger.send(level, message: 'Hello world')
447
83
  SemanticLogger.flush
448
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- #{@hash_str}/, @mock_logger.message)
84
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world/, @mock_logger.message)
449
85
  end
450
86
 
451
- it 'not log at a level below the silence level' do
452
- SemanticLogger.default_level = :info
453
- @logger.measure_info('hello world', silence: :error) do
454
- @logger.warn "don't log me"
455
- end
87
+ it 'logs payload and message' do
88
+ @logger.send(level, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
89
+ hash = {tracking_number: '123456', even: 2, more: 'data'}
456
90
  SemanticLogger.flush
457
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
91
+ hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
92
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
458
93
  end
459
94
 
460
- it 'log at a silence level below the default level' do
461
- SemanticLogger.default_level = :info
462
- first_message = nil
463
- @logger.measure_info('hello world', silence: :trace) do
464
- @logger.debug('hello world', @hash) { 'Calculations' }
465
- SemanticLogger.flush
466
- first_message = @mock_logger.message
467
- end
468
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ D \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, first_message)
95
+ it 'logs payload and message from block' do
96
+ @logger.send(level) { {message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'}} }
97
+ hash = {tracking_number: '123456', even: 2, more: 'data'}
469
98
  SemanticLogger.flush
470
- # Only the last log message is kept in mock logger
471
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
99
+ hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
100
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
472
101
  end
473
- end
474
102
 
475
- describe '.default_level' do
476
- before do
477
- SemanticLogger.default_level = :debug
478
- end
479
-
480
- it 'not log at a level below the global default' do
481
- assert_equal :debug, SemanticLogger.default_level
482
- assert_equal :debug, @logger.level
483
- @logger.trace('hello world', @hash) { 'Calculations' }
103
+ it 'logs payload only' do
104
+ hash = {tracking_number: '123456', even: 2, more: 'data'}
105
+ @logger.send(level, payload: hash)
484
106
  SemanticLogger.flush
485
- assert_nil @mock_logger.message
107
+ hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
108
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] LoggerTest -- #{hash_str}/, @mock_logger.message)
486
109
  end
487
110
 
488
- it 'log at the instance level' do
489
- assert_equal :debug, SemanticLogger.default_level
490
- @logger.level = :trace
491
- assert_equal :trace, @logger.level
492
- @logger.trace('hello world', @hash) { 'Calculations' }
111
+ it 'logs duration' do
112
+ @logger.send(level, duration: 123.45, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
113
+ hash = {tracking_number: '123456', even: 2, more: 'data'}
493
114
  SemanticLogger.flush
494
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ T \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
115
+ hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
116
+ duration_match = defined?(JRuby) ? '\(123ms\)' : '\(123\.5ms\)'
117
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] #{duration_match} LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
495
118
  end
496
119
 
497
- it 'not log at a level below the instance level' do
498
- assert_equal :debug, SemanticLogger.default_level
499
- @logger.level = :warn
500
- assert_equal :warn, @logger.level
501
- @logger.debug('hello world', @hash) { 'Calculations' }
120
+ it 'does not log when below min_duration' do
121
+ @logger.send(level, min_duration: 200, duration: 123.45, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
502
122
  SemanticLogger.flush
503
123
  assert_nil @mock_logger.message
504
124
  end
505
- end
506
125
 
507
- describe '.silence' do
508
- before do
509
- SemanticLogger.default_level = :info
510
- end
511
-
512
- it 'not log at a level below the silence level' do
513
- assert_equal :info, SemanticLogger.default_level
514
- assert_equal :info, @logger.level
515
- @logger.silence do
516
- @logger.warn('hello world', @hash) { 'Calculations' }
517
- @logger.info('hello world', @hash) { 'Calculations' }
518
- @logger.debug('hello world', @hash) { 'Calculations' }
519
- @logger.trace('hello world', @hash) { 'Calculations' }
126
+ it 'logs metric' do
127
+ # Add mock metric subscriber
128
+ $last_metric = nil
129
+ SemanticLogger.on_metric do |log|
130
+ $last_metric = log.dup
520
131
  end
132
+
133
+ metric_name = '/my/custom/metric'
134
+ @logger.send(level, metric: metric_name, duration: 123.45, message: 'Hello world', payload: {tracking_number: '123456', even: 2, more: 'data'})
135
+ hash = {tracking_number: '123456', even: 2, more: 'data'}
521
136
  SemanticLogger.flush
522
- assert_nil @mock_logger.message
137
+ hash_str = hash.inspect.sub('{', '\{').sub('}', '\}')
138
+ duration_match = defined?(JRuby) ? '\(123ms\)' : '\(123\.5ms\)'
139
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] #{duration_match} LoggerTest -- Hello world -- #{hash_str}/, @mock_logger.message)
140
+ assert metric_name, $last_metric.metric
523
141
  end
524
142
 
525
- it 'log at the instance level even with the silencer at a higher level' do
526
- @logger.level = :trace
527
- assert_equal :trace, @logger.level
528
- @logger.silence do
529
- @logger.trace('hello world', @hash) { 'Calculations' }
530
- end
143
+ end
144
+
145
+ describe '#filter' do
146
+ it 'Proc' do
147
+ @appender.filter = Proc.new { |l| (/\AExclude/ =~ l.message).nil? }
148
+ @logger.send(level, 'Exclude this log message', @hash) { 'Calculations' }
531
149
  SemanticLogger.flush
532
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ T \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
150
+ assert_nil @mock_logger.message
533
151
  end
534
152
 
535
- it 'log at a silence level below the default level' do
536
- assert_equal :info, SemanticLogger.default_level
537
- assert_equal :info, @logger.level
538
- @logger.silence(:debug) do
539
- @logger.debug('hello world', @hash) { 'Calculations' }
540
- end
153
+ it 'RegExp' do
154
+ filter = /\ALogger/
155
+ @appender.filter = filter
156
+ logger = SemanticLogger::Logger.new('NotLogger', :trace, filter)
157
+ logger.send(level, 'Ignore all log messages from this class', @hash) { 'Calculations' }
541
158
  SemanticLogger.flush
542
- assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ D \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
159
+ assert_nil @mock_logger.message
543
160
  end
544
161
  end
162
+ end
163
+ end
545
164
 
546
- describe '.level?' do
547
- it 'return true for debug? with :trace level' do
548
- SemanticLogger.default_level = :trace
549
- assert_equal :trace, @logger.level
550
- assert_equal true, @logger.debug?
551
- assert_equal true, @logger.trace?
552
- end
553
-
554
- it 'return false for debug? with global :debug level' do
555
- SemanticLogger.default_level = :debug
556
- assert_equal :debug, @logger.level, @logger.inspect
557
- assert_equal true, @logger.debug?, @logger.inspect
558
- assert_equal false, @logger.trace?, @logger.inspect
165
+ describe 'Compatibility' do
166
+ # Ensure that any log level can be logged
167
+ Logger::Severity.constants.each do |level|
168
+ it "log Ruby logger #{level} info" do
169
+ @logger.level = Logger::Severity.const_get(level)
170
+ if level.to_s == 'UNKNOWN'
171
+ assert_equal Logger::Severity.const_get('ERROR')+1, @logger.send(:level_index)
172
+ else
173
+ assert_equal Logger::Severity.const_get(level)+1, @logger.send(:level_index)
559
174
  end
175
+ end
176
+ end
177
+ end
560
178
 
561
- it 'return true for debug? with global :info level' do
562
- SemanticLogger.default_level = :info
563
- assert_equal :info, @logger.level, @logger.inspect
564
- assert_equal false, @logger.debug?, @logger.inspect
565
- assert_equal false, @logger.trace?, @logger.inspect
566
- end
179
+ describe '#level?' do
180
+ it 'return true for debug? with :trace level' do
181
+ SemanticLogger.default_level = :trace
182
+ assert_equal :trace, @logger.level
183
+ assert_equal true, @logger.debug?
184
+ assert_equal true, @logger.trace?
185
+ end
567
186
 
568
- it 'return false for debug? with instance :debug level' do
569
- @logger.level = :debug
570
- assert_equal :debug, @logger.level, @logger.inspect
571
- assert_equal true, @logger.debug?, @logger.inspect
572
- assert_equal false, @logger.trace?, @logger.inspect
573
- end
187
+ it 'return false for debug? with global :debug level' do
188
+ SemanticLogger.default_level = :debug
189
+ assert_equal :debug, @logger.level, @logger.inspect
190
+ assert_equal true, @logger.debug?, @logger.inspect
191
+ assert_equal false, @logger.trace?, @logger.inspect
192
+ end
574
193
 
575
- it 'return true for debug? with instance :info level' do
576
- @logger.level = :info
577
- assert_equal :info, @logger.level, @logger.inspect
578
- assert_equal false, @logger.debug?, @logger.inspect
579
- assert_equal false, @logger.trace?, @logger.inspect
580
- end
581
- end
194
+ it 'return true for debug? with global :info level' do
195
+ SemanticLogger.default_level = :info
196
+ assert_equal :info, @logger.level, @logger.inspect
197
+ assert_equal false, @logger.debug?, @logger.inspect
198
+ assert_equal false, @logger.trace?, @logger.inspect
199
+ end
582
200
 
201
+ it 'return false for debug? with instance :debug level' do
202
+ @logger.level = :debug
203
+ assert_equal :debug, @logger.level, @logger.inspect
204
+ assert_equal true, @logger.debug?, @logger.inspect
205
+ assert_equal false, @logger.trace?, @logger.inspect
583
206
  end
584
- end
585
207
 
586
- # Make sure that measure still logs when a block uses return to return from
587
- # a function
588
- def function_with_return(logger)
589
- logger.measure_info('hello world', payload: @hash) do
590
- return 'Good'
208
+ it 'return true for debug? with instance :info level' do
209
+ @logger.level = :info
210
+ assert_equal :info, @logger.level, @logger.inspect
211
+ assert_equal false, @logger.debug?, @logger.inspect
212
+ assert_equal false, @logger.trace?, @logger.inspect
591
213
  end
592
- 'Bad'
593
214
  end
594
215
 
595
216
  end