semantic_logger 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +55 -8
  3. data/lib/semantic_logger.rb +1 -2
  4. data/lib/semantic_logger/ansi_colors.rb +1 -2
  5. data/lib/semantic_logger/appender.rb +17 -15
  6. data/lib/semantic_logger/appender/bugsnag.rb +5 -4
  7. data/lib/semantic_logger/appender/elasticsearch.rb +102 -16
  8. data/lib/semantic_logger/appender/elasticsearch_http.rb +76 -0
  9. data/lib/semantic_logger/appender/file.rb +9 -25
  10. data/lib/semantic_logger/appender/graylog.rb +43 -38
  11. data/lib/semantic_logger/appender/honeybadger.rb +3 -5
  12. data/lib/semantic_logger/appender/http.rb +12 -15
  13. data/lib/semantic_logger/appender/kafka.rb +183 -0
  14. data/lib/semantic_logger/appender/mongodb.rb +3 -3
  15. data/lib/semantic_logger/appender/new_relic.rb +3 -7
  16. data/lib/semantic_logger/appender/sentry.rb +2 -5
  17. data/lib/semantic_logger/appender/splunk.rb +7 -10
  18. data/lib/semantic_logger/appender/splunk_http.rb +16 -16
  19. data/lib/semantic_logger/appender/syslog.rb +43 -122
  20. data/lib/semantic_logger/appender/tcp.rb +28 -9
  21. data/lib/semantic_logger/appender/udp.rb +4 -7
  22. data/lib/semantic_logger/appender/wrapper.rb +3 -7
  23. data/lib/semantic_logger/base.rb +47 -7
  24. data/lib/semantic_logger/formatters/base.rb +29 -10
  25. data/lib/semantic_logger/formatters/color.rb +75 -45
  26. data/lib/semantic_logger/formatters/default.rb +53 -28
  27. data/lib/semantic_logger/formatters/json.rb +7 -8
  28. data/lib/semantic_logger/formatters/raw.rb +97 -1
  29. data/lib/semantic_logger/formatters/syslog.rb +46 -80
  30. data/lib/semantic_logger/formatters/syslog_cee.rb +57 -0
  31. data/lib/semantic_logger/log.rb +17 -67
  32. data/lib/semantic_logger/logger.rb +17 -27
  33. data/lib/semantic_logger/processor.rb +70 -46
  34. data/lib/semantic_logger/semantic_logger.rb +130 -69
  35. data/lib/semantic_logger/subscriber.rb +18 -32
  36. data/lib/semantic_logger/version.rb +1 -1
  37. data/test/appender/elasticsearch_http_test.rb +75 -0
  38. data/test/appender/elasticsearch_test.rb +34 -27
  39. data/test/appender/file_test.rb +2 -2
  40. data/test/appender/honeybadger_test.rb +1 -1
  41. data/test/appender/kafka_test.rb +36 -0
  42. data/test/appender/new_relic_test.rb +1 -1
  43. data/test/appender/sentry_test.rb +1 -1
  44. data/test/appender/syslog_test.rb +2 -2
  45. data/test/appender/wrapper_test.rb +1 -1
  46. data/test/formatters/color_test.rb +154 -0
  47. data/test/formatters/default_test.rb +176 -0
  48. data/test/loggable_test.rb +1 -1
  49. data/test/logger_test.rb +47 -4
  50. data/test/measure_test.rb +2 -2
  51. data/test/semantic_logger_test.rb +34 -6
  52. data/test/test_helper.rb +8 -0
  53. metadata +14 -3
@@ -4,24 +4,43 @@ module SemanticLogger
4
4
  # Start the appender thread
5
5
  def self.start
6
6
  return false if active?
7
- @@thread = Thread.new { process_requests }
8
- raise 'Failed to start Appender Thread' unless @@thread
7
+ @thread = Thread.new { process_requests }
8
+ raise 'Failed to start Appender Thread' unless @thread
9
9
  true
10
10
  end
11
11
 
12
12
  # Returns true if the appender_thread is active
13
13
  def self.active?
14
- @@thread && @@thread.alive?
14
+ @thread && @thread.alive?
15
15
  end
16
16
 
