logging 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d4abf77abb948de12d0e860a18be03b9b2314bd
4
- data.tar.gz: f3bb7dc5daf79b192d56de6d2a96d217bebbe24b
3
+ metadata.gz: e350554eb562c0d216fa262c015afb4c2a68b82e
4
+ data.tar.gz: 22820d111096e8c44e7d0908e1cb7cca27d49009
5
5
  SHA512:
6
- metadata.gz: 31e6820636ea493830b4b880c112aa57a53fc4e283da0682b5dfbdb373d3040017889153e50f625525eb6e0e7e4d7e2752fd6fd60c8acbc909d249762b2fd879
7
- data.tar.gz: c55a5532bcc8e6c8543f231484a11cb9f65a747afe231f58709fc13274962e6318a05a3e76d09b12c1793bc346cd87eca759e0eefa2185af1ea38d2caf554ab9
6
+ metadata.gz: d8167665ad0871c41f053154f7d36686afd08d15d151a3d8c759a20ab9d845060494ed580fe6c95eeddccea69c57a6d94d464f6f3c463ed126b61c8021d05ac9
7
+ data.tar.gz: e741f1bea9ca11f52a06ca5b2873007430f26b02d92262222b2e64a86ae0de9635c2482b57e40c0b512d6a180486d665b9e36196a39d418311437a855e0d5a7c
@@ -10,4 +10,5 @@ rvm:
10
10
  - 2.0.0
11
11
  - 2.1.5
12
12
  - 2.2.1
