lumberjack 1.2.3 → 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.
@@ -8,30 +8,30 @@ module Lumberjack
8
8
  # production.log.1, then production.log.2, etc.
9
9
  class SizeRollingLogFile < RollingLogFile
10
10
  attr_reader :max_size
11
-
11
+
12
12
  # Create an new log device to the specified file. The maximum size of the log file is specified with
13
13
  # the :max_size option. The unit can also be specified: "32K", "100M", "2G" are all valid.
14
14
  def initialize(path, options = {})
15
15
  @manual = options[:manual]
16
16
  @max_size = options[:max_size]
17
17
  if @max_size.is_a?(String)
18
- if @max_size.match(/^(\d+(\.\d+)?)([KMG])?$/i)
18
+ if @max_size =~ /^(\d+(\.\d+)?)([KMG])?$/i
19
19
  @max_size = $~[1].to_f
20
20
  units = $~[3].to_s.upcase
21
21
  case units
22
22
  when "K"
23
23
  @max_size *= 1024
24
24
  when "M"
25
- @max_size *= 1024 ** 2
25
+ @max_size *= 1024**2
26
26
  when "G"
27
- @max_size *= 1024 ** 3
27
+ @max_size *= 1024**3
28
28
  end
29
29
  @max_size = @max_size.round
30
30
  else
31
31
  raise ArgumentError.new("illegal value for :max_size (#{@max_size})")
32
32
  end
33
33
  end
34
-
34
+
35
35
  super
36
36
  end
37
37
 
@@ -44,15 +44,15 @@ module Lumberjack
44
44
  rescue SystemCallError
45
45
  false
46
46
  end
47
-
47
+
48
48
  protected
49
-
49
+
50
50
  # Calculate the next archive file name extension.
51
51
  def next_archive_number # :nodoc:
52
52
  max = 0
53
53
  Dir.glob("#{path}.*").each do |filename|
54
- if filename.match(/\.\d+$/)
55
- suffix = filename.split('.').last.to_i
54
+ if /\.\d+\z/ =~ filename
55
+ suffix = filename.split(".").last.to_i
56
56
  max = suffix if suffix > max
57
57
  end
58
58
  end
@@ -71,7 +71,7 @@ module Lumberjack
71
71
  @template = template
72
72
  else
73
73
  additional_lines = (options[:additional_lines] || DEFAULT_ADDITIONAL_LINES_TEMPLATE)
74
- @template = Template.new(template, :additional_lines => additional_lines, :time_format => options[:time_format])
74
+ @template = Template.new(template, additional_lines: additional_lines, time_format: options[:time_format])
75
75
  end
76
76
  end
77
77
 
@@ -133,14 +133,10 @@ module Lumberjack
133
133
  protected
134
134
 
135
135
  # Set the underlying stream.
136
- def stream=(stream)
137
- @stream = stream
138
- end
136
+ attr_writer :stream
139
137
 
140
138
  # Get the underlying stream.
141
- def stream
142
- @stream
143
- end
139
+ attr_reader :stream
144
140
 
145
141
  private
146
142
 
@@ -149,10 +145,10 @@ module Lumberjack
149
145
  lines = lines.first if lines.is_a?(Array) && lines.size == 1
150
146
 
151
147
  out = nil
152
- if lines.is_a?(Array)
153
- out = "#{lines.join(Lumberjack::LINE_SEPARATOR)}#{Lumberjack::LINE_SEPARATOR}"
148
+ out = if lines.is_a?(Array)
149
+ "#{lines.join(Lumberjack::LINE_SEPARATOR)}#{Lumberjack::LINE_SEPARATOR}"
154
150
  else
155
- out = "#{lines}#{Lumberjack::LINE_SEPARATOR}"
151
+ "#{lines}#{Lumberjack::LINE_SEPARATOR}"
156
152
  end
157
153
 
158
154
  begin
