logging 2.2.2 → 2.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: bb433e2db44c13bc4956095561ad2ad34cd4fabf
4
- data.tar.gz: 6d6a401267834a2b1dad3c5992bb4c4c28ea05a0
2
+ SHA256:
3
+ metadata.gz: 1ec479cf977c621a6b42426cfe7c478a97e106c23762f3608ee67fcbaa49b324
4
+ data.tar.gz: 6a0c0107cf3c1a1f7504e19e85a9505ad94c4a84991d01eb6c65191257a01163
5
5
  SHA512:
6
- metadata.gz: 44ad1070f56d8618f9e6c118876364f70442723424d055716928e422a6699a40e744c68a86619227ed8fd5eea26e6c1fd6850f50877c74769a5160d6133b5140
7
- data.tar.gz: bf24fb750a15937f18d75b2acc738e323a8ea718661bb9877ea64b0d23eea12def864c3175e71cd1f9b7ccff69c44d661455ff3526e5c192cc0f67c026a77a7f
6
+ metadata.gz: 2cd72dabcd8b878b73f69ec8a445678b14635ca1c115576ef148a7160673f83939d7706e5d673c32ed11ef2c48046cc7a50bd2c2c0795b2fa79c35e9d4bccf87
7
+ data.tar.gz: 23422872b58d1bd0e0a146f64e4bb792ef5208da309b16e7650d5c74ca9969b12e6e65dd5ef79a90ce39e0d6c51dbc7514f7a2e913ec74b2e8404a06aefa8975
data/.gitignore CHANGED
@@ -12,3 +12,4 @@ tmp/
12
12
  vendor/
13
13
  .rbx
14
14
  .rvmrc
15
+ .tool-versions
@@ -9,6 +9,8 @@ rvm:
9
9
  - 2.0.0-p648
10
10
  - 2.1.10
11
11
  - 2.2.7
