logging 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,44 +1,55 @@
1
-
2
1
  module Logging::Appenders
3
2
 
4
- # Accessor / Factory for the Stdout appender.
5
- #
6
- def self.stdout( *args )
7
- if args.empty?
8
- return self['stdout'] || ::Logging::Appenders::Stdout.new
9
- end
10
- ::Logging::Appenders::Stdout.new(*args)
11
- end
12
-
13
- # This class provides an Appender that can write to STDOUT.
14
- #
15
- class Stdout < ::Logging::Appenders::IO
3
+ # This class is provides an Appender base class for writing to the standard IO
4
+ # stream - STDOUT and STDERR. This class should not be instantiated directly.
5
+ # The `Stdout` and `Stderr` subclasses should be used.
6
+ class Console < ::Logging::Appenders::IO
16
7
 
17
8
  # call-seq:
18
9
  # Stdout.new( name = 'stdout' )
19
- # Stdout.new( :layout => layout )
10
+ # Stderr.new( :layout => layout )
20
11
  # Stdout.new( name = 'stdout', :level => 'info' )
21
12
  #
22
- # Creates a new Stdout Appender. The name 'stdout' will be used unless
23
- # another is given. Optionally, a layout can be given for the appender
24
- # to use (otherwise a basic appender will be created) and a log level
25
- # can be specified.
13
+ # Creates a new Stdout/Stderr Appender. The name 'stdout'/'stderr' will be
14
+ # used unless another is given. Optionally, a layout can be given for the
15
+ # appender to use (otherwise a basic appender will be created) and a log
16
+ # level can be specified.
26
17
  #
27
18
  # Options:
28
19
  #
29
- # :layout => the layout to use when formatting log events
30
- # :level => the level at which to log
20
+ # :layout => the layout to use when formatting log events
21
+ # :level => the level at which to log
31
22
  #
32
23
  def initialize( *args )
24
+ name = self.class.name.split("::").last.downcase
25
+ io = Object.const_get(name.upcase)
26
+
33
27
  opts = Hash === args.last ? args.pop : {}
34
- name = args.empty? ? 'stdout' : args.shift
28
+ name = args.shift unless args.empty?
35
29
 
36
- opts[:encoding] = STDOUT.external_encoding if STDOUT.respond_to? :external_encoding
30
+ opts[:encoding] = io.external_encoding if io.respond_to? :external_encoding
37
31
 
38
- super(name, STDOUT, opts)
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"
39
36
  end
40
- end # Stdout
37
+ end
38
+
39
+ # This class provides an Appender that can write to STDOUT.
40
+ Stdout = Class.new(Console)
41
41
 
42
+ # This class provides an Appender that can write to STDERR.
43
+ Stderr = Class.new(Console)
44
+
45
+ # Accessor / Factory for the Stdout appender.
46
+ #
47
+ def self.stdout( *args )
48
+ if args.empty?
49
+ return self['stdout'] || ::Logging::Appenders::Stdout.new
50
+ end
51
+ ::Logging::Appenders::Stdout.new(*args)
52
+ end
42
53
 
43
54
  # Accessor / Factory for the Stderr appender.
44
55
  #
@@ -48,34 +59,4 @@ module Logging::Appenders
48
59
  end
49
60
  ::Logging::Appenders::Stderr.new(*args)
50
61
  end
51
-
52
- # This class provides an Appender that can write to STDERR.
53
- #
54
- class Stderr < ::Logging::Appenders::IO
55
-
56
- # call-seq:
57
- # Stderr.new( name = 'stderr' )
58
- # Stderr.new( :layout => layout )
59
- # Stderr.new( name = 'stderr', :level => 'warn' )
60
- #
61
- # Creates a new Stderr Appender. The name 'stderr' will be used unless
62
- # another is given. Optionally, a layout can be given for the appender
63
- # to use (otherwise a basic appender will be created) and a log level
64
- # can be specified.
65
- #
66
- # Options:
67
- #
68
- # :layout => the layout to use when formatting log events
69
- # :level => the level at which to log
70
- #
71
- def initialize( *args )
72
- opts = Hash === args.last ? args.pop : {}
73
- name = args.empty? ? 'stderr' : args.shift
74
-
75
- opts[:encoding] = STDERR.external_encoding if STDERR.respond_to? :external_encoding
76
-
77
- super(name, STDERR, opts)
78
- end
79
- end # Stderr
80
- end # Logging::Appenders
81
-
62
+ end
@@ -4,7 +4,7 @@ module Logging::Appenders
4
4
  # Accessor / Factory for the File appender.