@@ -170,9 +166,13 @@ module Lumberjack
170
166
  end
171
167
  end
172
168
  end
173
- stream.flush rescue nil
169
+ begin
170
+ stream.flush
171
+ rescue
172
+ nil
173
+ end
174
174
  rescue => e
175
- $stderr.write("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
175
+ $stderr.write("#{e.class.name}: #{e.message}#{" at " + e.backtrace.first if e.backtrace}")
176
176
  $stderr.write(out)
177
177
  $stderr.flush
178
178
  end
@@ -12,15 +12,15 @@ module Lumberjack
12
12
  #
13
13
  # Enumerable objects (including Hash and Array) will call the formatter recursively for each element.
14
14
  class Formatter
15
- require_relative "formatter/date_time_formatter.rb"
16
- require_relative "formatter/exception_formatter.rb"
17
- require_relative "formatter/id_formatter.rb"
18
- require_relative "formatter/inspect_formatter.rb"
19
- require_relative "formatter/object_formatter.rb"
20
- require_relative "formatter/pretty_print_formatter.rb"
21
- require_relative "formatter/string_formatter.rb"
22
- require_relative "formatter/strip_formatter.rb"
23
- require_relative "formatter/structured_formatter.rb"
15
+ require_relative "formatter/date_time_formatter"
16
+ require_relative "formatter/exception_formatter"
17
+ require_relative "formatter/id_formatter"
18
+ require_relative "formatter/inspect_formatter"
19
+ require_relative "formatter/object_formatter"
20
+ require_relative "formatter/pretty_print_formatter"
21
+ require_relative "formatter/string_formatter"
22
+ require_relative "formatter/strip_formatter"
23
+ require_relative "formatter/structured_formatter"
24
24
 
25
25
  class << self
26
26
  # Returns a new empty formatter with no mapping. For historical reasons, a formatter
@@ -30,7 +30,7 @@ module Lumberjack
30
30
  new.clear
31
31
  end
32
32
  end
33
-
33
+
34
34
  def initialize
35
35
  @class_formatters = {}
36
36
  @module_formatters = {}
@@ -72,10 +72,10 @@ module Lumberjack
72
72
  remove(klass)
73
73
  else
74
74
  if formatter.is_a?(Symbol)
75
- formatter_class_name = "#{formatter.to_s.gsub(/(^|_)([a-z])/){|m| $~[2].upcase}}Formatter"
75
+ formatter_class_name = "#{formatter.to_s.gsub(/(^|_)([a-z])/) { |m| $~[2].upcase }}Formatter"
76
76
  formatter = Formatter.const_get(formatter_class_name).new
77
77
  end
78
-
78
+
79
79
  Array(klass).each do |k|
80
80
  if k.class == Module
81
81
  @module_formatters[k] = formatter
@@ -106,7 +106,7 @@ module Lumberjack
106
106
  end
107
107
  self
108
108
  end
109
-
109
+
110
110
  # Remove all formatters including the default formatter. Can be chained to add method calls.
111
111
  def clear
112
112
  @class_formatters.clear
@@ -117,7 +117,7 @@ module Lumberjack
117
117
  # Format a message object as a string.
118
118
  def format(message)
119
119
  formatter = formatter_for(message.class)
120
- if formatter && formatter.respond_to?(:call)
120
+ if formatter&.respond_to?(:call)
121
121
  formatter.call(message)
122
122
  else
123
123
  message
@@ -135,7 +135,7 @@ module Lumberjack
135
135
  # Find the formatter for a class by looking it up using the class hierarchy.
136
136
  def formatter_for(klass) #:nodoc:
137
137
  check_modules = true
138
- while klass != nil do
138
+ until klass.nil?
139
139
  formatter = @class_formatters[klass.name]
140
140
  return formatter if formatter
141
141
 
@@ -5,13 +5,12 @@ module Lumberjack
5
5
  # Format a Date, Time, or DateTime object. If you don't specify a format in the constructor,
6
6
  # it will use the ISO-8601 format.
7
7
  class DateTimeFormatter
8
-
9
8
  attr_reader :format
10
-
9
+
11
10
  def initialize(format = nil)
12
11
  @format = format.dup.to_s.freeze unless format.nil?
13
12
  end
14
-
13
+
15
14
  def call(obj)
16
15
  if @format && obj.respond_to?(:strftime)
17
16
  obj.strftime(@format)
@@ -7,7 +7,6 @@ module Lumberjack
7
7
  # passed to this object and the returned array is what will be logged. You can
8
8
  # use this to clean out superfluous lines.
9
9
  class ExceptionFormatter
10
-
11
10
  attr_accessor :backtrace_cleaner
12
11
 
13
12
  def initialize(backtrace_cleaner = nil)
@@ -33,7 +32,6 @@ module Lumberjack
33
32
  trace
34
33
  end
35
34
  end
36
-
37
35
  end
38
36
  end
39
37
  end
@@ -9,11 +9,11 @@ module Lumberjack
9
9
  def initialize(id_attribute = :id)
10
10
  @id_attribute = id_attribute
11
11
  end
12
-
12
+
13
13
  def call(obj)
14
14
  if obj.respond_to?(@id_attribute)
15
15
  id = obj.send(@id_attribute)
16
- { "class" => obj.class.name, "id" => id }
16
+ {"class" => obj.class.name, "id" => id}
17
17
  else
18
18
  obj.to_s
19
19
  end
@@ -1,20 +1,20 @@
1
1
  # frozen_string_literals: true
2
2
 
3
- require 'pp'
4
- require 'stringio'
3
+ require "pp"
4
+ require "stringio"
5
5
 
6
6
  module Lumberjack
7
7
  class Formatter
8
8
  # Format an object with it's pretty print method.
9
9
  class PrettyPrintFormatter
10
10
  attr_accessor :width
11
-
11
+
12
12
  # Create a new formatter. The maximum width of the message can be specified with the width
13
13
  # parameter (defaults to 79 characters).
14
14
  def initialize(width = 79)
15
15
  @width = width
16
16
  end
17
-
17
+
18
18
  def call(obj)
19
19
  s = StringIO.new
20
20
  PP.pp(obj, s)
@@ -6,6 +6,9 @@ module Lumberjack
6
6
  class Formatter
7
7
  # Dereference arrays and hashes and recursively call formatters on each element.
8
8
  class StructuredFormatter
9
+ class RecusiveReferenceError < StandardError
10
+ end
11
+
9
12
  def initialize(formatter = nil)
10
13
  @formatter = formatter
11
14
  end
@@ -18,31 +21,43 @@ module Lumberjack
18
21
 
19
22
  def call_with_references(obj, references)
20
23
  if obj.is_a?(Hash)
21
- hash = {}
22
- references << obj.object_id
23
- obj.each do |name, value|
24
- next if references.include?(value.object_id)
25
- references << value
26
- hash[name.to_s] = call_with_references(value, references)
24
+ with_object_reference(obj, references) do
25
+ hash = {}
26
+ obj.each do |name, value|
27
+ value = call_with_references(value, references)
28
+ hash[name.to_s] = value unless value.is_a?(RecusiveReferenceError)
29
+ end
30
+ hash
27
31
  end
28
- references.delete(obj.object_id)
29
- hash
30
32
  elsif obj.is_a?(Enumerable) && obj.respond_to?(:size) && obj.size != Float::INFINITY
31
- array = []
32
- references << obj.object_id
33
- obj.each do |value|
34
- next if references.include?(value.object_id)
35
- references << value
36
- array << call_with_references(value, references)
33
+ with_object_reference(obj, references) do
34
+ array = []
35
+ obj.each do |value|
36
+ value = call_with_references(value, references)
37
+ array << value unless value.is_a?(RecusiveReferenceError)
38
+ end
39
+ array
37
40
  end
38
- references.delete(obj.object_id)
39
- array
40
41
  elsif @formatter
41
42
  @formatter.format(obj)
42
43
  else
43
44
  obj
44
45
  end
45
46
  end
47
+
48
+ def with_object_reference(obj, references)
49
+ if obj.is_a?(Enumerable)
50
+ return RecusiveReferenceError.new if references.include?(obj.object_id)
51
+ references << obj.object_id
52
+ begin
53
+ yield
54
+ ensure
55
+ references.delete(obj.object_id)
56
+ end
57
+ else
58
+ yield
59
+ end
60
+ end
46
61
  end
47
62
  end
48
63
  end
@@ -17,10 +17,10 @@ module Lumberjack
17
17
  @progname = progname
18
18
  @pid = pid
19
19
  # backward compatibility with 1.0 API where the last argument was the unit of work id
20
- if tags.nil? || tags.is_a?(Hash)
21
- @tags = tags
20
+ @tags = if tags.nil? || tags.is_a?(Hash)
21
+ tags
22
22
  else
23
- @tags = { UNIT_OF_WORK_ID => tags }
23
+ {UNIT_OF_WORK_ID => tags}
24
24
  end
25
25
  end
26
26
 
@@ -29,7 +29,7 @@ module Lumberjack
29
29
  end
30
30
 
31
31
  def to_s
32
- "[#{time.strftime(TIME_FORMAT)}.#{(time.usec / 1000.0).round.to_s.rjust(3, '0')} #{severity_label} #{progname}(#{pid})#{tags_to_s}] #{message}"
32
+ "[#{time.strftime(TIME_FORMAT)}.#{(time.usec / 1000.0).round.to_s.rjust(3, "0")} #{severity_label} #{progname}(#{pid})#{tags_to_s}] #{message}"
33
33
  end
34
34
 
35
35
  def inspect
@@ -46,10 +46,10 @@ module Lumberjack
46
46
  if tags
47
47
  tags[UNIT_OF_WORK_ID] = value
48
48
  else
49
- @tags = { UNIT_OF_WORK_ID => value }
49
+ @tags = {UNIT_OF_WORK_ID => value}
50
50
  end
51
51
  end
52
-
52
+
53
53
  # Return the tag with the specified name.
54
54
  def tag(name)
55
55
  tags[name.to_s] if tags
@@ -58,10 +58,8 @@ module Lumberjack
58
58
  private
59
59
 
60
60
  def tags_to_s
61
- tags_string = String.new
62
- if tags
63
- tags.each { |name, value| tags_string << " #{name}:#{value.inspect}" }
64
- end
61
+ tags_string = ""
62
+ tags&.each { |name, value| tags_string << " #{name}:#{value.inspect}" }
65
63
  tags_string
66
64
  end
67
65
  end
@@ -63,7 +63,7 @@ module Lumberjack
63
63
  # * :max_size - If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
64
64
  #
65
65
  # All other options are passed to the device constuctor.
66
- def initialize(device = STDOUT, options = {})
66
+ def initialize(device = $stdout, options = {})
67
67
  options = options.dup
68
68
  self.level = options.delete(:level) || INFO
69
69
  self.progname = options.delete(:progname)
@@ -100,19 +100,19 @@ module Lumberjack
100
100
  thread_local_value(:lumberjack_logger_level) || @level
101
101
  end
102
102
 
103
- alias_method :sev_threshold, :level
103
+ alias sev_threshold level
104
104
 
105
105
  # Set the log level using either an integer level like Logger::INFO or a label like
106
106
  # :info or "info"
107
107
  def level=(value)
108
- if value.is_a?(Integer)
109
- @level = value
108
+ @level = if value.is_a?(Integer)
109
+ value
110
110
  else
111
- @level = Severity::label_to_level(value)
111
+ Severity.label_to_level(value)
112
112
  end
113
113
  end
114
114
 
115
- alias_method :sev_threshold=, :level=
115
+ alias sev_threshold= level=
116
116
 
117
117
  # Set the Lumberjack::Formatter used to format objects for logging as messages.
118
118
  def formatter=(value)
@@ -137,7 +137,7 @@ module Lumberjack
137
137
  # in an array under the "tagged" tag. So calling `logger.tagged("foo", "bar")` will result
138
138
  # in tags `{"tagged" => ["foo", "bar"]}`.
139
139
  def tagged_logger!
140
- self.extend(TaggedLoggerSupport)
140
+ extend(TaggedLoggerSupport)
141
141
  self
142
142
  end
143
143
 
@@ -156,10 +156,10 @@ module Lumberjack
156
156
  # logger.add_entry(:warn, "Request took a long time")
157
157
  # logger.add_entry(Logger::DEBUG){"Start processing with options #{options.inspect}"}
158
158
  def add_entry(severity, message, progname = nil, tags = nil)
159
- begin
159
+ begin
160
160
  severity = Severity.label_to_level(severity) unless severity.is_a?(Integer)
161
161
  return true unless device && severity && severity >= level
162
-
162
+
163
163
  return true if Thread.current[:lumberjack_logging]
164
164
  Thread.current[:lumberjack_logging] = true
165
165
 
@@ -173,10 +173,10 @@ module Lumberjack
173
173
  if current_tags.empty?
174
174
  tags = Tags.stringify_keys(tags) unless tags.nil?
175
175
  else
176
- if tags.nil?
177
- tags = current_tags.dup
176
+ tags = if tags.nil?
177
+ current_tags.dup
178
178
  else
179
- tags = current_tags.merge(Tags.stringify_keys(tags))
179
+ current_tags.merge(Tags.stringify_keys(tags))
180
180
  end
181
181
  end
182
182
  tags = Tags.expand_runtime_values(tags)
@@ -203,7 +203,7 @@ module Lumberjack
203
203
  add_entry(severity, message, progname)
204
204
  end
205
205
 
206
- alias_method :log, :add
206
+ alias log add
207
207
 
208
208
  # Flush the logging device. Messages are not guaranteed to be written until this method is called.
209
209
  def flush
@@ -238,6 +238,11 @@ module Lumberjack
238
238
  level <= FATAL
239
239
  end
240
240
 
241
+ # Set the log level to fatal.
242
+ def fatal!
243
+ self.level = FATAL
244
+ end
245
+
241
246
  # Log an +ERROR+ message. The message can be passed in either the +message+ argument or in a block.
242
247
  def error(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
243
248
  call_add_entry(ERROR, message_or_progname_or_tags, progname_or_tags, &block)
@@ -248,6 +253,11 @@ module Lumberjack
248
253
  level <= ERROR
249
254
  end
250
255
 
256
+ # Set the log level to error.
257
+ def error!
258
+ self.level = ERROR
259
+ end
260
+
251
261
  # Log a +WARN+ message. The message can be passed in either the +message+ argument or in a block.
252
262
  def warn(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
253
263
  call_add_entry(WARN, message_or_progname_or_tags, progname_or_tags, &block)
@@ -258,6 +268,11 @@ module Lumberjack
258
268
  level <= WARN
259
269
  end
260
270
 
271
+ # Set the log level to warn.
272
+ def warn!
273
+ self.level = WARN
274
+ end
275
+
261
276
  # Log an +INFO+ message. The message can be passed in either the +message+ argument or in a block.
262
277
  def info(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
263
278
  call_add_entry(INFO, message_or_progname_or_tags, progname_or_tags, &block)
@@ -268,6 +283,11 @@ module Lumberjack
268
283
  level <= INFO
269
284
  end
270
285
 
286
+ # Set the log level to info.
287
+ def info!
288
+ self.level = INFO
289
+ end
290
+
271
291
  # Log a +DEBUG+ message. The message can be passed in either the +message+ argument or in a block.
272
292
  def debug(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
273
293
  call_add_entry(DEBUG, message_or_progname_or_tags, progname_or_tags, &block)
@@ -278,6 +298,11 @@ module Lumberjack
278
298
  level <= DEBUG
279
299
  end
280
300
 
301
+ # Set the log level to debug.
302
+ def debug!
303
+ self.level = DEBUG
304
+ end
305
+
281
306
  # Log a message when the severity is not known. Unknown messages will always appear in the log.
282
307
  # The message can be passed in either the +message+ argument or in a block.
283
308
  def unknown(message_or_progname_or_tags = nil, progname_or_tags = nil, &block)
@@ -300,7 +325,7 @@ module Lumberjack
300
325
  def silence(temporary_level = ERROR, &block)
301
326
  if silencer
302
327
  unless temporary_level.is_a?(Integer)
303
- temporary_level = Severity::label_to_level(temporary_level)
328
+ temporary_level = Severity.label_to_level(temporary_level)
304
329
  end
305
330
  push_thread_local_value(:lumberjack_logger_level, temporary_level, &block)
306
331
  else
@@ -324,30 +349,67 @@ module Lumberjack
324
349
  end
325
350
 
326
351
  # Set a hash of tags on logger. If a block is given, the tags will only be set
327
- # for the duration of the block.
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.
328
356
  def tag(tags, &block)
329
357
  tags = Tags.stringify_keys(tags)
358
+ thread_tags = thread_local_value(:lumberjack_logger_tags)
330
359
  if block
331
- thread_tags = thread_local_value(:lumberjack_logger_tags)
332
- value = (thread_tags ? thread_tags.merge(tags) : tags)
333
- push_thread_local_value(:lumberjack_logger_tags, value, &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
334
365
  else
335
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) }
336
380
  end
337
381
  end
338
382
 
339
383
  # Return all tags in scope on the logger including global tags set on the Lumberjack
340
- # context, tags set on the logger, and tags set on the current block for the logger
384
+ # context, tags set on the logger, and tags set on the current block for the logger.
341
385
  def tags
342
386
  tags = {}
343
387
  context_tags = Lumberjack.context_tags
344
388
  tags.merge!(context_tags) if context_tags && !context_tags.empty?
345
- tags.merge!(@tags) if !@tags.empty?
389
+ tags.merge!(@tags) if !@tags.empty? && !thread_local_value(:lumberjack_logger_untagged)
346
390
  scope_tags = thread_local_value(:lumberjack_logger_tags)
347
391
  tags.merge!(scope_tags) if scope_tags && !scope_tags.empty?
348
392
  tags
349
393
  end
350
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
+
351
413
  private
352
414
 
353
415
  # Dereference arguments to log calls so we can have methods with compatibility with ::Logger
@@ -430,12 +492,12 @@ module Lumberjack
430
492
  end
431
493
 
432
494
  def write_to_device(entry) #:nodoc:
433
- begin
434
- device.write(entry)
435
- rescue => e
436
- $stderr.puts("#{e.class.name}: #{e.message}#{' at ' + e.backtrace.first if e.backtrace}")
437
- $stderr.puts(entry.to_s)
438
- end
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
439
501
  end
440
502
 
441
503
  # Create a thread that will periodically call flush.
@@ -444,12 +506,12 @@ module Lumberjack
444
506
  begin
445
507
  logger = self
446
508
  Thread.new do
447
- while !closed?
509
+ until closed?
448
510
  begin
449
511
  sleep(flush_seconds)
450
512
  logger.flush if Time.now - logger.last_flushed_at >= flush_seconds
451
513
  rescue => e
452
- STDERR.puts("Error flushing log: #{e.inspect}")
514
+ warn("Error flushing log: #{e.inspect}")
453
515
  end
454
516
  end
455
517
  end