lumberjack 1.0.13 → 1.2.8

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 (58) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +129 -0
  3. data/{MIT_LICENSE → MIT_LICENSE.txt} +0 -0
  4. data/README.md +142 -23
  5. data/VERSION +1 -1
  6. data/lib/lumberjack.rb +70 -22
  7. data/lib/lumberjack/context.rb +35 -0
  8. data/lib/lumberjack/device.rb +22 -8
  9. data/lib/lumberjack/device/date_rolling_log_file.rb +9 -9
  10. data/lib/lumberjack/device/log_file.rb +14 -3
  11. data/lib/lumberjack/device/multi.rb +46 -0
  12. data/lib/lumberjack/device/null.rb +1 -3
  13. data/lib/lumberjack/device/rolling_log_file.rb +45 -21
  14. data/lib/lumberjack/device/size_rolling_log_file.rb +10 -10
  15. data/lib/lumberjack/device/writer.rb +92 -61
  16. data/lib/lumberjack/formatter.rb +97 -28
  17. data/lib/lumberjack/formatter/date_time_formatter.rb +25 -0
  18. data/lib/lumberjack/formatter/exception_formatter.rb +25 -2
  19. data/lib/lumberjack/formatter/id_formatter.rb +23 -0
  20. data/lib/lumberjack/formatter/object_formatter.rb +12 -0
  21. data/lib/lumberjack/formatter/pretty_print_formatter.rb +4 -4
  22. data/lib/lumberjack/formatter/string_formatter.rb +1 -1
  23. data/lib/lumberjack/formatter/strip_formatter.rb +12 -0
  24. data/lib/lumberjack/formatter/structured_formatter.rb +63 -0
  25. data/lib/lumberjack/log_entry.rb +44 -16
  26. data/lib/lumberjack/logger.rb +275 -69
  27. data/lib/lumberjack/rack.rb +3 -2
  28. data/lib/lumberjack/rack/context.rb +18 -0
  29. data/lib/lumberjack/rack/request_id.rb +4 -4
  30. data/lib/lumberjack/rack/unit_of_work.rb +1 -1
  31. data/lib/lumberjack/severity.rb +11 -10
  32. data/lib/lumberjack/tag_formatter.rb +96 -0
  33. data/lib/lumberjack/tagged_logger_support.rb +66 -0
  34. data/lib/lumberjack/tagged_logging.rb +29 -0
  35. data/lib/lumberjack/tags.rb +42 -0
  36. data/lib/lumberjack/template.rb +81 -33
  37. data/lumberjack.gemspec +31 -0
  38. metadata +26 -53
  39. data/Rakefile +0 -40
  40. data/spec/device/date_rolling_log_file_spec.rb +0 -73
  41. data/spec/device/log_file_spec.rb +0 -48
  42. data/spec/device/null_spec.rb +0 -12
  43. data/spec/device/rolling_log_file_spec.rb +0 -151
  44. data/spec/device/size_rolling_log_file_spec.rb +0 -58
  45. data/spec/device/writer_spec.rb +0 -118
  46. data/spec/formatter/exception_formatter_spec.rb +0 -20
  47. data/spec/formatter/inspect_formatter_spec.rb +0 -13
  48. data/spec/formatter/pretty_print_formatter_spec.rb +0 -14
  49. data/spec/formatter/string_formatter_spec.rb +0 -12
  50. data/spec/formatter_spec.rb +0 -45
  51. data/spec/log_entry_spec.rb +0 -69
  52. data/spec/logger_spec.rb +0 -411
  53. data/spec/lumberjack_spec.rb +0 -29
  54. data/spec/rack/request_id_spec.rb +0 -48
  55. data/spec/rack/unit_of_work_spec.rb +0 -26
  56. data/spec/severity_spec.rb +0 -23
  57. data/spec/spec_helper.rb +0 -32
  58. data/spec/template_spec.rb +0 -34
@@ -30,14 +30,17 @@ module Lumberjack
30
30
  # The time that the device was last flushed.
31
31
  attr_reader :last_flushed_at
32
32
 
33
- # The name of the program associated with log messages.
33
+ # Set +silencer+ to false to disable silencing the log.
34
+ attr_accessor :silencer
35
+
36
+ # Set the name of the program to attach to log entries.
34
37
  attr_writer :progname