13
-
13
+ - 2.3.0
14
+ - jruby-9.0.4.0
@@ -1,3 +1,22 @@
1
+ == 2.1.0 / 2016-03-13
2
+
3
+ Enhancements
4
+ - appender factories now fail explicitly on bad arguments [PR #117]
5
+ - console loggers (stdout, stderr) use `write` for compatibility [PR #127]
6
+ - allow whitespace in traced method names [PR #128]
7
+ - accessor methods for `backtrace` settings [PR #134]
8
+ - asynchronous writing from buffered appenders [PR #135]
9
+ - improve date format performance when outputting microseconds [PR #136]
10
+ - added some thread safety to log level setters [PR #137]
11
+ - use `write` everywhere instead of `syswrite` [PR #138]
12
+
13
+ Bug Fixes
14
+ - fixing encodings in tests [PR #116]
15
+ - fix Rails4 logger compatibility [PR #121]
16
+ - explicitly adding the MIT license [PR #123]
17
+ - update `object_id` format in inspect methods [PR #133]
18
+ - fixed Travis-CI tests
19
+
1
20
  == 2.0.0 / 2015-03-28
2
21
 
3
22
  Enhancements
data/Rakefile CHANGED
@@ -28,7 +28,7 @@ Bones {
28
28
  depend_on 'little-plugger', '~> 1.1'
29
29
  depend_on 'multi_json', '~> 1.10'
30
30
 
31
- depend_on 'flexmock', '~> 1.0', :development => true
31
+ depend_on 'test-unit', '~> 3.1', :development => true
32
32
  depend_on 'bones-git', '~> 1.3', :development => true
33
33
  #depend_on 'bones-rcov', :development => true
34
34
  }
@@ -0,0 +1,21 @@
1
+ # :stopdoc:
2
+ #
3
+ # Rails 4 allows you to hook up multiple loggers (even those external to this gem)
4
+ # so you can use a single Rails.logger statement. For Rails developers, this is
5
+ # easier because if you ever change logging frameworks, you don't have to change
6
+ # all of your app code.
7
+ #
8
+ # See http://railsware.com/blog/2014/08/07/rails-logging-into-several-backends/
9
+ #
10
+
11
+ require 'logging'
12
+
13
+ log = Logging.logger(STDOUT)
14
+ log.level = :warn
15
+
16
+ Rails.logger.extend(ActiveSupport::Logger.broadcast(log))
17
+
18
+ Rails.logger.debug "this debug message will not be output by the logger"
19
+ Rails.logger.warn "this is your last warning"
20
+
21
+ # :startdoc:
@@ -251,17 +251,16 @@ class Appender
251
251
  self
252
252
  end
253
253
 
254
+ # Save off the original `to_s` for use in tests
255
+ alias_method :_to_s, :to_s
256
+
254
257
  # call-seq:
255
- # inspect => string
258
+ # to_s => string
256
259
  #
257
260
  # Returns a string representation of the appender.
258
261
  #
259
- def inspect
260
- "<%s:0x%x name=\"%s\">" % [
261
- self.class.name.sub(%r/^Logging::/, ''),
262
- self.object_id,
263
- self.name
264
- ]
262
+ def to_s
263
+ "<%s name=\"%s\">" % [self.class.name.sub(%r/^Logging::/, ''), self.name]
265
264
  end
266
265
 
267
266
  # Returns the current Encoding for the appender or nil if an encoding has
@@ -27,6 +27,10 @@ module Logging::Appenders
27
27
  # flush_period.
28
28
  attr_reader :flush_period
29
29
 
30
+ # When set, the buffer will be flushed using an asynchronous Thread. That
31
+ # is, the main program thread will not be blocked during writes.
32
+ attr_reader :async
33
+
30
34
  # Messages will be written in chunks. This controls the number of messages
31
35
  # to pull from the buffer for each write operation. The default is to pull
32
36
  # all messages from the buffer at once.
@@ -39,20 +43,21 @@ module Logging::Appenders
39
43
  @buffer = []
40
44
  @immediate = []
41
45
  @auto_flushing = 1
42
- @flush_period = @periodic_flusher = nil
46
+ @async = false
47
+ @flush_period = @async_flusher = nil
43
48
 
44
49
  super(*args, &block)
45
50
  end
46
51
 
47
- # Close the message buffer by flushing all log events to the appender. If a
48
- # periodic flusher thread is running, shut it down and allow it to exit.
52
+ # Close the message buffer by flushing all log events to the appender. If an
53
+ # async flusher thread is running, shut it down and allow it to exit.
49
54
  #
50
55
  def close( *args )
51
56
  flush
52
57
 
53
- if @periodic_flusher
54
- @periodic_flusher.stop
55
- @periodic_flusher = nil
58
+ if @async_flusher
59
+ @async_flusher.stop
60
+ @async_flusher = nil
56
61
  Thread.pass
57
62
  end
58
63
 
@@ -60,11 +65,11 @@ module Logging::Appenders
60
65
  end
61
66
 
62
67
  # Reopen the connection to the underlying logging destination. In addition
63
- # if the appender is configured for periodic flushing, then the flushing
68
+ # if the appender is configured for asynchronous flushing, then the flushing
64
69
  # thread will be stopped and restarted.
65
70
  #
66
71
  def reopen
67
- _setup_periodic_flusher
72
+ _setup_async_flusher
68
73
  super
69
74
  end
70
75
 
@@ -194,21 +199,43 @@ module Logging::Appenders
194
199
  # manually if so desired.
195
200
  #
196
201
  def flush_period=( period )
197
- period =
202
+ @flush_period =
198
203
  case period
199
204
  when Integer, Float, nil; period
200
- when String;
205
+ when String
201
206
  num = _parse_hours_minutes_seconds(period) || _parse_numeric(period)
202
- num = ArgumentError.new("unrecognized flush period: #{period.inspect}") if num.nil?
207
+ raise ArgumentError.new("unrecognized flush period: #{period.inspect}") if num.nil?
203
208
  num
204
- else ArgumentError.new("unrecognized flush period: #{period.inspect}") end
209
+ else
210
+ raise ArgumentError.new("unrecognized flush period: #{period.inspect}")
211
+ end
205
212
 
206
- raise period if Exception === period
207
- @flush_period = period
213
+ if !@flush_period.nil? && @flush_period <= 0
214
+ raise ArgumentError,
215
+ "flush_period must be greater than zero: #{period.inspect}"
216
+ end
208
217
 
209
- _setup_periodic_flusher
218
+ _setup_async_flusher
210
219
  end
211
220
 
221
+ # Returns `true` if an asynchronous flush period has been defined for the
222
+ # appender.
223
+ def flush_period?
224
+ !@flush_period.nil?
225
+ end
226
+
227
+ # Enable or disable asynchronous logging via a dedicated logging Thread.
228
+ # Pass in `true` to enable and `false` to disable.
229
+ #
230
+ # bool - A boolean value
231
+ #
232
+ def async=( bool )
233
+ @async = bool ? true : false
234
+ _setup_async_flusher
235
+ end
236
+
237
+ alias_method :async?, :async
238
+
212
239
  protected
213
240
 
214
241
  # Configure the buffering using the arguments found in the give options
@@ -223,12 +250,12 @@ module Logging::Appenders
223
250
  self.immediate_at = opts.fetch(:immediate_at, '')
224
251
  self.auto_flushing = opts.fetch(:auto_flushing, true)
225
252
  self.flush_period = opts.fetch(:flush_period, nil)
253
+ self.async = opts.fetch(:async, false)
226
254
  self.write_size = opts.fetch(:write_size, DEFAULT_BUFFER_SIZE)
227
255
  end
228
256
 
229
- # Returns true if the _event_ level matches one of the configured
230
- # immediate logging levels. Otherwise returns false.
231
- #
257
+ # Returns `true` if the `event` level matches one of the configured
258
+ # immediate logging levels. Otherwise returns `false`.
232
259
  def immediate?( event )
233
260
  return false unless event.respond_to? :level
234
261
  @immediate[event.level]
@@ -240,14 +267,15 @@ module Logging::Appenders
240
267
  # call-seq:
241
268
  # write( event )
242
269
  #
243
- # Writes the given _event_ to the logging destination. The _event_ can
270
+ # Writes the given `event` to the logging destination. The `event` can
244
271
  # be either a LogEvent or a String. If a LogEvent, then it will be
245
272
  # formatted using the layout given to the appender when it was created.
246
273
  #
247
- # The _event_ will be formatted and then buffered until the
274
+ # The `event` will be formatted and then buffered until the
248
275
  # "auto_flushing" level has been reached. At this time the canonical_write
249
276
  # method will be used to log all events stored in the buffer.
250
277
  #
278
+ # Returns this appender instance
251
279
  def write( event )
252
280
  str = event.instance_of?(::Logging::LogEvent) ?
253
281
  layout.format(event) : event.to_s
@@ -256,12 +284,21 @@ module Logging::Appenders
256
284
  if @auto_flushing == 1
257
285
  canonical_write(str)
258
286
  else
287
+ str = str.force_encoding(encoding) if encoding && str.encoding != encoding
259
288
  sync {
260
- str = str.force_encoding(encoding) if encoding && str.encoding != encoding
261
289
  @buffer << str
262
290
  }
263
- @periodic_flusher.signal if @periodic_flusher
264
- flush if @buffer.length >= @auto_flushing || immediate?(event)
291
+ flush_now = @buffer.length >= @auto_flushing || immediate?(event)
292
+
293
+ if flush_now
294
+ if async?
295
+ @async_flusher.signal(flush_now)
296
+ else
297
+ self.flush
298
+ end
299
+ elsif @async_flusher && flush_period?
300
+ @async_flusher.signal
301
+ end
265
302
  end
266
303
 
267
304
  self
@@ -270,9 +307,14 @@ module Logging::Appenders
270
307
  # Attempt to parse an hours/minutes/seconds value from the string and return
271
308
  # an integer number of seconds.
272
309
  #
310
+ # str - The input String to parse for time values.
311
+ #
312
+ # Examples
313
+ #
273
314
  # _parse_hours_minutes_seconds("14:12:42") #=> 51162
274
315
  # _parse_hours_minutes_seconds("foo") #=> nil
275
316
  #
317
+ # Returns a Numeric or `nil`
276
318
  def _parse_hours_minutes_seconds( str )
277
319
  m = %r/^\s*(\d{2,}):(\d{2}):(\d{2}(?:\.\d+)?)\s*$/.match(str)
278
320
  return if m.nil?
@@ -281,49 +323,60 @@ module Logging::Appenders
281
323
  end
282
324
 
283
325
  # Convert the string into a numeric value. If the string does not
284
- # represent a valid Integer or Float then +nil+ is returned.
326
+ # represent a valid Integer or Float then `nil` is returned.
327
+ #
328
+ # str - The input String to parse for Numeric values.
329
+ #
330
+ # Examples
285
331
  #
286
332
  # _parse_numeric("10") #=> 10
287
333
  # _parse_numeric("1.0") #=> 1.0
288
334
  # _parse_numeric("foo") #=> nil
289
335
  #
336
+ # Returns a Numeric or `nil`
290
337
  def _parse_numeric( str )
291
338
  Integer(str) rescue (Float(str) rescue nil)
292
339
  end
293
340
 
294
- # Using the flush_period, create a new PeriodicFlusher attached to this
341
+ # Using the flush_period, create a new AsyncFlusher attached to this
295
342
  # appender. If the flush_period is nil, then no action will be taken. If a
296
- # PeriodicFlusher already exists, it will be stopped and a new one will be
343
+ # AsyncFlusher already exists, it will be stopped and a new one will be
297
344
  # created.
298
345
  #
299
- def _setup_periodic_flusher
300
- # stop and remove any existing periodic flusher instance
301
- if @periodic_flusher
302
- @periodic_flusher.stop
303
- @periodic_flusher = nil
346
+ # Returns `nil`
347
+ def _setup_async_flusher
348
+ # stop and remove any existing async flusher instance
349
+ if @async_flusher
350
+ @async_flusher.stop
351
+ @async_flusher = nil
304
352
  Thread.pass
305
353
  end
306
354
 
307
- # create a new periodic flusher if we have a valid flush period
308
- if @flush_period
355
+ # create a new async flusher if we have a valid flush period
356
+ if @flush_period || async?
309
357
  @auto_flushing = DEFAULT_BUFFER_SIZE unless @auto_flushing > 1
310
- @periodic_flusher = PeriodicFlusher.new(self, @flush_period)
311
- @periodic_flusher.start
358
+ @async_flusher = AsyncFlusher.new(self, @flush_period)
359
+ @async_flusher.start
360
+ Thread.pass
312
361
  end
362
+
363
+ nil
313
364
  end
314
365
 
315
366
  # :stopdoc:
316
367
 
317
- # The PeriodicFlusher contains an internal run loop that will periodically
368
+ # The AsyncFlusher contains an internal run loop that will periodically
318
369
  # wake up and flush any log events contained in the message buffer of the
319
- # owning appender instance. The PeriodicFlusher relies on a _signal_ from
370
+ # owning appender instance. The AsyncFlusher relies on a `signal` from
320
371
  # the appender in order to wakeup and perform the flush on the appender.
321
- #
322
- class PeriodicFlusher
372
+ class AsyncFlusher
323
373
 
324
- # Create a new PeriodicFlusher instance that will call the +flush+
325
- # method on the given _appender_. The +flush+ method will be called
326
- # every _period_ seconds, but only when the message buffer is non-empty.
374
+ # Create a new AsyncFlusher instance that will call the `flush`
375
+ # method on the given `appender`. The `flush` method will be called
376
+ # every `period` seconds, but only when the message buffer is non-empty.
377
+ #
378
+ # appender - The Appender instance to periodically `flush`
379
+ # period - The Numeric sleep period or `nil`
327
380
  #
328
381
  def initialize( appender, period )
329
382
  @appender = appender
@@ -334,10 +387,12 @@ module Logging::Appenders
334
387
  @thread = nil
335
388
  @waiting = nil
336
389
  @signaled = false
390
+ @immediate = 0
337
391
  end
338
392
 
339
393
  # Start the periodic flusher's internal run loop.
340
394
  #
395
+ # Returns this flusher instance
341
396
  def start
342
397
  return if @thread
343
398
 
@@ -345,57 +400,75 @@ module Logging::Appenders
345
400
  begin
346
401
  break if Thread.current[:stop]
347
402
  _wait_for_signal
348
- sleep @period unless Thread.current[:stop]
403
+ _try_to_sleep
349
404
  @appender.flush
350
405
  rescue => err
351
- ::Logging.log_internal {"PeriodicFlusher for appender #{@appender.inspect} encountered an error"}
406
+ ::Logging.log_internal {"AsyncFlusher for appender #{@appender.inspect} encountered an error"}
352
407
  ::Logging.log_internal_error(err)
353
408
  end
354
- }; @thread = nil }
409
+ }}
355
410
 
356
411
  self
357
412
  end
358
413
 
359
- # Stop the periodic flusher's internal run loop.
414
+ # Stop the async flusher's internal run loop.
360
415
  #
416
+ # Returns this flusher instance
361
417
  def stop
362
418
  return if @thread.nil?
363
419
  @thread[:stop] = true
364
420
  signal if waiting?
421
+ @thread = nil
365
422
  self
366
423
  end
367
424
 
368
- # Signal the periodic flusher. This will wake up the run loop if it is
425
+ # Signal the async flusher. This will wake up the run loop if it is
369
426
  # currently waiting for something to do. If the signal method is never
370
- # called, the periodic flusher will never perform the flush action on
427
+ # called, the async flusher will never perform the flush action on
371
428
  # the appender.
372
429
  #
373
- def signal
430
+ # immediate - Set to `true` if the sleep period should be skipped
431
+ #
432
+ # Returns this flusher instance
433
+ def signal( immediate = nil )
374
434
  return if Thread.current == @thread # don't signal ourselves
375
435
  return if @signaled # don't need to signal again
376
436
 
377
437
  @mutex.synchronize {
378
438
  @signaled = true
439
+ @immediate += 1 if immediate
379
440
  @cv.signal
380
441
  }
381
442
  self
382
443
  end
383
444
 
384
- # Returns +true+ if the flusher is waiting for a signal. Returns +false+
445
+ # Returns `true` if the flusher is waiting for a signal. Returns `false`
385
446
  # if the flusher is somewhere in the processing loop.
386
- #
387
447
  def waiting?
388
448
  @waiting
389
449
  end
390
450
 
451
+ # Returns `true` if the flusher should immeidately write the buffer to the
452
+ # IO destination.
453
+ def immediate?
454
+ @immediate > 0
455
+ end
456
+
391
457
  private
392
458
 
459
+ def _try_to_sleep
460
+ return if Thread.current[:stop]
461
+ return if immediate?
462
+ sleep @period unless @period.nil?
463
+ end
464
+
393
465
  def _wait_for_signal
394
466
  @mutex.synchronize {
395
467
  begin
396
468
  # wait on the condition variable only if we have NOT been signaled
397
469
  unless @signaled
398
470
  @waiting = true
471
+ @immediate -= 1 if immediate?
399
472
  @cv.wait(@mutex)
400
473
  @waiting = false
401
474
  end
@@ -406,9 +479,7 @@ module Logging::Appenders
406
479
  ensure
407
480
  @waiting = false
408
481
  end
409
- end # class PeriodicFlusher
482
+ end
410
483
  # :startdoc:
411
-
412
- end # Buffering
413
- end # Logging::Appenders
414
-
484
+ end
485
+ end