12
- - 2.3.4
13
- - 2.4.1
14
- - jruby-9.1.8.0
12
+ - 2.3.8
13
+ - 2.4.9
14
+ - 2.5.7
15
+ - 2.6.5
16
+ - jruby-9.2.9.0
@@ -1,3 +1,18 @@
1
+ == 2.3.0 / 2020-07-04
2
+
3
+ Enhancements
4
+ - all appender output is now synchronized [PR #219]
5
+ - renamed the `LogEvent#method` to no longer conflict with `Kernel#method` [PR #218]
6
+ - @bhuga (not the Fortnite star) added a `raise_errors` method for debugging [PR #203]
7
+ - thanks to @olleolleolle for keeping on top of Travis and Ruby versions
8
+
9
+ Bug Fixes
10
+ - conosle appenders can be reopened [PR #220]
11
+ - fixed a race condition in the rolling file appender [PR #216]
12
+ - fixed a race condition when opening log file destinations [PR #208 #217]
13
+ - @MikaelSmith fixed a race condition in Logger creation [PR #201]
14
+ - documentation bug fixes [PR #184 #185 #188 #194 #209]
15
+
1
16
  == 2.2.2 / 2017-04-11
2
17
 
3
18
  Enhancements
data/Rakefile CHANGED
@@ -26,9 +26,9 @@ Bones {
26
26
  use_gmail
27
27
 
28
28
  depend_on 'little-plugger', '~> 1.1'
29
- depend_on 'multi_json', '~> 1.10'
29
+ depend_on 'multi_json', '~> 1.14'
30
30
 
31
- depend_on 'test-unit', '~> 3.1', :development => true
31
+ depend_on 'test-unit', '~> 3.3', :development => true
32
32
  depend_on 'bones-git', '~> 1.3', :development => true
33
33
  #depend_on 'bones-rcov', :development => true
34
34
  }
@@ -1,7 +1,7 @@
1
1
  # :stopdoc:
2
2
  #
3
3
  # Appenders are used to output log events to some logging destination. The
4
- # same log event can be sent to multiple desitnations by associating
4
+ # same log event can be sent to multiple destinations by associating
5
5
  # multiple appenders with the logger.
6
6
  #
7
7
  # The following is a list of all the available appenders and a brief
@@ -29,9 +29,9 @@
29
29
  Logging.mdc['first'] = 'John'
30
30
  Logging.mdc['last'] = 'Doe'
31
31
 
32
- # in this first thread we will log some quotes by Allan Rickman
32
+ # in this first thread we will log some quotes by Alan Rickman
33
33
  t1 = Thread.new {
34
- Logging.mdc['first'] = 'Allan'
34
+ Logging.mdc['first'] = 'Alan'
35
35
  Logging.mdc['last'] = 'Rickman'
36
36
 
37
37
  [ %q{I've never been able to plan my life. I just lurch from indecision to indecision.},
@@ -258,6 +258,7 @@ module Logging
258
258
  module_eval "MAX_LEVEL_LENGTH = #{longest.length}", __FILE__, __LINE__
259
259
 
260
260
  self.cause_depth = nil unless defined? @cause_depth
261
+ self.raise_errors = false unless defined? @raise_errors
261
262
 
262
263
  initialize_plugins
263
264
  levels.keys
@@ -268,8 +269,8 @@ module Logging
268
269
  #
269
270
  # Defines the default _obj_format_ method to use when converting objects
270
271
  # into string representations for logging. _obj_format_ can be one of
271
- # <tt>:string</tt>, <tt>:inspect</tt>, or <tt>:yaml</tt>. These
272
- # formatting commands map to the following object methods
272
+ # <tt>:string</tt>, <tt>:inspect</tt>, <tt>:json</tt> or <tt>:yaml</tt>.
273
+ # These formatting commands map to the following object methods
273
274
  #
274
275
  # * :string => to_s
275
276
  # * :inspect => inspect
@@ -277,7 +278,7 @@ module Logging
277
278
  # * :json => MultiJson.encode(obj)
278
279
  #
279
280
  # An +ArgumentError+ is raised if anything other than +:string+,
280
- # +:inspect+, +:yaml+ is passed to this method.
281
+ # +:inspect+, +:json+ or +:yaml+ is passed to this method.
281
282
  #
282
283
  def format_as( f )
283
284
  f = f.intern if f.instance_of? String
@@ -490,6 +491,21 @@ module Logging
490
491
  io
491
492
  end
492
493
 
494
+ # Raise an exception when an error is encountered while logging, be it with
495
+ # a backing store, formatter, or anything else. You probably wouldn't want
496
+ # to enable this outside of test.
497
+ #
498
+ # Not that only one error will ever be raised per logging backend, as
499
+ # backends that raise errors on write will be set to :off.
500
+ def raise_errors=(boolean)
501
+ @raise_errors = boolean
502
+ end
503
+
504
+ # Whether or not we should raise errors when writing logs.
505
+ def raise_errors?
506
+ @raise_errors
507
+ end
508
+
493
509
  # :stopdoc:
494
510
  # Convert the given level into a canonical form - a lowercase string.
495
511
  def levelify( level )
@@ -518,7 +534,7 @@ module Logging
518
534
  # exception will be raised again.
519
535
  def log_internal_error( err )
520
536
  log_internal(-2) { err }
521
- raise err if Thread.abort_on_exception
537
+ raise err if ::Logging.raise_errors?
522
538
  end
523
539
 
524
540
  # Close all appenders
@@ -569,8 +585,7 @@ module Logging
569
585
  require libpath('logging/diagnostic_context')
570
586
 
571
587
  require libpath('logging/rails_compat')
572
- end # module Logging
573
-
588
+ end
574
589
 
575
590
  # This finalizer will close all the appenders that exist in the system.
576
591
  # This is needed for closing IO streams and connections to the syslog server
@@ -9,11 +9,6 @@ module Logging
9
9
  # Each subclass should provide a +write+ method that will write log
10
10
  # messages to the logging destination.
11
11
  #
12
- # A private +sync+ method is provided for use by subclasses. It is used to
13
- # synchronize writes to the logging destination, and can be used by
14
- # subclasses to synchronize the closing or flushing of the logging
15
- # destination.
16
- #
17
12
  class Appender
18
13
 
19
14
  attr_reader :name, :layout, :level, :filters
@@ -263,13 +258,9 @@ class Appender
263
258
  "<%s name=\"%s\">" % [self.class.name.sub(%r/^Logging::/, ''), self.name]
264
259
  end
265
260
 
266
- # Returns the current Encoding for the appender or nil if an encoding has
267
- # not been set.
268
- #
269
- def encoding
270
- return @encoding if defined? @encoding
271
- @encoding = Object.const_defined?(:Encoding) ? Encoding.default_external : nil
272
- end
261
+ # Returns the current Encoding for the appender. The default external econding
262
+ # will be used if none is explicitly set.
263
+ attr_reader :encoding
273
264
 
274
265
  # Set the appender encoding to the given value. The value can either be an
275
266
  # Encoding instance or a String or Symbol referring to a valid encoding.
@@ -282,9 +273,9 @@ class Appender
282
273
  # Raises ArgumentError if the value is not a valid encoding.
283
274
  def encoding=( value )
284
275
  if value.nil?
285
- @encoding = nil
276
+ @encoding = Encoding.default_external
286
277
  else
287
- @encoding = Object.const_defined?(:Encoding) ? Encoding.find(value.to_s) : nil
278
+ @encoding = Encoding.find(value.to_s)
288
279
  end
289
280
  end
290
281
 
@@ -328,17 +319,6 @@ private
328
319
  nil
329
320
  end
330
321
 
331
- # call-seq:
332
- # sync { block }
333
- #
334
- # Obtains an exclusive lock, runs the block, and releases the lock when
335
- # the block completes. This method is re-entrant so that a single thread
336
- # can call +sync+ multiple times without hanging the thread.
337
- #
338
- def sync( &block )
339
- @mutex.synchronize(&block)
340
- end
341
-
342
322
  end # class Appender
343
323
  end # module Logging
344
324
 
@@ -79,7 +79,7 @@ module Logging::Appenders
79
79
  return self if @buffer.empty?
80
80
 
81
81
  ary = nil
82
- sync {
82
+ @mutex.synchronize {
83
83
  ary = @buffer.dup
84
84
  @buffer.clear
85
85
  }
@@ -100,7 +100,7 @@ module Logging::Appenders
100
100
  # Clear the underlying buffer of all log events. These events will not be
101
101
  # appended to the logging destination; they will be lost.
102
102
  def clear!
103
- sync { @buffer.clear }
103
+ @mutex.synchronize { @buffer.clear }
104
104
  end
105
105
 
106
106
  # Configure the levels that will trigger an immediate flush of the
@@ -285,7 +285,7 @@ module Logging::Appenders
285
285
  canonical_write(str)
286
286
  else
287
287
  str = str.force_encoding(encoding) if encoding && str.encoding != encoding
288
- sync {
288
+ @mutex.synchronize {
289
289
  @buffer << str
290
290
  }
291
291
  flush_now = @buffer.length >= @auto_flushing || immediate?(event)
@@ -22,17 +22,49 @@ module Logging::Appenders
22
22
  #
23
23
  def initialize( *args )
24
24
  name = self.class.name.split("::").last.downcase
25
- io = Object.const_get(name.upcase)
26
25
 
27
26
  opts = args.last.is_a?(Hash) ? args.pop : {}
28
27
  name = args.shift unless args.empty?
29
28
 
30
- opts[:encoding] = io.external_encoding if io.respond_to? :external_encoding
29
+ io = open_fd
30
+ opts[:encoding] = io.external_encoding
31
31
 
32
32
  super(name, io, opts)
33
- rescue NameError
34
- raise RuntimeError, "Please do not use the `Logging::Appenders::Console` class directly - " +
35
- "use `Logging::Appenders::Stdout` and `Logging::Appenders::Stderr` instead"
33
+ end
34
+
35
+ # Reopen the connection to the underlying logging destination. If the
36
+ # connection is currently closed then it will be opened. If the connection
37
+ # is currently open then it will be closed and immediately reopened.
38
+ def reopen
39
+ @mutex.synchronize {
40
+ if defined? @io && @io
41
+ flush
42
+ @io.close rescue nil
43
+ end
44
+ @io = open_fd
45
+ }
46
+ super
47
+ self
48
+ end
49
+
50
+ private
51
+
52
+ def open_fd
53
+ case self.class.name
54
+ when "Logging::Appenders::Stdout"
55
+ fd = STDOUT.fileno
56
+ encoding = STDOUT.external_encoding
57
+ when "Logging::Appenders::Stderr"
58
+ fd = STDERR.fileno
59
+ encoding = STDERR.external_encoding
60
+ else
61
+ raise RuntimeError, "Please do not use the `Logging::Appenders::Console` class directly - " +
62
+ "use `Logging::Appenders::Stdout` and `Logging::Appenders::Stderr` instead" +
63
+ " [class #{self.class.name}]"
64
+ end
65
+
66
+ mode = ::File::WRONLY | ::File::APPEND
67
+ ::IO.for_fd(fd, mode: mode, encoding: encoding)
36
68
  end
37
69
  end
38
70
 
@@ -43,7 +75,6 @@ module Logging::Appenders
43
75
  Stderr = Class.new(Console)
44
76
 
45
77
  # Accessor / Factory for the Stdout appender.
46
- #
47
78
  def self.stdout( *args )
48
79
  if args.empty?
49
80
  return self['stdout'] || ::Logging::Appenders::Stdout.new
@@ -52,7 +83,6 @@ module Logging::Appenders
52
83
  end
53
84
 
54
85
  # Accessor / Factory for the Stderr appender.
55
- #
56
86
  def self.stderr( *args )
57
87
  if args.empty?
58
88
  return self['stderr'] || ::Logging::Appenders::Stderr.new
@@ -2,14 +2,12 @@
2
2
  module Logging::Appenders
3
3
 
4
4
  # Accessor / Factory for the File appender.
5
- #
6
5
  def self.file( *args )
7
6
  fail ArgumentError, '::Logging::Appenders::File needs a name as first argument.' if args.empty?
8
7
  ::Logging::Appenders::File.new(*args)
9
8
  end
10
9
 
11
10
  # This class provides an Appender that can write to a File.
12
- #
13
11
  class File < ::Logging::Appenders::IO
14
12
 
15
13
  # call-seq:
@@ -21,15 +19,14 @@ module Logging::Appenders
21
19
  # writable.
22
20
  #
23
21
  # An +ArgumentError+ is raised if any of these assertions fail.
24
- #
25
22
  def self.assert_valid_logfile( fn )
26
23
  if ::File.exist?(fn)
27
- if not ::File.file?(fn)
24
+ if !::File.file?(fn)
28
25
  raise ArgumentError, "#{fn} is not a regular file"
29
- elsif not ::File.writable?(fn)
26
+ elsif !::File.writable?(fn)
30
27
  raise ArgumentError, "#{fn} is not writeable"
31
28
  end
32
- elsif not ::File.writable?(::File.dirname(fn))
29
+ elsif !::File.writable?(::File.dirname(fn))
33
30
  raise ArgumentError, "#{::File.dirname(fn)} is not writable"
34
31
  end
35
32
  true
@@ -45,41 +42,65 @@ module Logging::Appenders
45
42
  # created. If the :truncate option is set to +true+ then the file will
46
43
  # be truncated before writing begins; otherwise, log messages will be
47
44
  # appended to the file.
48
- #
49
45
  def initialize( name, opts = {} )
50
- @fn = opts.fetch(:filename, name)
51
- raise ArgumentError, 'no filename was given' if @fn.nil?
46
+ @filename = opts.fetch(:filename, name)
47
+ raise ArgumentError, 'no filename was given' if @filename.nil?
52
48
 
53
- @fn = ::File.expand_path(@fn)
54
- self.class.assert_valid_logfile(@fn)
55
- @mode = opts.fetch(:truncate, false) ? 'w' : 'a'
49
+ @filename = ::File.expand_path(@filename).freeze
50
+ self.class.assert_valid_logfile(@filename)
56
51
 
57
52
  self.encoding = opts.fetch(:encoding, self.encoding)
58
- @mode = "#{@mode}:#{self.encoding}" if self.encoding
59
53
 
60
- super(name, ::File.new(@fn, @mode), opts)
54
+ io = open_file
55
+ super(name, io, opts)
56
+
57
+ truncate if opts.fetch(:truncate, false)
61
58
  end
62
59
 
63
60
  # Returns the path to the logfile.
64
- #
65
- def filename() @fn.dup end
61
+ attr_reader :filename
66
62
 
67
63
  # Reopen the connection to the underlying logging destination. If the
68
64
  # connection is currently closed then it will be opened. If the connection
69
65
  # is currently open then it will be closed and immediately opened.
70
- #
71
66
  def reopen
72
67
  @mutex.synchronize {
73
- if defined? @io and @io
68
+ if defined? @io && @io
74
69
  flush
75
70
  @io.close rescue nil
76
71
  end
77
- @io = ::File.new(@fn, @mode)
72
+ @io = open_file
78
73
  }
79
74
  super
80
75
  self
81
76
  end
82
77
 
83
- end # FileAppender
84
- end # Logging::Appenders
85
78
 
79
+ protected
80
+
81
+ def truncate
82
+ @mutex.synchronize {
83
+ begin
84
+ @io.flock(::File::LOCK_EX)
85
+ @io.truncate(0)
86
+ ensure
87
+ @io.flock(::File::LOCK_UN)
88
+ end
89
+ }
90
+ end
91
+
92
+ def open_file
93
+ mode = ::File::WRONLY | ::File::APPEND
94
+ ::File.open(filename, mode: mode, external_encoding: encoding)
95
+ rescue Errno::ENOENT
96
+ create_file
97
+ end
98
+
99
+ def create_file
100
+ mode = ::File::WRONLY | ::File::APPEND | ::File::CREAT | ::File::EXCL
101
+ ::File.open(filename, mode: mode, external_encoding: encoding)
102
+ rescue Errno::EEXIST
103
+ open_file
104
+ end
105
+ end
106
+ end
@@ -2,7 +2,6 @@
2
2
  module Logging::Appenders
3
3
 
4
4
  # Accessor / Factory for the IO appender.
5
- #
6
5
  def self.io( *args )
7
6
  return ::Logging::Appenders::IO if args.empty?
8
7
  ::Logging::Appenders::IO.new(*args)
@@ -10,14 +9,12 @@ module Logging::Appenders
10
9
 
11
10
  # This class provides an Appender that can write to any IO stream
12
11
  # configured for writing.
13
- #
14
12
  class IO < ::Logging::Appender
15
13
  include Buffering
16
14
 
17
15
  # The method that will be used to close the IO stream. Defaults to :close
18
16
  # but can be :close_read, :close_write or nil. When nil, the IO stream
19
17
  # will not be closed when the appender's close method is called.
20
- #
21
18
  attr_accessor :close_method
22
19
 
23
20
  # call-seq:
@@ -26,7 +23,6 @@ module Logging::Appenders
26
23
  #
27
24
  # Creates a new IO Appender using the given name that will use the _io_
28
25
  # stream as the logging destination.
29
- #
30
26
  def initialize( name, io, opts = {} )
31
27
  unless io.respond_to? :write
32
28
  raise TypeError, "expecting an IO object but got '#{io.class.name}'"
@@ -47,7 +43,6 @@ module Logging::Appenders
47
43
  # destination if the _footer_ flag is set to +true+. Log events will
48
44
  # no longer be written to the logging destination after the appender
49
45
  # is closed.
50
- #
51
46
  def close( *args )
52
47
  return self if @io.nil?
53
48
  super
@@ -61,16 +56,25 @@ module Logging::Appenders
61
56
  return self
62
57
  end
63
58
 
59
+ # Reopen the connection to the underlying logging destination. If the
60
+ # connection is currently closed then it will be opened. If the connection
61
+ # is currently open then it will be closed and immediately opened. If
62
+ # supported, the IO will have its sync mode set to `true` so that all writes
63
+ # are immediately flushed to the underlying operating system.
64
+ def reopen
65
+ super
66
+ @io.sync = true if @io.respond_to? :sync=
67
+ self
68
+ end
64
69
 
65
70
  private
66
71
 
67
72
  # This method is called by the buffering code when messages need to be
68
73
  # written to the logging destination.
69
- #
70
74
  def canonical_write( str )
71
75
  return self if @io.nil?
72
76
  str = str.force_encoding(encoding) if encoding && str.encoding != encoding
73
- @io.write str
77
+ @mutex.synchronize { @io.write str }
74
78
  self
75
79
  rescue StandardError => err
76
80
  handle_internal_error(err)
@@ -82,6 +86,5 @@ module Logging::Appenders
82
86
  ::Logging.log_internal {"appender #{name.inspect} has been disabled"}
83
87
  ::Logging.log_internal_error(err)
84
88
  end
85
-
86
- end # IO
87
- end # Logging::Appenders
89
+ end
90
+ end