35
38
 
36
- # The device being written to.
37
- attr_reader :device
39
+ # The device being written to
40
+ attr_accessor :device
38
41
 
39
- # Set +silencer+ to false to disable silencing the log.
40
- attr_accessor :silencer
42
+ # The TagFormatter used for formatting tags for output
43
+ attr_accessor :tag_formatter
41
44
 
42
45
  # Create a new logger to log to a Device.
43
46
  #
@@ -45,37 +48,50 @@ module Lumberjack
45
48
  #
46
49
  # If it is a Device object, that object will be used.
47
50
  # If it has a +write+ method, it will be wrapped in a Device::Writer class.
48
- # If it is <tt>:null</tt>, it will be a Null device that won't record any output.
51
+ # If it is :null, it will be a Null device that won't record any output.
49
52
  # Otherwise, it will be assumed to be file path and wrapped in a Device::LogFile class.
50
53
  #
51
54
  # This method can take the following options:
52
55
  #
53
- # * <tt>:level</tt> - The logging level below which messages will be ignored.
54
- # * <tt>:progname</tt> - The name of the program that will be recorded with each log entry.
55
- # * <tt>:flush_seconds</tt> - The maximum number of seconds between flush calls.
56
- # * <tt>:roll</tt> - If the log device is a file path, it will be a Device::DateRollingLogFile if this is set.
57
- # * <tt>:max_size</tt> - If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
56
+ # * :level - The logging level below which messages will be ignored.
57
+ # * :formatter - The formatter to use for outputting messages to the log.
58
+ # * :datetime_format - The format to use for log timestamps.
59
+ # * :tag_formatter - The TagFormatter to use for formatting tags.
60
+ # * :progname - The name of the program that will be recorded with each log entry.
61
+ # * :flush_seconds - The maximum number of seconds between flush calls.
62
+ # * :roll - If the log device is a file path, it will be a Device::DateRollingLogFile if this is set.
63
+ # * :max_size - If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
58
64
  #
59
65
  # All other options are passed to the device constuctor.
60
- def initialize(device = STDOUT, options = {})
61
- @thread_settings = {}
62
-
66
+ def initialize(device = $stdout, options = {})
63
67
  options = options.dup
64
68
  self.level = options.delete(:level) || INFO
65
69
  self.progname = options.delete(:progname)
66
70
  max_flush_seconds = options.delete(:flush_seconds).to_f
67
71
 
68
- @device = open_device(device, options)
69
- @_formatter = Formatter.new
72
+ @device = open_device(device, options) if device
73
+ self.formatter = (options[:formatter] || Formatter.new)
74
+ @tag_formatter = (options[:tag_formatter] || TagFormatter.new)
75
+ time_format = (options[:datetime_format] || options[:time_format])
76
+ self.datetime_format = time_format if time_format
70
77
  @last_flushed_at = Time.now
71
78
  @silencer = true
79
+ @tags = {}
80
+ @closed = false
72
81
 
73
82
  create_flusher_thread(max_flush_seconds) if max_flush_seconds > 0
74
83
  end
75
84
 
76
- # Get the Formatter object used to convert messages into strings.
77
- def formatter
78
- @_formatter
85
+ # Get the timestamp format on the device if it has one.
86
+ def datetime_format
87
+ device.datetime_format if device.respond_to?(:datetime_format)
88
+ end
89
+
90
+ # Set the timestamp format on the device if it is supported.
91
+ def datetime_format=(format)
92
+ if device.respond_to?(:datetime_format=)
93
+ device.datetime_format = format
94
+ end
79
95
  end
80
96
 
81
97
  # Get the level of severity of entries that are logged. Entries with a lower
@@ -84,6 +100,47 @@ module Lumberjack
84
100
  thread_local_value(:lumberjack_logger_level) || @level
85
101
  end
86
102
 
