semantic_logger 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
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