17
- # Returns [Integer] the number of log entries waiting to be written to the appenders
17
+ # Returns [Integer] the number of log entries waiting to be written to the appenders.
18
+ #
19
+ # When this number grows it is because the logging appender thread is not
20
+ # able to write to the appenders fast enough. Either reduce the amount of
21
+ # logging, increase the log level, reduce the number of appenders, or
22
+ # look into speeding up the appenders themselves
18
23
  def self.queue_size
19
24
  queue.size
20
25
  end
21
26
 
22
- # Add log request to the queue for processing
27
+ # Flush all queued log entries disk, database, etc.
28
+ # All queued log messages are written and then each appender is flushed in turn.
29
+ def self.flush
30
+ submit_request(:flush)
31
+ end
32
+
33
+ # Close all appenders and flush any outstanding messages.
34
+ def self.close
35
+ submit_request(:close)
36
+ end
37
+
38
+ # Add log request to the queue for processing.
23
39
  def self.<<(log)
24
- queue << log if active?
40
+ return unless active?
41
+
42
+ call_log_subscribers(log)
43
+ queue << log
25
44
  end
26
45
 
27
46
  # Submit command and wait for reply
@@ -47,78 +66,68 @@ module SemanticLogger
47
66
  # SemanticLogger::Logger itself since it is for reporting problems
48
67
  # while trying to log to the various appenders
49
68
  def self.logger=(logger)
50
- @@logger = logger
69
+ @logger = logger
51
70
  end
52
71
 
53
72
  # Returns the check_interval which is the number of messages between checks
54
73
  # to determine if the appender thread is falling behind
55
74
  def self.lag_check_interval
56
- @@lag_check_interval
75
+ @lag_check_interval
57
76
  end
58
77
 
59
78
  # Set the check_interval which is the number of messages between checks
60
79
  # to determine if the appender thread is falling behind
61
80
  def self.lag_check_interval=(lag_check_interval)
62
- @@lag_check_interval = lag_check_interval
81
+ @lag_check_interval = lag_check_interval
63
82
  end
64
83
 
65
84
  # Returns the amount of time in seconds
66
85
  # to determine if the appender thread is falling behind
67
86
  def self.lag_threshold_s
68
- @@lag_threshold_s
87
+ @lag_threshold_s
69
88
  end
70
89
 
71
- # Supply a metrics appender to be called whenever a logging metric is encountered
72
- #
73
- # Parameters
74
- # appender: [Symbol | Object | Proc]
75
- # [Proc] the block to call.
76
- # [Object] the block on which to call #call.
77
- # [Symbol] :new_relic, or :statsd to forward metrics to
78
- #
79
- # block
80
- # The block to be called
81
- #
82
- # Example:
83
- # SemanticLogger.on_metric do |log|
84
- # puts "#{log.metric} was received. Log: #{log.inspect}"
85
- # end
86
- #
87
- # Note:
88
- # * This callback is called in the logging thread.
89
- # * Does not slow down the application.
90
- # * Only context is what is passed in the log struct, the original thread context is not available.
91
90
  def self.on_metric(options = {}, &block)
92
91
  # Backward compatibility
93
- options = options.is_a?(Hash) ? options.dup : {appender: options}
94
- appender = block || options.delete(:appender)
92
+ options = options.is_a?(Hash) ? options.dup : {appender: options}
93
+ subscriber = block || options.delete(:appender)
95
94
 
96
95
  # Convert symbolized metrics appender to an actual object
97
- appender = SemanticLogger::Appender.constantize_symbol(appender, 'SemanticLogger::Metrics').new(options) if appender.is_a?(Symbol)
96
+ subscriber = SemanticLogger::Appender.constantize_symbol(subscriber, 'SemanticLogger::Metrics').new(options) if subscriber.is_a?(Symbol)
97
+
98
+ raise('When supplying a metrics subscriber, it must support the #call method') unless subscriber.is_a?(Proc) || subscriber.respond_to?(:call)
99
+ subscribers = (@metric_subscribers ||= Concurrent::Array.new)
100
+ subscribers << subscriber unless subscribers.include?(subscriber)
101
+ end
102
+
103
+ def self.on_log(object = nil, &block)
104
+ subscriber = block || object
98
105
 
99
- raise('When supplying a metrics appender, it must support the #call method') unless appender.is_a?(Proc) || appender.respond_to?(:call)
100
- (@@metric_subscribers ||= Concurrent::Array.new) << appender
106
+ raise('When supplying an on_log subscriber, it must support the #call method') unless subscriber.is_a?(Proc) || subscriber.respond_to?(:call)
107
+ subscribers = (@log_subscribers ||= Concurrent::Array.new)
108
+ subscribers << subscriber unless subscribers.include?(subscriber)
101
109
  end