103
+ alias sev_threshold level
104
+
105
+ # Set the log level using either an integer level like Logger::INFO or a label like
106
+ # :info or "info"
107
+ def level=(value)
108
+ @level = if value.is_a?(Integer)
109
+ value
110
+ else
111
+ Severity.label_to_level(value)
112
+ end
113
+ end
114
+
115
+ alias sev_threshold= level=
116
+
117
+ # Set the Lumberjack::Formatter used to format objects for logging as messages.
118
+ def formatter=(value)
119
+ @_formatter = (value.is_a?(TaggedLoggerSupport::Formatter) ? value.__formatter : value)
120
+ end
121
+
122
+ # Get the Lumberjack::Formatter used to format objects for logging as messages.
123
+ def formatter
124
+ if respond_to?(:tagged)
125
+ # Wrap in an object that supports ActiveSupport::TaggedLogger API
126
+ TaggedLoggerSupport::Formatter.new(logger: self, formatter: @_formatter)
127
+ else
128
+ @_formatter
129
+ end
130
+ end
131
+
132
+ # Enable this logger to function like an ActiveSupport::TaggedLogger. This will make the logger
133
+ # API compatible with ActiveSupport::TaggedLogger and is provided as a means of compatibility
134
+ # with other libraries that assume they can call the `tagged` method on a logger to add tags.
135
+ #
136
+ # The tags added with this method are just strings so they are stored in the logger tags
137
+ # in an array under the "tagged" tag. So calling `logger.tagged("foo", "bar")` will result
138
+ # in tags `{"tagged" => ["foo", "bar"]}`.
139
+ def tagged_logger!
140
+ extend(TaggedLoggerSupport)
141
+ self
142
+ end
143
+
87
144
  # Add a message to the log with a given severity. The message can be either
88
145
  # passed in the +message+ argument or supplied with a block. This method
89
146
  # is not normally called. Instead call one of the helper functions
@@ -94,39 +151,59 @@ module Lumberjack
94
151
  #
95
152
  # === Example
96
153
  #
97
- # logger.add(Lumberjack::Severity::ERROR, exception)
98
- # logger.add(Lumberjack::Severity::INFO, "Request completed")
99
- # logger.add(:warn, "Request took a long time")
100
- # logger.add(Lumberjack::Severity::DEBUG){"Start processing with options #{options.inspect}"}
101
- def add(severity, message = nil, progname = nil)
102
- severity = Severity.label_to_level(severity) if severity.is_a?(String) || severity.is_a?(Symbol)
154
+ # logger.add_entry(Logger::ERROR, exception)
155
+ # logger.add_entry(Logger::INFO, "Request completed")
156
+ # logger.add_entry(:warn, "Request took a long time")
157
+ # logger.add_entry(Logger::DEBUG){"Start processing with options #{options.inspect}"}
158
+ def add_entry(severity, message, progname = nil, tags = nil)
159
+ begin
160
+ severity = Severity.label_to_level(severity) unless severity.is_a?(Integer)
161
+ return true unless device && severity && severity >= level
162
+
163
+ return true if Thread.current[:lumberjack_logging]
164
+ Thread.current[:lumberjack_logging] = true
103
165
 
104
- return unless severity && severity >= level
166
+ time = Time.now
167
+ message = message.call if message.is_a?(Proc)
168
+ message = formatter.format(message)
169
+ progname ||= self.progname
105
170
 
106
- time = Time.now
171
+ current_tags = self.tags
172
+ tags = nil unless tags.is_a?(Hash)
173
+ if current_tags.empty?
174
+ tags = Tags.stringify_keys(tags) unless tags.nil?
175
+ else
176
+ tags = if tags.nil?
177
+ current_tags.dup
178
+ else
179
+ current_tags.merge(Tags.stringify_keys(tags))
180
+ end
181
+ end
182
+ tags = Tags.expand_runtime_values(tags)
183
+ tags = tag_formatter.format(tags) if tag_formatter
184
+
185
+ entry = LogEntry.new(time, severity, message, progname, $$, tags)
186
+ write_to_device(entry)
187
+ ensure
188
+ Thread.current[:lumberjack_logging] = nil
189
+ end
190
+ true
191
+ end
192
+
193
+ # ::Logger compatible method to add a log entry.
194
+ def add(severity, message = nil, progname = nil, &block)
107
195
  if message.nil?
108
- if block_given?
109
- message = yield
196
+ if block
197
+ message = block
110
198
  else
