semantic_logger 3.4.1 → 4.0.0.beta1

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.
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