5
5
  #
6
6
  def self.file( *args )
7
- return ::Logging::Appenders::File if args.empty?
7
+ fail ArgumentError, '::Logging::Appenders::File needs a name as first argument.' if args.empty?
8
8
  ::Logging::Appenders::File.new(*args)
9
9
  end
10
10
 
@@ -28,13 +28,12 @@ module Logging::Appenders
28
28
  # stream as the logging destination.
29
29
  #
30
30
  def initialize( name, io, opts = {} )
31
- unless io.respond_to? :syswrite
31
+ unless io.respond_to? :write
32
32
  raise TypeError, "expecting an IO object but got '#{io.class.name}'"
33
33
  end
34
34
 
35
35
  @io = io
36
- @io.sync = true if io.respond_to? :sync= # syswrite complains if the IO stream is buffered
37
- @io.flush rescue nil # syswrite also complains if in unbuffered mode and buffer isn't empty
36
+ @io.sync = true if io.respond_to? :sync=
38
37
  @close_method = :close
39
38
 
40
39
  super(name, opts)
@@ -55,7 +54,7 @@ module Logging::Appenders
55
54
 
56
55
  io, @io = @io, nil
57
56
  unless [STDIN, STDERR, STDOUT].include?(io)
58
- io.send(@close_method) if @close_method and io.respond_to? @close_method
57
+ io.send(@close_method) if @close_method && io.respond_to?(@close_method)
59
58
  end
60
59
  rescue IOError
61
60
  ensure
@@ -70,10 +69,15 @@ module Logging::Appenders
70
69
  #
71
70
  def canonical_write( str )
72
71
  return self if @io.nil?
73
- str = str.force_encoding(encoding) if encoding and str.encoding != encoding
74
- @io.syswrite str
72
+ str = str.force_encoding(encoding) if encoding && str.encoding != encoding
73
+ @io.write str
75
74
  self
76
75
  rescue StandardError => err
76
+ handle_internal_error(err)
77
+ end
78
+
79
+ def handle_internal_error( err )
80
+ return err if off?
77
81
  self.level = :off
78
82
  ::Logging.log_internal {"appender #{name.inspect} has been disabled"}
79
83
  ::Logging.log_internal_error(err)
@@ -81,4 +85,3 @@ module Logging::Appenders
81
85
 
82
86
  end # IO
83
87
  end # Logging::Appenders
84
-
@@ -2,7 +2,7 @@ module Logging::Appenders
2
2
 
3
3
  # Accessor / Factory for the RollingFile appender.
4
4
  def self.rolling_file( *args )
5
- return ::Logging::Appenders::RollingFile if args.empty?
5
+ fail ArgumentError, '::Logging::Appenders::RollingFile needs a name as first argument.' if args.empty?
6
6
  ::Logging::Appenders::RollingFile.new(*args)
7
7
  end
8
8
 
@@ -148,7 +148,7 @@ module Logging::Appenders
148
148
  return self if @io.nil?
149
149
 
150
150
  str = str.force_encoding(encoding) if encoding && str.encoding != encoding
151
- @io.flock_sh { @io.syswrite str }
151
+ @io.flock_sh { @io.write str }
152
152
 
153
153
  if roll_required?