102
110
 
103
111
  private
104
112
 
105
- @@thread = nil
106
- @@queue = Queue.new
107
- @@lag_check_interval = 5000
108
- @@lag_threshold_s = 30
109
- @@metric_subscribers = nil
113
+ @thread = nil
114
+ @queue = Queue.new
115
+ @lag_check_interval = 5000
116
+ @lag_threshold_s = 30
117
+ @metric_subscribers = nil
118
+ @log_subscribers = nil
110
119
 
111
120
  # Queue to hold messages that need to be logged to the various appenders
112
121
  def self.queue
113
- @@queue
122
+ @queue
114
123
  end
115
124
 
116
125
  # Internal logger for SemanticLogger
117
126
  # For example when an appender is not working etc..
118
127
  # By default logs to STDERR
119
128
  def self.logger
120
- @@logger ||= begin
121
- l = SemanticLogger::Appender::File.new(STDERR, :warn)
129
+ @logger ||= begin
130
+ l = SemanticLogger::Appender::File.new(io: STDERR, level: :warn)
122
131
  l.name = name
123
132
  l
124
133
  end
@@ -156,6 +165,7 @@ module SemanticLogger
156
165
  when :close
157
166
  close_appenders
158
167
  message[:reply_queue] << true if message[:reply_queue]
168
+ break
159
169
  else
160
170
  logger.warn "Appender thread: Ignoring unknown command: #{message[:command]}"
161
171
  end
@@ -170,7 +180,7 @@ module SemanticLogger
170
180
  end
171
181
  retry
172
182
  ensure
173
- @@thread = nil
183
+ @thread = nil
174
184
  # This block may be called after the file handles have been released by Ruby
175
185
  begin
176
186
  logger.trace 'Appender thread has stopped'
@@ -183,9 +193,9 @@ module SemanticLogger
183
193
  # Call Metric subscribers
184
194
  def self.call_metric_subscribers(log)
185
195
  # If no subscribers registered, then return immediately
186
- return unless @@metric_subscribers
196
+ return unless @metric_subscribers
187
197
 
188
- @@metric_subscribers.each do |subscriber|
198
+ @metric_subscribers.each do |subscriber|
189
199
  begin
190
200
  subscriber.call(log)
191
201
  rescue Exception => exc
@@ -194,6 +204,20 @@ module SemanticLogger
194
204
  end
195
205
  end
196
206
 
207
+ # Call on_log subscribers
208
+ def self.call_log_subscribers(log)
209
+ # If no subscribers registered, then return immediately
210
+ return unless @log_subscribers
211
+
212
+ @log_subscribers.each do |subscriber|
213
+ begin
214
+ subscriber.call(log)
215
+ rescue Exception => exc
216
+ logger.error 'Exception calling :on_log subscriber', exc
217
+ end
218
+ end
219
+ end
220
+
197
221
  # Call Appenders
198
222
  def self.call_appenders(log)
199
223
  SemanticLogger.appenders.each do |appender|
@@ -12,14 +12,14 @@ module SemanticLogger
12
12
 
13
13
  # Sets the global default log level
14
14
  def self.default_level=(level)
15
- @@default_level = level
15
+ @default_level = level
16
16
  # For performance reasons pre-calculate the level index
17
- @@default_level_index = level_to_index(level)
17
+ @default_level_index = level_to_index(level)
18
18
  end
19
19
 
20
20
  # Returns the global default log level
21
21
  def self.default_level
22
- @@default_level
22
+ @default_level
23
23
  end
24
24
 
25
25
  # Sets the level at which backtraces should be captured
@@ -33,45 +33,45 @@ module SemanticLogger
33
33
  # Capturing backtraces is very expensive and should not be done all
34
34
  # the time. It is recommended to run it at :error level in production.
35
35
  def self.backtrace_level=(level)
36
- @@backtrace_level = level
36
+ @backtrace_level = level
37
37
  # For performance reasons pre-calculate the level index
38
- @@backtrace_level_index = level.nil? ? 65535 : level_to_index(level)
38
+ @backtrace_level_index = level.nil? ? 65535 : level_to_index(level)
39
39
  end
40
40
 
41
41
  # Returns the current backtrace level
42
42
  def self.backtrace_level