111
199
  message = progname
112
200
  progname = nil
113
201
  end
114
202
  end
115
-
116
- message = @_formatter.format(message)
117
- progname ||= self.progname
118
- entry = LogEntry.new(time, severity, message, progname, $$, Lumberjack.unit_of_work_id)
119
- begin
120
- device.write(entry)
121
- rescue => e
122
- $stderr.puts("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
123
- $stderr.puts(entry.to_s)
124
- end
125
-
126
- nil
203
+ add_entry(severity, message, progname)
127
204
  end
128
205
 
129
- alias_method :log, :add
206
+ alias log add
130
207
 
131
208
  # Flush the logging device. Messages are not guaranteed to be written until this method is called.
132
209
  def flush
@@ -138,12 +215,22 @@ module Lumberjack
138
215
  # Close the logging device.
139
216
  def close
140
217
  flush
141
- @device.close if @device.respond_to?(:close)
218
+ device.close if device.respond_to?(:close)
219
+ @closed = true
220
+ end
221
+
222
+ def closed?
223
+ @closed
224
+ end
225
+
226
+ def reopen(logdev = nil)
227
+ @closed = false
228
+ device.reopen(logdev) if device.respond_to?(:reopen)
142
229
  end
143
230
 
144
231
  # Log a +FATAL+ message. The message can be passed in either the +message+ argument or in a block.
145
- def fatal(message = nil, progname = nil, &block)
146
- add(FATAL, message, progname, &block)
232
+ def fatal(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
233
+ call_add_entry(FATAL, message_or_progname_or_tags, progname_or_tags, &block)
147
234
  end
148
235
 
149
236
  # Return +true+ if +FATAL+ messages are being logged.
@@ -151,9 +238,14 @@ module Lumberjack
151
238
  level <= FATAL
152
239
  end
153
240
 
241
+ # Set the log level to fatal.
242
+ def fatal!
243
+ self.level = FATAL
244
+ end
245
+
154
246
  # Log an +ERROR+ message. The message can be passed in either the +message+ argument or in a block.
155
- def error(message = nil, progname = nil, &block)
156
- add(ERROR, message, progname, &block)
247
+ def error(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
248
+ call_add_entry(ERROR, message_or_progname_or_tags, progname_or_tags, &block)
157
249
  end
158
250
 
159
251
  # Return +true+ if +ERROR+ messages are being logged.
@@ -161,9 +253,14 @@ module Lumberjack
161
253
  level <= ERROR
162
254
  end
163
255
 
256
+ # Set the log level to error.
257
+ def error!
258
+ self.level = ERROR
259
+ end
260
+
164
261
  # Log a +WARN+ message. The message can be passed in either the +message+ argument or in a block.
165
- def warn(message = nil, progname = nil, &block)
166
- add(WARN, message, progname, &block)
262
+ def warn(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
263
+ call_add_entry(WARN, message_or_progname_or_tags, progname_or_tags, &block)
167
264
  end
168
265
 
169
266
  # Return +true+ if +WARN+ messages are being logged.
@@ -171,9 +268,14 @@ module Lumberjack
171
268
  level <= WARN
172
269
  end
173
270
 
271
+ # Set the log level to warn.
272
+ def warn!
273
+ self.level = WARN
274
+ end
275
+
174
276
  # Log an +INFO+ message. The message can be passed in either the +message+ argument or in a block.
175
- def info(message = nil, progname = nil, &block)
176
- add(INFO, message, progname, &block)
277
+ def info(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
278
+ call_add_entry(INFO, message_or_progname_or_tags, progname_or_tags, &block)
177
279
  end
178
280
 
179
281
  # Return +true+ if +INFO+ messages are being logged.
@@ -181,9 +283,14 @@ module Lumberjack
181
283
  level <= INFO
182
284
  end
183
285
 
286
+ # Set the log level to info.
287
+ def info!
288
+ self.level = INFO
289
+ end
290
+
184
291
  # Log a +DEBUG+ message. The message can be passed in either the +message+ argument or in a block.
185
- def debug(message = nil, progname = nil, &block)
186
- add(DEBUG, message, progname, &block)
292
+ def debug(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
293
+ call_add_entry(DEBUG, message_or_progname_or_tags, progname_or_tags, &block)
187
294
  end
188
295
 
189
296
  # Return +true+ if +DEBUG+ messages are being logged.
@@ -191,21 +298,19 @@ module Lumberjack
191
298
  level <= DEBUG
192
299
  end
193
300
 
301
+ # Set the log level to debug.
302
+ def debug!
303
+ self.level = DEBUG
304
+ end
305
+
194
306
  # Log a message when the severity is not known. Unknown messages will always appear in the log.
195
307
  # The message can be passed in either the +message+ argument or in a block.
196
- def unknown(message = nil, progname = nil, &block)
197
- add(UNKNOWN, message, progname, &block)
308
+ def unknown(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
309
+ call_add_entry(UNKNOWN, message_or_progname_or_tags, progname_or_tags, &block)
198
310
  end
199
311
 
200
- alias_method :<<, :unknown
201
-
202
- # Set the minimum level of severity of messages to log.
203
- def level=(severity)
204
- if severity.is_a?(Integer)
205
- @level = severity
206
- else
207
- @level = Severity.label_to_level(severity)
208
- end
312
+ def <<(msg)
313
+ add_entry(UNKNOWN, msg)
209
314
  end
210
315
 
211
316
  # Silence the logger by setting a new log level inside a block. By default, only +ERROR+ or +FATAL+
@@ -213,12 +318,15 @@ module Lumberjack
213
318
  #
214
319
  # === Example
215
320
  #
216
- # logger.level = Lumberjack::Severity::INFO
321
+ # logger.level = Logger::INFO
217
322
  # logger.silence do
218
323
  # do_something # Log level inside the block is +ERROR+
219
324
  # end
220
325
  def silence(temporary_level = ERROR, &block)
221
326
  if silencer
327
+ unless temporary_level.is_a?(Integer)
328
+ temporary_level = Severity.label_to_level(temporary_level)
329
+ end
222
330
  push_thread_local_value(:lumberjack_logger_level, temporary_level, &block)
223
331
  else
224
332
  yield
@@ -240,8 +348,95 @@ module Lumberjack
240
348
  thread_local_value(:lumberjack_logger_progname) || @progname
241
349
  end
242
350
 
351
+ # Set a hash of tags on logger. If a block is given, the tags will only be set
352
+ # for the duration of the block. If this method is called inside such a block,
353
+ # the tags will only be defined on the tags in that block. When the parent block
354
+ # exits, all the tags will be reverted. If there is no block, then the tags will
355
+ # be defined as global and apply to all log statements.
356
+ def tag(tags, &block)
357
+ tags = Tags.stringify_keys(tags)
358
+ thread_tags = thread_local_value(:lumberjack_logger_tags)
359
+ if block
360
+ merged_tags = (thread_tags ? thread_tags.merge(tags) : tags.dup)
361
+ push_thread_local_value(:lumberjack_logger_tags, merged_tags, &block)
362
+ elsif thread_tags
363
+ thread_tags.merge!(tags)
364
+ nil
365
+ else
366
+ @tags.merge!(tags)
367
+ nil
368
+ end
369
+ end
370
+
371
+ # Remove a tag from the current tag context. If this is called inside a block to a
372
+ # call to `tag`, the tags will only be removed for the duration of that block. Otherwise
373
+ # they will be removed from the global tags.
374
+ def remove_tag(*tag_names)
375
+ thread_tags = thread_local_value(:lumberjack_logger_tags)
376
+ if thread_tags
377
+ tag_names.each { |name| thread_tags.delete(name.to_s) }
378
+ else
379
+ tag_names.each { |name| @tags.delete(name.to_s) }
380
+ end
381
+ end
382
+
383
+ # Return all tags in scope on the logger including global tags set on the Lumberjack
384
+ # context, tags set on the logger, and tags set on the current block for the logger.
385
+ def tags
386
+ tags = {}
387
+ context_tags = Lumberjack.context_tags
388
+ tags.merge!(context_tags) if context_tags && !context_tags.empty?
389
+ tags.merge!(@tags) if !@tags.empty? && !thread_local_value(:lumberjack_logger_untagged)
390
+ scope_tags = thread_local_value(:lumberjack_logger_tags)
391
+ tags.merge!(scope_tags) if scope_tags && !scope_tags.empty?
392
+ tags
393
+ end
394
+
395
+ # Remove all tags on the current logger and logging context within a block.
396
+ # You can still set new block scoped tags within theuntagged block and provide
397
+ # tags on individual log methods.
398
+ def untagged(&block)
399
+ Lumberjack.use_context(nil) do
400
+ scope_tags = thread_local_value(:lumberjack_logger_tags)
401
+ untagged = thread_local_value(:lumberjack_logger_untagged)
402
+ begin
403
+ set_thread_local_value(:lumberjack_logger_untagged, true)
404
+ set_thread_local_value(:lumberjack_logger_tags, nil)
405
+ tag({}, &block)
406
+ ensure
407
+ set_thread_local_value(:lumberjack_logger_untagged, untagged)
408
+ set_thread_local_value(:lumberjack_logger_tags, scope_tags)
409
+ end
410
+ end
411
+ end
412
+
243
413
  private
244
414
 
415
+ # Dereference arguments to log calls so we can have methods with compatibility with ::Logger
416
+ def call_add_entry(severity, message_or_progname_or_tags, progname_or_tags, &block) #:nodoc:
417
+ message = nil
418
+ progname = nil
419
+ tags = nil
420
+ if block
421
+ message = block
422
+ if message_or_progname_or_tags.is_a?(Hash)
423
+ tags = message_or_progname_or_tags
424
+ progname = progname_or_tags
425
+ else
426
+ progname = message_or_progname_or_tags
427
+ tags = progname_or_tags if progname_or_tags.is_a?(Hash)
428
+ end
429
+ else
430
+ message = message_or_progname_or_tags
431
+ if progname_or_tags.is_a?(Hash)
432
+ tags = progname_or_tags
433
+ else
434
+ progname = progname_or_tags
435
+ end
436
+ end
437
+ add_entry(severity, message, progname, tags)
438
+ end
439
+
245
440
  # Set a local value for a thread tied to this object.
246
441
  def set_thread_local_value(name, value) #:nodoc:
247
442
  values = Thread.current[name]
@@ -276,7 +471,9 @@ module Lumberjack
276
471
 
277
472
  # Open a logging device.
278
473
  def open_device(device, options) #:nodoc:
279
- if device.is_a?(Device)
474
+ if device.nil?
475
+ nil
476
+ elsif device.is_a?(Device)
280
477
  device
281
478
  elsif device.respond_to?(:write) && device.respond_to?(:flush)
282
479
  Device::Writer.new(device, options)
@@ -287,25 +484,34 @@ module Lumberjack
287
484
  if options[:roll]
288
485
  Device::DateRollingLogFile.new(device, options)
289
486
  elsif options[:max_size]
290
- Device::SizeRollingLogFile.new(device, options)
487
+ Device::SizeRollingLogFile.new(device, options)
291
488
  else
292
489
  Device::LogFile.new(device, options)
293
490
  end
294
491
  end
295
492
  end
296
493
 
494
+ def write_to_device(entry) #:nodoc:
495
+ device.write(entry)
496
+ rescue => e
497
+ # rubocop:disable Style/StderrPuts
498
+ $stderr.puts("#{e.class.name}: #{e.message}#{" at " + e.backtrace.first if e.backtrace}")
499
+ $stderr.puts(entry.to_s)
500
+ # rubocop:enable Style/StderrPuts
501
+ end
502
+
297
503
  # Create a thread that will periodically call flush.
298
504
  def create_flusher_thread(flush_seconds) #:nodoc:
299
505
  if flush_seconds > 0
300
506
  begin
301
507
  logger = self
302
508
  Thread.new do
303
- loop do
509
+ until closed?
304
510
  begin
305
511
  sleep(flush_seconds)
306
512
  logger.flush if Time.now - logger.last_flushed_at >= flush_seconds
307
513
  rescue => e
308
- STDERR.puts("Error flushing log: #{e.inspect}")
514
+ warn("Error flushing log: #{e.inspect}")
309
515
  end
310
516
  end
311
517
  end