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
@@ -0,0 +1,249 @@
1
+ require_relative 'test_helper'
2
+
3
+ class MeasureTest < Minitest::Test
4
+ describe 'Measure' do
5
+ before do
6
+ SemanticLogger.default_level = :trace
7
+ SemanticLogger.backtrace_level = nil
8
+ @mock_logger = MockLogger.new
9
+ @appender = SemanticLogger.add_appender(logger: @mock_logger)
10
+ @logger = SemanticLogger['LoggerTest']
11
+ @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
12
+ @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
13
+ @thread_name = Thread.current.name
14
+ @file_name_reg_exp = " #{File.basename(__FILE__)}:\d+"
15
+
16
+ # Add mock metric subscriber
17
+ $last_metric = nil
18
+ SemanticLogger.on_metric do |log|
19
+ $last_metric = log.dup
20
+ end
21
+ end
22
+
23
+ after do
24
+ SemanticLogger.remove_appender(@appender)
25
+ end
26
+
27
+ # Ensure that any log level can be measured and logged
28
+ SemanticLogger::LEVELS.each do |level|
29
+ level_char = level.to_s.upcase[0]
30
+ measure_level = "measure_#{level}".to_sym
31
+
32
+ describe "##{measure_level}" do
33
+ it ':message' do
34
+ assert_equal 'result', @logger.send(measure_level, 'hello world') { 'result' } # Measure duration of the supplied block
35
+ SemanticLogger.flush
36
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
37
+ end
38
+
39
+ it ':payload' do
40
+ assert_equal 'result', @logger.send(measure_level, 'hello world', payload: @hash) { 'result' } # Measure duration of the supplied block
41
+ SemanticLogger.flush
42
+ 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)
43
+ end
44
+
45
+ describe ':min_duration' do
46
+ it 'not log when faster' do
47
+ assert_equal 'result', @logger.send(measure_level, 'hello world', min_duration: 500) { 'result' } # Measure duration of the supplied block
48
+ SemanticLogger.flush
49
+ assert_nil @mock_logger.message
50
+ end
51
+
52
+ it 'log when slower' do
53
+ assert_equal 'result', @logger.send(measure_level, 'hello world', min_duration: 200, payload: @hash) { sleep 0.5; 'result' } # Measure duration of the supplied block
54
+ SemanticLogger.flush
55
+ 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)
56
+ end
57
+ end
58
+
59
+ it ':exception' do
60
+ assert_raises RuntimeError do
61
+ @logger.send(measure_level, 'hello world', payload: @hash) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
62
+ end
63
+ SemanticLogger.flush
64
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
65
+ end
66
+
67
+ it ':on_exception_level' do
68
+ assert_raises RuntimeError do
69
+ @logger.send(measure_level, 'hello world', payload: @hash, on_exception_level: :fatal) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
70
+ end
71
+ SemanticLogger.flush
72
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ F \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
73
+ end
74
+
75
+ it ':metric' do
76
+ metric_name = '/my/custom/metric'
77
+ assert_equal 'result', @logger.send(measure_level, 'hello world', metric: metric_name) { 'result' } # Measure duration of the supplied block
78
+ SemanticLogger.flush
79
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
80
+ assert metric_name, $last_metric.metric
81
+ end
82
+
83
+ it ':backtrace_level' do
84
+ SemanticLogger.stub(:backtrace_level_index, 0) do
85
+ assert_equal 'result', @logger.send(measure_level, 'hello world') { 'result' }
86
+ SemanticLogger.flush
87
+ 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)
88
+ end
89
+ end
90
+ end
91
+
92
+ describe "#measure(#{level})" do
93
+ it ':message' do
94
+ assert_equal 'result', @logger.measure(level, 'hello world') { 'result' } # Measure duration of the supplied block
95
+ SemanticLogger.flush
96
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
97
+ end
98
+
99
+ it ':payload' do
100
+ assert_equal 'result', @logger.measure(level, 'hello world', payload: @hash) { 'result' } # Measure duration of the supplied block
101
+ SemanticLogger.flush
102
+ 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)
103
+ end
104
+
105
+ describe ':min_duration' do
106
+ it 'not log when faster' do
107
+ assert_equal 'result', @logger.measure(level, 'hello world', min_duration: 500) { 'result' } # Measure duration of the supplied block
108
+ SemanticLogger.flush
109
+ assert_nil @mock_logger.message
110
+ end
111
+
112
+ it 'log when slower' do
113
+ assert_equal 'result', @logger.measure(level, 'hello world', min_duration: 200, payload: @hash) { sleep 0.5; 'result' } # Measure duration of the supplied block
114
+ SemanticLogger.flush
115
+ 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)
116
+ end
117
+ end
118
+
119
+ it ':exception' do
120
+ assert_raises RuntimeError do
121
+ @logger.measure(level, 'hello world', payload: @hash) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
122
+ end
123
+ SemanticLogger.flush
124
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
125
+ end
126
+
127
+ it ':metric' do
128
+ metric_name = '/my/custom/metric'
129
+ assert_equal 'result', @logger.measure(level, 'hello world', metric: metric_name) { 'result' } # Measure duration of the supplied block
130
+ SemanticLogger.flush
131
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
132
+ assert metric_name, $last_metric.metric
133
+ end
134
+
135
+ it "log #{level} info with backtrace" do
136
+ SemanticLogger.stub(:backtrace_level_index, 0) do
137
+ assert_equal 'result', @logger.measure(level, 'hello world') { 'result' }
138
+ SemanticLogger.flush
139
+ 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)
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "##{measure_level} named parameters" do
145
+ it ':message' do
146
+ assert_equal 'result', @logger.send(measure_level, message: 'hello world') { 'result' } # Measure duration of the supplied block
147
+ SemanticLogger.flush
148
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
149
+ end
150
+
151
+ it ':payload' do
152
+ assert_equal 'result', @logger.send(measure_level, message: 'hello world', payload: @hash) { 'result' } # Measure duration of the supplied block
153
+ SemanticLogger.flush
154
+ 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)
155
+ end
156
+
157
+ describe ':min_duration' do
158
+ it 'not log when faster' do
159
+ assert_equal 'result', @logger.send(measure_level, message: 'hello world', min_duration: 500) { 'result' } # Measure duration of the supplied block
160
+ SemanticLogger.flush
161
+ assert_nil @mock_logger.message
162
+ end
163
+
164
+ it 'log when slower' do
165
+ assert_equal 'result', @logger.send(measure_level, message: 'hello world', min_duration: 200, payload: @hash) { sleep 0.5; 'result' } # Measure duration of the supplied block
166
+ SemanticLogger.flush
167
+ 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)
168
+ end
169
+ end
170
+
171
+ it ':exception' do
172
+ assert_raises RuntimeError do
173
+ @logger.send(measure_level, message: 'hello world', payload: @hash) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
174
+ end
175
+ SemanticLogger.flush
176
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
177
+ end
178
+
179
+ it ':on_exception_level' do
180
+ assert_raises RuntimeError do
181
+ @logger.send(measure_level, message: 'hello world', payload: @hash, on_exception_level: :fatal) { raise RuntimeError.new('Test') } # Measure duration of the supplied block
182
+ end
183
+ SemanticLogger.flush
184
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ F \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world -- Exception: RuntimeError: Test -- #{@hash_str}/, @mock_logger.message)
185
+ end
186
+
187
+ it ':metric' do
188
+ metric_name = '/my/custom/metric'
189
+ assert_equal 'result', @logger.send(measure_level, message: 'hello world', metric: metric_name) { 'result' } # Measure duration of the supplied block
190
+ SemanticLogger.flush
191
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ #{level_char} \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
192
+ assert metric_name, $last_metric.metric
193
+ end
194
+
195
+ it ':backtrace_level' do
196
+ SemanticLogger.stub(:backtrace_level_index, 0) do
197
+ assert_equal 'result', @logger.send(measure_level, message: 'hello world') { 'result' }
198
+ SemanticLogger.flush
199
+ 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)
200
+ end
201
+ end
202
+ end
203
+
204
+ end
205
+
206
+ describe 'return' do
207
+ it 'log when the block performs a return' do
208
+ assert_equal 'Good', function_with_return(@logger)
209
+ SemanticLogger.flush
210
+ 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)
211
+ end
212
+ end
213
+
214
+ describe ':silence' do
215
+ it 'silences messages' do
216
+ SemanticLogger.default_level = :info
217
+ @logger.measure_info('hello world', silence: :error) do
218
+ @logger.warn "don't log me"
219
+ end
220
+ SemanticLogger.flush
221
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
222
+ end
223
+
224
+ it 'does not silence higer level messages' do
225
+ SemanticLogger.default_level = :info
226
+ first_message = nil
227
+ @logger.measure_info('hello world', silence: :trace) do
228
+ @logger.debug('hello world', @hash) { 'Calculations' }
229
+ SemanticLogger.flush
230
+ first_message = @mock_logger.message
231
+ end
232
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ D \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, first_message)
233
+ SemanticLogger.flush
234
+ # Only the last log message is kept in mock logger
235
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \((\d+\.\d+)|(\d+)ms\) LoggerTest -- hello world/, @mock_logger.message)
236
+ end
237
+ end
238
+
239
+ # Make sure that measure still logs when a block uses return to return from
240
+ # a function
241
+ def function_with_return(logger)
242
+ logger.measure_info('hello world', payload: @hash) do
243
+ return 'Good'
244
+ end
245
+ 'Bad'
246
+ end
247
+
248
+ end
249
+ end
@@ -0,0 +1,257 @@
1
+ require_relative 'test_helper'
2
+
3
+ class SemanticLoggerTest < Minitest::Test
4
+ describe SemanticLogger do
5
+ describe '.add_appender' do
6
+ before do
7
+ @appender = nil
8
+ end
9
+
10
+ after do
11
+ SemanticLogger.remove_appender(@appender)
12
+ File.delete('sample.log') if File.exist?('sample.log')
13
+ end
14
+
15
+ it 'adds file appender' do
16
+ @appender = SemanticLogger.add_appender(file_name: 'sample.log')
17
+ assert @appender.is_a?(SemanticLogger::Appender::File)
18
+ assert SemanticLogger.appenders.include?(@appender)
19
+ assert @appender.formatter.is_a?(SemanticLogger::Formatters::Default)
20
+ end
21
+
22
+ it 'adds file appender with json format' do
23
+ @appender = SemanticLogger.add_appender(file_name: 'sample.log', formatter: :json)
24
+ assert @appender.is_a?(SemanticLogger::Appender::File)
25
+ assert SemanticLogger.appenders.include?(@appender)
26
+ assert @appender.formatter.is_a?(SemanticLogger::Formatters::Json)
27
+ end
28
+
29
+ it 'adds stream appender' do
30
+ @appender = SemanticLogger.add_appender(io: STDOUT)
31
+ assert @appender.is_a?(SemanticLogger::Appender::File)
32
+ assert SemanticLogger.appenders.include?(@appender)
33
+ end
34
+
35
+ it 'adds symbol appender' do
36
+ @appender = SemanticLogger.add_appender(appender: :wrapper, logger: Logger.new(STDOUT))
37
+ assert @appender.is_a?(SemanticLogger::Appender::Wrapper), -> { @appender.ai }
38
+ assert SemanticLogger.appenders.include?(@appender)
39
+ end
40
+
41
+ it 'adds symbol appender with underscores' do
42
+ @appender = SemanticLogger.add_appender(appender: :new_relic)
43
+ assert @appender.is_a?(SemanticLogger::Appender::NewRelic), -> { @appender.ai }
44
+ assert SemanticLogger.appenders.include?(@appender)
45
+ end
46
+
47
+ it 'adds logger wrapper appender' do
48
+ @appender = SemanticLogger.add_appender(logger: ::Logger.new(STDOUT))
49
+ assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
50
+ assert @appender.logger.is_a?(::Logger)
51
+ assert SemanticLogger.appenders.include?(@appender)
52
+ assert @appender.formatter.is_a?(SemanticLogger::Formatters::Default)
53
+ end
54
+
55
+ it 'adds logger wrapper appender with color formatter' do
56
+ @appender = SemanticLogger.add_appender(logger: ::Logger.new(STDOUT), formatter: :color)
57
+ assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
58
+ assert @appender.logger.is_a?(::Logger)
59
+ assert SemanticLogger.appenders.include?(@appender)
60
+ assert @appender.formatter.is_a?(SemanticLogger::Formatters::Color)
61
+ end
62
+
63
+ it 'adds appender' do
64
+ @appender = SemanticLogger.add_appender(appender: SemanticLogger::Appender::File.new(io: STDOUT))
65
+ assert @appender.is_a?(SemanticLogger::Appender::File), @appender.ai
66
+ assert SemanticLogger.appenders.include?(@appender)
67
+ end
68
+
69
+ it 'fails to add invalid logger appender' do
70
+ assert_raises do
71
+ SemanticLogger.add_appender(logger: 'blah')
72
+ end
73
+ end
74
+ end
75
+
76
+ describe '.add_appender DEPRECATED' do
77
+ before do
78
+ @appender = nil
79
+ end
80
+
81
+ after do
82
+ SemanticLogger.remove_appender(@appender) if @appender
83
+ File.delete('sample.log') if File.exist?('sample.log')
84
+ end
85
+
86
+ it 'adds file appender' do
87
+ @appender = SemanticLogger.add_appender('sample.log')
88
+ assert @appender.is_a?(SemanticLogger::Appender::File)
89
+ assert SemanticLogger.appenders.include?(@appender)
90
+ end
91
+
92
+ it 'adds stream appender' do
93
+ @appender = SemanticLogger.add_appender(STDOUT)
94
+ assert @appender.is_a?(SemanticLogger::Appender::File)
95
+ assert SemanticLogger.appenders.include?(@appender)
96
+ end
97
+
98
+ it 'adds appender' do
99
+ @appender = SemanticLogger.add_appender(SemanticLogger::Appender::File.new(io: STDOUT))
100
+ assert @appender.is_a?(SemanticLogger::Appender::File), @appender.ai
101
+ assert SemanticLogger.appenders.include?(@appender)
102
+ end
103
+
104
+ it 'adds logger wrapper appender' do
105
+ @appender = SemanticLogger.add_appender(::Logger.new(STDOUT))
106
+ assert @appender.is_a?(SemanticLogger::Appender::Wrapper)
107
+ assert @appender.logger.is_a?(::Logger)
108
+ assert SemanticLogger.appenders.include?(@appender)
109
+ end
110
+
111
+ it 'fails to add invalid logger appender' do
112
+ assert_raises do
113
+ SemanticLogger.add_appender(logger: 'blah')
114
+ end
115
+ end
116
+ end
117
+
118
+ describe 'mock_logger' do
119
+ before do
120
+ # Use a mock logger that just keeps the last logged entry in an instance
121
+ # variable
122
+ SemanticLogger.default_level = :trace
123
+ SemanticLogger.backtrace_level = nil
124
+ @mock_logger = MockLogger.new
125
+ @appender = SemanticLogger.add_appender(logger: @mock_logger)
126
+
127
+ # Use this test's class name as the application name in the log output
128
+ @logger = SemanticLogger['LoggerTest']
129
+ @hash = {session_id: 'HSSKLEU@JDK767', tracking_number: 12345}
130
+ @hash_str = @hash.inspect.sub("{", "\\{").sub("}", "\\}")
131
+ @thread_name = Thread.current.name
132
+ end
133
+
134
+ after do
135
+ SemanticLogger.remove_appender(@appender)
136
+ end
137
+
138
+ describe '.tagged' do
139
+ it 'add tags to log entries' do
140
+ SemanticLogger.tagged('12345', 'DJHSFK') do
141
+ @logger.info('Hello world')
142
+ SemanticLogger.flush
143
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[12345\] \[DJHSFK\] LoggerTest -- Hello world/, @mock_logger.message)
144
+ end
145
+ end
146
+
147
+ it 'add embedded tags to log entries' do
148
+ SemanticLogger.tagged('First Level', 'tags') do
149
+ SemanticLogger.tagged('Second Level') do
150
+ @logger.info('Hello world')
151
+ SemanticLogger.flush
152
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[First Level\] \[tags\] \[Second Level\] LoggerTest -- Hello world/, @mock_logger.message)
153
+ end
154
+ assert_equal 2, SemanticLogger.tags.count, SemanticLogger.tags
155
+ assert_equal 'First Level', SemanticLogger.tags.first
156
+ assert_equal 'tags', SemanticLogger.tags.last
157
+ end
158
+ end
159
+ end
160
+
161
+ describe '.named_tagged' do
162
+ it 'logs named tags' do
163
+ SemanticLogger.named_tagged(tracking_number: '123456') do
164
+ SemanticLogger.named_tagged(even: 2, more: 'data') do
165
+ @logger.info('Hello world')
166
+ SemanticLogger.flush
167
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[even: 2\] \[more: data\] \[tracking_number: 123456\] LoggerTest -- Hello world/, @mock_logger.message)
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ describe '.fast_tag' do
174
+ it 'add string tag to log entries' do
175
+ @logger.fast_tag('12345') do
176
+ @logger.info('Hello world')
177
+ SemanticLogger.flush
178
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ I \[\d+:#{@thread_name}\] \[12345\] LoggerTest -- Hello world/, @mock_logger.message)
179
+ end
180
+ end
181
+ end
182
+
183
+ describe '.default_level' do
184
+ before do
185
+ SemanticLogger.default_level = :debug
186
+ end
187
+
188
+ it 'not log at a level below the global default' do
189
+ assert_equal :debug, SemanticLogger.default_level
190
+ assert_equal :debug, @logger.level
191
+ @logger.trace('hello world', @hash) { 'Calculations' }
192
+ SemanticLogger.flush
193
+ assert_nil @mock_logger.message
194
+ end
195
+
196
+ it 'log at the instance level' do
197
+ assert_equal :debug, SemanticLogger.default_level
198
+ @logger.level = :trace
199
+ assert_equal :trace, @logger.level
200
+ @logger.trace('hello world', @hash) { 'Calculations' }
201
+ SemanticLogger.flush
202
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ T \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
203
+ end
204
+
205
+ it 'not log at a level below the instance level' do
206
+ assert_equal :debug, SemanticLogger.default_level
207
+ @logger.level = :warn
208
+ assert_equal :warn, @logger.level
209
+ @logger.debug('hello world', @hash) { 'Calculations' }
210
+ SemanticLogger.flush
211
+ assert_nil @mock_logger.message
212
+ end
213
+ end
214
+
215
+ describe '.silence' do
216
+ before do
217
+ SemanticLogger.default_level = :info
218
+ end
219
+
220
+ it 'not log at a level below the silence level' do
221
+ assert_equal :info, SemanticLogger.default_level
222
+ assert_equal :info, @logger.level
223
+ @logger.silence do
224
+ @logger.warn('hello world', @hash) { 'Calculations' }
225
+ @logger.info('hello world', @hash) { 'Calculations' }
226
+ @logger.debug('hello world', @hash) { 'Calculations' }
227
+ @logger.trace('hello world', @hash) { 'Calculations' }
228
+ end
229
+ SemanticLogger.flush
230
+ assert_nil @mock_logger.message
231
+ end
232
+
233
+ it 'log at the instance level even with the silencer at a higher level' do
234
+ @logger.level = :trace
235
+ assert_equal :trace, @logger.level
236
+ @logger.silence do
237
+ @logger.trace('hello world', @hash) { 'Calculations' }
238
+ end
239
+ SemanticLogger.flush
240
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ T \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
241
+ end
242
+
243
+ it 'log at a silence level below the default level' do
244
+ assert_equal :info, SemanticLogger.default_level
245
+ assert_equal :info, @logger.level
246
+ @logger.silence(:debug) do
247
+ @logger.debug('hello world', @hash) { 'Calculations' }
248
+ end
249
+ SemanticLogger.flush
250
+ assert_match(/\d+-\d+-\d+ \d+:\d+:\d+.\d+ D \[\d+:#{@thread_name}\] LoggerTest -- hello world -- Calculations -- #{@hash_str}/, @mock_logger.message)
251
+ end
252
+ end
253
+
254
+ end
255
+
256
+ end
257
+ end