154
154
  @io.flock? {
@@ -9,7 +9,7 @@ module Logging::Appenders
9
9
  # Accessor / Factory for the Syslog appender.
10
10
  #
11
11
  def self.syslog( *args )
12
- return ::Logging::Appenders::Syslog if args.empty?
12
+ fail ArgumentError, '::Logging::Appenders::Syslog needs a name as first argument.' if args.empty?
13
13
  ::Logging::Appenders::Syslog.new(*args)
14
14
  end
15
15
 
@@ -143,7 +143,7 @@ module Logging
143
143
  Thread.current[STACK_NAME] = [obj.dup]
144
144
  when Thread
145
145
  return if Thread.current == obj
146
- Thread.exclusive {
146
+ DIAGNOSTIC_MUTEX.synchronize {
147
147
  if obj[STACK_NAME]
148
148
  hash = flatten(obj[STACK_NAME])
149
149
  Thread.current[STACK_NAME] = [hash]
@@ -338,7 +338,7 @@ module Logging
338
338
  Thread.current[NAME] = obj.dup
339
339
  when Thread
340
340
  return if Thread.current == obj
341
- Thread.exclusive {
341
+ DIAGNOSTIC_MUTEX.synchronize {
342
342
  Thread.current[NAME] = obj[NAME].dup if obj[NAME]
343
343
  }
344
344
  end
@@ -381,7 +381,7 @@ module Logging
381
381
  #
382
382
  def self.clear_diagnostic_contexts( all = false )
383
383
  if all
384
- Thread.exclusive {
384
+ DIAGNOSTIC_MUTEX.synchronize {
385
385
  Thread.list.each { |thread|
386
386
  thread[MappedDiagnosticContext::NAME] = nil if thread[MappedDiagnosticContext::NAME]
387
387
  thread[NestedDiagnosticContext::NAME] = nil if thread[NestedDiagnosticContext::NAME]
@@ -396,6 +396,8 @@ module Logging
396
396
  self
397
397
  end
398
398
 
399
+ DIAGNOSTIC_MUTEX = Mutex.new
400
+
399
401
  end # module Logging
400
402
 
401
403
 
@@ -41,15 +41,28 @@ class Layout
41
41
  when :inspect, :yaml, :json; f
42
42
  else :string end
43
43
 
44
- b = opts.fetch(:backtrace, ::Logging.backtrace)
45
- @backtrace = case b
46
- when :on, 'on', true; true
47
- when :off, 'off', false; false
48
- else
49
- raise ArgumentError, "backtrace must be true or false"
50
- end
44
+ self.backtrace = opts.fetch(:backtrace, ::Logging.backtrace)
51
45
  end
52
46
 
47
+ # call-seq:
48
+ # layout.backtrace = true
49
+ #
50
+ # Set the backtrace flag to the given value. This can be set to `true` or
51
+ # `false`.
52
+ #
53
+ def backtrace=( value )
54
+ @backtrace = case value
55
+ when :on, 'on', true; true
56
+ when :off, 'off', false; false
57
+ else
58
+ raise ArgumentError, "backtrace must be `true` or `false`"
59
+ end
60
+ end
61
+
62
+ # Returns the backtrace setting.
63
+ attr_reader :backtrace
64
+ alias :backtrace? :backtrace
65
+
53
66
  # call-seq:
54
67
  # format( event )
55
68
  #
@@ -85,7 +98,7 @@ class Layout
85
98
  when String; obj
86
99
  when Exception
87
100
  str = "<#{obj.class.name}> #{obj.message}"
88
- if @backtrace && !obj.backtrace.nil?
101
+ if backtrace? && !obj.backtrace.nil?
89
102
  str << "\n\t" << obj.backtrace.join("\n\t")
90
103
  end
91
104
  str
@@ -83,7 +83,7 @@ module Logging::Layouts
83
83
  # events is configured to generate tracing information. If this is not
84
84
  # the case these fields will always be empty.
85
85
  #
86
- # The directives for include diagnostic context information in the log
86
+ # The directives for including diagnostic context information in the log
87
87
  # messages are X and x. For the Mapped Diagnostic Context the directive must
88
88
  # be accompanied by the key identifying the value to insert into the log
89
89
  # message. The X directive can appear multiple times to include multiple
@@ -166,12 +166,9 @@ module Logging::Layouts
166
166
  code << "def format_date( time )\n"
167
167
  if pl.date_method.nil?
168
168
  if pl.date_pattern =~ %r/%s/
169
- code << <<-CODE
170
- dp = '#{pl.date_pattern}'.gsub('%s','%06d' % time.usec)
171
- time.strftime dp
172
- CODE
169
+ code << "time.strftime('#{pl.date_pattern.gsub('%s','%6N')}')\n"
173
170
  else
174
- code << "time.strftime '#{pl.date_pattern}'\n"
171
+ code << "time.strftime('#{pl.date_pattern}')\n"
175
172
  end
176
173
  else
177
174
  code << "time.#{pl.date_method}\n"
@@ -11,7 +11,7 @@ module Logging
11
11
  # * $1 == filename
12
12
  # * $2 == line number
13
13
  # * $3 == method name (might be nil)
14
- CALLER_RGXP = %r/([-\.\/\(\)\w]+):(\d+)(?::in `(\w+)')?/o
14
+ CALLER_RGXP = %r/([-\.\/\(\)\w]+):(\d+)(?::in `([^']+)')?/o
15
15
  #CALLER_INDEX = 2
16
16
  CALLER_INDEX = ((defined? JRUBY_VERSION and JRUBY_VERSION > '1.6') or (defined? RUBY_ENGINE and RUBY_ENGINE[%r/^rbx/i])) ? 1 : 2
17
17
  # :startdoc:
@@ -26,87 +26,97 @@ module Logging
26
26
 
27
27
  @mutex = Mutex.new # :nodoc:
28
28
 
29
- class << self
29
+ # Returns the root logger.
30
+ def self.root
31
+ ::Logging::Repository.instance[:root]
32
+ end
30
33
 
31
- # Returns the root logger.
32
- def root
33
- ::Logging::Repository.instance[:root]
34
- end
34
+ class << self
35
+ alias_method :instantiate, :new # `instantiate` becomes the "real" `new`
36
+ end
35
37
 
36
- alias_method :instantiate, :new # the "real" new
38
+ # Overrides the new method such that only one Logger will be created
39
+ # for any given logger name.
40
+ def self.new( *args )
41
+ args.empty? ? super : self[args.shift]
42
+ end
37
43
 
38
- # Overrides the new method such that only one Logger will be created
39
- # for any given logger name.
40
- def new( *args )
41
- args.empty? ? super : self[args.shift]
42
- end
44
+ # Returns a logger instance for the given name.
45
+ def self.[]( name )
46
+ repo = ::Logging::Repository.instance
47
+ name = repo.to_key(name)
48
+ logger = repo[name]
49
+ return logger unless logger.nil?
43
50
 
44
- # Returns a logger instance for the given name.
45
- def []( name )
46
- repo = ::Logging::Repository.instance
47
- name = repo.to_key(name)
51
+ @mutex.synchronize do
48
52
  logger = repo[name]
49
- return logger unless logger.nil?
53
+ return logger unless logger.nil? # thread-safe double checking
50
54
 
51
- @mutex.synchronize do
52
- logger = repo[name]
53
- return logger unless logger.nil? # thread-safe double checking
54
-
55
- logger = instantiate(name)
56
- repo[name] = logger
57
- repo.children(name).each { |c| c.__send__(:parent=, logger) }
58
- logger
59
- end
55
+ logger = instantiate(name)
56
+ repo[name] = logger
57
+ repo.children(name).each { |child| child.__send__(:parent=, logger) }
58
+ logger
60
59
  end
60
+ end
61
61
 
62
- # This is where the actual logging methods are defined. Two methods
63
- # are created for each log level. The first is a query method used to
64
- # determine if that perticular logging level is enabled. The second is
65
- # the actual logging method that accepts a list of objects to be
66
- # logged or a block. If a block is given, then the object returned
67
- # from the block will be logged.
68
- #
69
- # Example
70
- #
71
- # log = Logging::Logger['my logger']
72
- # log.level = :warn
73
- #
74
- # log.info? # => false
75
- # log.warn? # => true
76
- # log.warn 'this is your last warning'
77
- # log.fatal 'I die!', exception
78
- #
79
- # log.debug do
80
- # # expensive method to construct log message
81
- # msg
82
- # end
83
- #
84
- def define_log_methods( logger )
85
- ::Logging::LEVELS.each do |name,num|
86
- code = "undef :#{name} if method_defined? :#{name}\n"
87
- code << "undef :#{name}? if method_defined? :#{name}?\n"
88
-
89
- if logger.level > num
90
- code << <<-CODE
91
- def #{name}?( ) false end
92
- def #{name}( data = nil ) false end
93
- CODE
94
- else
95
- code << <<-CODE
96
- def #{name}?( ) true end
97
- def #{name}( data = nil )
98
- data = yield if block_given?
99
- log_event(::Logging::LogEvent.new(@name, #{num}, data, @caller_tracing))
100
- true
101
- end
102
- CODE
103
- end
62
+ # This is where the actual logging methods are defined. Two methods
63
+ # are created for each log level. The first is a query method used to
64
+ # determine if that perticular logging level is enabled. The second is
65
+ # the actual logging method that accepts a list of objects to be
66
+ # logged or a block. If a block is given, then the object returned
67
+ # from the block will be logged.
68
+ #
69
+ # Example
70
+ #
71
+ # log = Logging::Logger['my logger']
72
+ # log.level = :warn
73
+ #
74
+ # log.info? # => false
75
+ # log.warn? # => true
76
+ # log.warn 'this is your last warning'
77
+ # log.fatal 'I die!', exception
78
+ #
79
+ # log.debug do
80
+ # # expensive method to construct log message
81
+ # msg
82
+ # end
83
+ #
84
+ def self.define_log_methods( logger )
85
+ code = log_methods_for_level(logger.level)
86
+ logger._meta_eval(code, __FILE__, __LINE__)
87
+ logger
88
+ end
104
89
 
105
- logger._meta_eval(code, __FILE__, __LINE__)
90
+ # This generator is used to define the log methods for the given `level`.
91
+ # This code is evaluated in the context of a Logger instance.
92
+ #
93
+ # Returns log methods as a String
94
+ def self.log_methods_for_level( level )
95
+ code = []
96
+ ::Logging::LEVELS.each do |name,num|
97
+ code << <<-CODE
98
+ undef :#{name} if method_defined? :#{name}
99
+ undef :#{name}? if method_defined? :#{name}?
100
+ CODE
101
+
102
+ if level > num
103
+ code << <<-CODE
104
+ def #{name}?( ) false end
105
+ def #{name}( data = nil ) false end
106
+ CODE
107
+ else
108
+ code << <<-CODE
109
+ def #{name}?( ) true end
110
+ def #{name}( data = nil )
111
+ data = yield if block_given?
112
+ log_event(::Logging::LogEvent.new(@name, #{num}, data, @caller_tracing))
113
+ true
114
+ end
115
+ CODE
106
116
  end
107
- logger
108
117
  end
109
- end # class << self
118
+ code.join("\n")
119
+ end
110
120
 
111
121
  attr_reader :name, :parent, :additive, :caller_tracing
112
122
 
@@ -197,7 +207,14 @@ module Logging
197
207
  lvl = Integer(lvl)
198
208
  return false if lvl < level
199
209
 
200
- data = yield if block_given?
210
+ if data.nil?
211
+ if block_given?
212
+ data = yield
213
+ else
214
+ data = progname
215
+ end
216
+ end
217
+
201
218
  log_event(::Logging::LogEvent.new(@name, lvl, data, @caller_tracing))
202
219
  true
203
220
  end
@@ -292,6 +309,11 @@ module Logging
292
309
  self.level
293
310
  end
294
311
 
312
+ # Returns `true` if the logger has its own level defined.
313
+ def has_own_level?
314
+ !@level.nil?
315
+ end
316
+
295
317
  # Returns the list of appenders.
296
318
  #
297
319
  def appenders
@@ -353,17 +375,7 @@ module Logging
353
375
  #
354
376
  def clear_appenders( ) @appenders.clear end
355
377
 
356
- # call-seq:
357
- # inspect => string
358
- #
359
- # Returns a string representation of the logger.
360
- #
361
- def inspect
362
- "<%s:0x%x name=\"%s\">" % [self.class.name, self.object_id, self.name]
363
- end
364
-
365
-
366
- protected
378
+ protected
367
379
 
368
380
  # call-seq:
369
381
  # parent = ParentLogger
@@ -396,18 +408,26 @@ module Logging
396
408
  #
397
409
  # Recursively call this method on all our children loggers.
398
410
  #
399
- def define_log_methods( force = false )
400
- return if @level and !force
411
+ def define_log_methods( force = false, code = nil )
412
+ return if has_own_level? and !force
401
413
 
402
- ::Logging::Logger.define_log_methods(self)
403
- ::Logging::Repository.instance.children(name).each do |c|
404
- c.define_log_methods
414
+ ::Logging::Logger._reentrant_mutex.synchronize do
415
+ ::Logging::Logger.define_log_methods(self)
416
+ ::Logging::Repository.instance.children(name).each do |child|
417
+ child.define_log_methods
418
+ end
405
419
  end
406
420
  self
407
421
  end
408
422
 
409
423
  # :stopdoc:
410
- public
424
+ public
425
+
426
+ @reentrant_mutex = ReentrantMutex.new
427
+
428
+ def self._reentrant_mutex
429
+ @reentrant_mutex
430
+ end
411
431
 
412
432
  # call-seq:
413
433
  # _meta_eval( code )
@@ -483,7 +503,7 @@ module Logging
483
503
  @appenders.each do |appender|
484
504
  str << indent_str
485
505
  str << '- '
486
- str << appender.inspect
506
+ str << appender.to_s
487
507
  str << "\n"
488
508
  end
489
509