43
- @@backtrace_level
43
+ @backtrace_level
44
44
  end
45
45
 
46
46
  # Returns the current backtrace level index
47
47
  # For internal use only
48
48
  def self.backtrace_level_index #:nodoc
49
- @@backtrace_level_index
49
+ @backtrace_level_index
50
50
  end
51
51
 
52
52
  # Returns [String] name of this host for logging purposes
53
53
  # Note: Not all appenders use `host`
54
54
  def self.host
55
- @@host ||= Socket.gethostname.force_encoding("UTF-8")
55
+ @host ||= Socket.gethostname.force_encoding("UTF-8")
56
56
  end
57
57
 
58
58
  # Override the default host name
59
59
  def self.host=(host)
60
- @@host = host
60
+ @host = host
61
61
  end
62
62
 
63
63
  # Returns [String] name of this application for logging purposes
64
64
  # Note: Not all appenders use `application`
65
65
  def self.application
66
- @@application
66
+ @application
67
67
  end
68
68
 
69
69
  # Override the default application
70
70
  def self.application=(application)
71
- @@application = application
71
+ @application = application
72
72
  end
73
73
 
74
- @@application = 'Semantic Logger'
74
+ @application = 'Semantic Logger'
75
75
 
76
76
  # Add a new logging appender as a new destination for all log messages
77
77
  # emitted from Semantic Logger
@@ -154,7 +154,7 @@ module SemanticLogger
154
154
  def self.add_appender(options, deprecated_level = nil, &block)
155
155
  options = options.is_a?(Hash) ? options.dup : convert_old_appender_args(options, deprecated_level)
156
156
  appender = SemanticLogger::Appender.create(options, &block)
157
- @@appenders << appender
157
+ @appenders << appender
158
158
 
159
159
  # Start appender thread if it is not already running
160
160
  SemanticLogger::Processor.start
@@ -164,7 +164,7 @@ module SemanticLogger
164
164
  # Remove an existing appender
165
165
  # Currently only supports appender instances
166
166
  def self.remove_appender(appender)
167
- @@appenders.delete(appender)
167
+ @appenders.delete(appender)
168
168
  end
169
169
 
170
170
  # Returns [SemanticLogger::Subscriber] a copy of the list of active
@@ -172,31 +172,33 @@ module SemanticLogger
172
172
  # Use SemanticLogger.add_appender and SemanticLogger.remove_appender
173
173
  # to manipulate the active appenders list
174
174
  def self.appenders
175
- @@appenders.clone
175
+ @appenders.clone
176
176
  end
177
177
 
178
- # Wait until all queued log messages have been written and flush all active
179
- # appenders
178
+ # Flush all queued log entries disk, database, etc.
179
+ # All queued log messages are written and then each appender is flushed in turn.
180
180
  def self.flush
181
- SemanticLogger::Logger.flush
181
+ SemanticLogger::Processor.flush
182
182
  end
183
183
 
184
- # Close and flush all appenders
184
+ # Close all appenders and flush any outstanding messages.
185
185
  def self.close
186
- SemanticLogger::Logger.close
186
+ SemanticLogger::Processor.close
187
187
  end
188
188
 
189
189
  # After forking an active process call SemanticLogger.reopen to re-open
190
- # any open file handles etc to resources
190
+ # any open file handles etc to resources.
191
191
  #
192
- # Note: Only appenders that implement the reopen method will be called
192
+ # Note:
193
+ # Not all appenders implement reopen.
194
+ # Check the code for each appender you are using before relying on this behavior.
193
195
  def self.reopen
194
- @@appenders.each { |appender| appender.reopen if appender.respond_to?(:reopen) }
195
- # After a fork the appender thread is not running, start it if it is not running
196
+ @appenders.each {|appender| appender.reopen if appender.respond_to?(:reopen)}
197
+ # After a fork the appender thread is not running, start it if it is not running.
196
198
  SemanticLogger::Processor.start
197
199
  end
198
200
 
199
- # Supply a block to be called whenever a metric is seen during measure logging
201
+ # Supply a metrics appender to be called whenever a logging metric is encountered
200
202
  #
201
203
  # Parameters
202
204
  # appender: [Symbol | Object | Proc]
@@ -213,13 +215,41 @@ module SemanticLogger
213
215
  # end
214
216
  #
215
217
  # Note:
216
- # * This callback is called in the logging thread.
218
+ # * This callback is called in the separate logging thread.
217
219
  # * Does not slow down the application.
218
220
  # * Only context is what is passed in the log struct, the original thread context is not available.
219
221
  def self.on_metric(options = {}, &block)
220
222
  SemanticLogger::Processor.on_metric(options, &block)
221
223
  end
222
224
 
225
+ # Supply a callback to be called whenever a log entry is created.
226
+ # Useful for capturing appender specific context information.
227
+ #
228
+ # Parameters
229
+ # object: [Object | Proc]
230
+ # [Proc] the block to call.
231
+ # [Object] any object on which to call #call.
232
+ #
233
+ # Example:
234
+ # SemanticLogger.on_log do |log|
235
+ # log.set_context(:honeybadger, Honeybadger.get_context)
236
+ # end
237
+ #
238
+ # Example:
239
+ # module CaptureContext
240
+ # def call(log)
241
+ # log.set_context(:honeybadger, Honeybadger.get_context)
242
+ # end
243
+ # end
244
+ # SemanticLogger.on_log(CaptureContext)
245
+ #
246
+ # Note:
247
+ # * This callback is called within the thread of the application making the logging call.
248
+ # * If these callbacks are slow they will slow down the application.
249
+ def self.on_log(object = nil, &block)
250
+ Processor.on_log(object, &block)
251
+ end
252
+
223
253
  # Add signal handlers for Semantic Logger
224
254
  #
225
255
  # Two signal handlers will be registered by default:
@@ -285,20 +315,52 @@ module SemanticLogger
285
315
  # If the tag being supplied is definitely a string then this fast
286
316
  # tag api can be used for short lived tags
287
317
  def self.fast_tag(tag)
288
- (Thread.current[:semantic_logger_tags] ||= []) << tag
289
- yield
290
- ensure
291
- Thread.current[:semantic_logger_tags].pop
318
+ return yield if tag.nil? || tag == ''
319
+
320
+ t = Thread.current[:semantic_logger_tags] ||= []
321
+ begin
322
+ t << tag
323
+ yield
324
+ ensure
325
+ t.pop
326
+ end
292
327
  end
293
328
 
294
- # Add the supplied tags to the list of tags to log for this thread whilst
295
- # the supplied block is active.
296
- # Returns result of block
297
- def self.tagged(*tags)
298
- new_tags = push_tags(*tags)
299
- yield self
300
- ensure
301
- pop_tags(new_tags.size)
329
+ # Add the tags or named tags to the list of tags to log for this thread whilst the supplied block is active.
330
+ #
331
+ # Returns result of block.
332
+ #
333
+ # Tagged example:
334
+ # SemanticLogger.tagged(12345, 'jack') do
335
+ # logger.debug('Hello World')
336
+ # end
337
+ #
338
+ # Named Tags (Hash) example:
339
+ # SemanticLogger.tagged(tracking_number: 12345) do
340
+ # logger.debug('Hello World')
341
+ # end
342
+ #
343
+ # Notes:
344
+ # - Tags should be a list without any empty values, or contain any array.
345
+ # - `logger.tagged` is a slower api that will flatten the example below:
346
+ # `logger.tagged([['first', nil], nil, ['more'], 'other'])`
347
+ # to the equivalent of:
348
+ # `logger.tagged('first', 'more', 'other')`
349
+ def self.tagged(*tags, &block)
350
+ return yield if tags.empty?
351
+
352
+ # Allow named tags to be passed into the logger
353
+ if tags.size == 1
354
+ tag = tags[0]
355
+ return tag.is_a?(Hash) ? named_tagged(tag, &block) : fast_tag(tag, &block)
356
+ end
357
+
358
+ begin
359
+ push_tags(*tags)
360
+ yield
361
+ ensure
362
+ pop_tags(tags.size)
363
+ end
302
364
  end
303
365
 
304
366
  # Returns a copy of the [Array] of [String] tags currently active for this thread
@@ -310,13 +372,15 @@ module SemanticLogger
310
372
  end
311
373
 
312
374
  # Add tags to the current scope
313
- # Returns the list of tags pushed after flattening them out and removing blanks
375
+ #
376
+ # Note:
377
+ # - This method does not flatten the array or remove any empty elements, or duplicates
378
+ # since the performance penalty is excessive.
379
+ # - To get the flattening behavior use the slower api:
380
+ # `logger.push_tags`
314
381
  def self.push_tags(*tags)
315
- # Need to flatten and reject empties to support calls from Rails 4
316
- new_tags = tags.flatten.collect(&:to_s).reject(&:empty?)
317
- t = Thread.current[:semantic_logger_tags]
318
- Thread.current[:semantic_logger_tags] = t.nil? ? new_tags : t.concat(new_tags)
319
- new_tags
382
+ (Thread.current[:semantic_logger_tags] ||= []).concat(tags)
383
+ tags
320
384
  end
321
385
 
322
386
  # Remove specified number of tags from the current tag list
@@ -325,33 +389,30 @@ module SemanticLogger
325
389
  t.pop(quantity) unless t.nil?
326
390
  end
327
391
 
328
- # Add the supplied named tags to the list of tags to log for this thread whilst
329
- # the supplied block is active.
330
- #
331
- # Add a payload to all log calls on This Thread within the supplied block
332
- #
333
- # SemanticLogger.named_tagged(tracking_number: 12345) do
334
- # logger.debug('Hello World')
335
- # end
336
- #
337
- # Returns result of block
392
+ # :nodoc
338
393
  def self.named_tagged(hash)
394
+ return yield if hash.nil? || hash.empty?
339
395
  raise(ArgumentError, '#named_tagged only accepts named parameters (Hash)') unless hash.is_a?(Hash)
340
- (Thread.current[:semantic_logger_named_tags] ||= []) << hash
341
- yield
342
- ensure
343
- Thread.current[:semantic_logger_named_tags].pop
396
+
397
+ t = Thread.current[:semantic_logger_named_tags] ||= []
398
+ begin
399
+ t << hash
400
+ yield
401
+ ensure
402
+ t.pop
403
+ end
344
404
  end
345
405
 
346
- # Returns a copy of the [Hash] of named tags currently active for this thread
347
- # Returns nil if no named tags are set
406
+ # Returns [Hash] a copy of the named tags currently active for this thread.
348
407
  def self.named_tags
349
408
  if (list = Thread.current[:semantic_logger_named_tags]) && !list.empty?
350
409
  if list.size > 1
351
- list.inject({}) { |h, sum| sum.merge(h) }
410
+ list.reduce({}) {|sum, h| sum.merge(h)}
352
411
  else
353
412
  list.first.clone
354
413
  end
414
+ else
415
+ {}
355
416
  end
356
417
  end
357
418
 
@@ -401,10 +462,10 @@ module SemanticLogger
401
462
 
402
463
  private
403
464
 
404
- @@appenders = Concurrent::Array.new
465
+ @appenders = Concurrent::Array.new
405
466
 
406
467
  def self.default_level_index
407
- Thread.current[:semantic_logger_silence] || @@default_level_index
468
+ Thread.current[:semantic_logger_silence] || @default_level_index
408
469
  end
409
470
 
410
471
  # Returns the symbolic level for the supplied level index
@@ -425,14 +486,14 @@ module SemanticLogger
425
486
  LEVELS.index(level)
426
487
  elsif level.is_a?(Integer) && defined?(::Logger::Severity)
427
488
  # Mapping of Rails and Ruby Logger levels to SemanticLogger levels
428
- @@map_levels ||= begin
489
+ @map_levels ||= begin
429
490
  levels = []
430
491
  ::Logger::Severity.constants.each do |constant|
431
492
  levels[::Logger::Severity.const_get(constant)] = LEVELS.find_index(constant.downcase.to_sym) || LEVELS.find_index(:error)
432
493
  end
433
494
  levels
434
495
  end
435
- @@map_levels[level]
496
+ @map_levels[level]
436
497
  end
437
498
  raise "Invalid level:#{level.inspect} being requested. Must be one of #{LEVELS.inspect}" unless index
438
499
  index
@@ -457,8 +518,8 @@ module SemanticLogger
457
518
  end
458
519
 
459
520
  # Initial default Level for all new instances of SemanticLogger::Logger
460
- @@default_level = :info
461
- @@default_level_index = level_to_index(@@default_level)
462
- @@backtrace_level = :error
463
- @@backtrace_level_index = level_to_index(@@backtrace_level)
521
+ @default_level = :info
522
+ @default_level_index = level_to_index(@default_level)
523
+ @backtrace_level = :error
524
+ @backtrace_level_index = level_to_index(@backtrace_level)
464
525
  end