logging 2.0.0 → 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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +8 -5
- data/History.txt +59 -0
- data/LICENSE +22 -0
- data/README.md +20 -41
- data/Rakefile +2 -2
- data/examples/appenders.rb +1 -1
- data/examples/layouts.rb +1 -1
- data/examples/lazy.rb +1 -1
- data/examples/mdc.rb +2 -2
- data/examples/rails4.rb +21 -0
- data/examples/reusing_layouts.rb +51 -0
- data/lib/logging.rb +99 -9
- data/lib/logging/appender.rb +13 -34
- data/lib/logging/appenders/buffering.rb +130 -59
- data/lib/logging/appenders/console.rb +68 -57
- data/lib/logging/appenders/file.rb +43 -22
- data/lib/logging/appenders/io.rb +22 -16
- data/lib/logging/appenders/rolling_file.rb +60 -26
- data/lib/logging/appenders/string_io.rb +1 -1
- data/lib/logging/appenders/syslog.rb +3 -4
- data/lib/logging/color_scheme.rb +1 -1
- data/lib/logging/diagnostic_context.rb +100 -73
- data/lib/logging/layout.rb +144 -16
- data/lib/logging/layouts/parseable.rb +50 -12
- data/lib/logging/layouts/pattern.rb +8 -9
- data/lib/logging/log_event.rb +19 -12
- data/lib/logging/logger.rb +117 -95
- data/lib/logging/proxy.rb +1 -1
- data/lib/logging/rails_compat.rb +4 -13
- data/lib/logging/version.rb +1 -1
- data/logging.gemspec +31 -32
- data/script/console +8 -0
- data/test/appenders/{test_periodic_flushing.rb → test_async_flushing.rb} +67 -14
- data/test/appenders/test_buffered_io.rb +19 -18
- data/test/appenders/test_console.rb +55 -12
- data/test/appenders/test_file.rb +48 -28
- data/test/appenders/test_rolling_file.rb +18 -12
- data/test/appenders/test_syslog.rb +6 -0
- data/test/benchmark.rb +42 -18
- data/test/layouts/test_json.rb +14 -1
- data/test/layouts/test_nested_exceptions.rb +124 -0
- data/test/layouts/test_pattern.rb +16 -3
- data/test/layouts/test_yaml.rb +15 -1
- data/test/performance.rb +66 -0
- data/test/setup.rb +26 -30
- data/test/test_appender.rb +2 -4
- data/test/test_layout.rb +49 -0
- data/test/test_log_event.rb +10 -2
- data/test/test_logger.rb +20 -3
- data/test/test_logging.rb +75 -4
- data/test/test_mapped_diagnostic_context.rb +15 -6
- data/test/test_nested_diagnostic_context.rb +6 -1
- metadata +23 -17
@@ -103,7 +103,7 @@ module Logging::Layouts
|
|
103
103
|
'message' => 'format_obj(event.data)'.freeze,
|
104
104
|
'file' => 'event.file'.freeze,
|
105
105
|
'line' => 'event.line'.freeze,
|
106
|
-
'method' => 'event.
|
106
|
+
'method' => 'event.method_name'.freeze,
|
107
107
|
'hostname' => "'#{Socket.gethostname}'".freeze,
|
108
108
|
'pid' => 'Process.pid'.freeze,
|
109
109
|
'millis' => 'Integer((event.time-@created_at)*1000)'.freeze,
|
@@ -177,8 +177,9 @@ module Logging::Layouts
|
|
177
177
|
#
|
178
178
|
# Creates a new Parseable layout using the following options:
|
179
179
|
#
|
180
|
-
# :style
|
181
|
-
# :items
|
180
|
+
# :style => :json or :yaml
|
181
|
+
# :items => %w[timestamp level logger message]
|
182
|
+
# :utc_offset => "-06:00" or -21600 or "UTC"
|
182
183
|
#
|
183
184
|
def initialize( opts = {} )
|
184
185
|
super
|
@@ -218,10 +219,15 @@ module Logging::Layouts
|
|
218
219
|
def format_obj( obj )
|
219
220
|
case obj
|
220
221
|
when Exception
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
222
|
+
hash = {
|
223
|
+
:class => obj.class.name,
|
224
|
+
:message => obj.message
|
225
|
+
}
|
226
|
+
hash[:backtrace] = obj.backtrace if backtrace? && obj.backtrace
|
227
|
+
|
228
|
+
cause = format_cause(obj)
|
229
|
+
hash[:cause] = cause unless cause.empty?
|
230
|
+
hash
|
225
231
|
when Time
|
226
232
|
iso8601_format(obj)
|
227
233
|
else
|
@@ -229,6 +235,37 @@ module Logging::Layouts
|
|
229
235
|
end
|
230
236
|
end
|
231
237
|
|
238
|
+
# Internal: Format any nested exceptions found in the given exception `e`
|
239
|
+
# while respecting the maximum `cause_depth`.
|
240
|
+
#
|
241
|
+
# e - Exception to format
|
242
|
+
#
|
243
|
+
# Returns the cause formatted as a Hash
|
244
|
+
def format_cause(e)
|
245
|
+
rv = curr = {}
|
246
|
+
prev = nil
|
247
|
+
|
248
|
+
cause_depth.times do
|
249
|
+
break unless e.respond_to?(:cause) && e.cause
|
250
|
+
|
251
|
+
cause = e.cause
|
252
|
+
curr[:class] = cause.class.name
|
253
|
+
curr[:message] = cause.message
|
254
|
+
curr[:backtrace] = format_cause_backtrace(e, cause) if backtrace? && cause.backtrace
|
255
|
+
|
256
|
+
prev[:cause] = curr unless prev.nil?
|
257
|
+
prev, curr = curr, {}
|
258
|
+
|
259
|
+
e = cause
|
260
|
+
end
|
261
|
+
|
262
|
+
if e.respond_to?(:cause) && e.cause
|
263
|
+
prev[:cause] = {message: "Further #cause backtraces were omitted"}
|
264
|
+
end
|
265
|
+
|
266
|
+
rv
|
267
|
+
end
|
268
|
+
|
232
269
|
private
|
233
270
|
|
234
271
|
# Call the appropriate class level create format method based on the
|
@@ -241,9 +278,11 @@ module Logging::Layouts
|
|
241
278
|
else raise ArgumentError, "unknown format style '#@style'" end
|
242
279
|
end
|
243
280
|
|
244
|
-
# Convert the given time
|
281
|
+
# Convert the given `time` into an ISO8601 formatted time string.
|
245
282
|
#
|
246
|
-
def iso8601_format(
|
283
|
+
def iso8601_format( time )
|
284
|
+
value = apply_utc_offset(time)
|
285
|
+
|
247
286
|
str = value.strftime('%Y-%m-%dT%H:%M:%S')
|
248
287
|
str << ('.%06d' % value.usec)
|
249
288
|
|
@@ -254,6 +293,5 @@ module Logging::Layouts
|
|
254
293
|
return str << (value.gmt_offset < 0 ? '-' : '+') << offset
|
255
294
|
end
|
256
295
|
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
296
|
+
end
|
297
|
+
end
|
@@ -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
|
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
|
@@ -164,14 +164,12 @@ module Logging::Layouts
|
|
164
164
|
def self.create_date_format_methods( pl )
|
165
165
|
code = "undef :format_date if method_defined? :format_date\n"
|
166
166
|
code << "def format_date( time )\n"
|
167
|
+
code << "time = apply_utc_offset(time)\n"
|
167
168
|
if pl.date_method.nil?
|
168
169
|
if pl.date_pattern =~ %r/%s/
|
169
|
-
code <<
|
170
|
-
dp = '#{pl.date_pattern}'.gsub('%s','%06d' % time.usec)
|
171
|
-
time.strftime dp
|
172
|
-
CODE
|
170
|
+
code << "time.strftime('#{pl.date_pattern.gsub('%s','%6N')}')\n"
|
173
171
|
else
|
174
|
-
code << "time.strftime
|
172
|
+
code << "time.strftime('#{pl.date_pattern}')\n"
|
175
173
|
end
|
176
174
|
else
|
177
175
|
code << "time.#{pl.date_method}\n"
|
@@ -206,7 +204,8 @@ module Logging::Layouts
|
|
206
204
|
#
|
207
205
|
# :pattern => "[%d] %-5l -- %c : %m\n"
|
208
206
|
# :date_pattern => "%Y-%m-%d %H:%M:%S"
|
209
|
-
# :date_method =>
|
207
|
+
# :date_method => "usec" or "to_s"
|
208
|
+
# :utc_offset => "-06:00" or -21600 or "UTC"
|
210
209
|
# :color_scheme => :default
|
211
210
|
#
|
212
211
|
# If used, :date_method will supersede :date_pattern.
|
@@ -219,7 +218,7 @@ module Logging::Layouts
|
|
219
218
|
#
|
220
219
|
def initialize( opts = {} )
|
221
220
|
super
|
222
|
-
@created_at = Time.now
|
221
|
+
@created_at = Time.now.freeze
|
223
222
|
|
224
223
|
@date_pattern = opts.fetch(:date_pattern, nil)
|
225
224
|
@date_method = opts.fetch(:date_method, nil)
|
@@ -308,7 +307,7 @@ module Logging::Layouts
|
|
308
307
|
'l' => '::Logging::LNAMES[event.level]'.freeze,
|
309
308
|
'L' => 'event.line'.freeze,
|
310
309
|
'm' => 'format_obj(event.data)'.freeze,
|
311
|
-
'M' => 'event.
|
310
|
+
'M' => 'event.method_name'.freeze,
|
312
311
|
'h' => "'#{Socket.gethostname}'".freeze,
|
313
312
|
'p' => 'Process.pid'.freeze,
|
314
313
|
'r' => 'Integer((event.time-@created_at)*1000).to_s'.freeze,
|
data/lib/logging/log_event.rb
CHANGED
@@ -2,8 +2,7 @@
|
|
2
2
|
module Logging
|
3
3
|
|
4
4
|
# This class defines a logging event.
|
5
|
-
|
6
|
-
LogEvent = Struct.new( :logger, :level, :data, :time, :file, :line, :method ) {
|
5
|
+
class LogEvent
|
7
6
|
# :stopdoc:
|
8
7
|
|
9
8
|
# Regular expression used to parse out caller information
|
@@ -11,11 +10,13 @@ module Logging
|
|
11
10
|
# * $1 == filename
|
12
11
|
# * $2 == line number
|
13
12
|
# * $3 == method name (might be nil)
|
14
|
-
CALLER_RGXP = %r/([-\.\/\(\)\w]+):(\d+)(?::in `(
|
13
|
+
CALLER_RGXP = %r/([-\.\/\(\)\w]+):(\d+)(?::in `([^']+)')?/o
|
15
14
|
#CALLER_INDEX = 2
|
16
15
|
CALLER_INDEX = ((defined? JRUBY_VERSION and JRUBY_VERSION > '1.6') or (defined? RUBY_ENGINE and RUBY_ENGINE[%r/^rbx/i])) ? 1 : 2
|
17
16
|
# :startdoc:
|
18
17
|
|
18
|
+
attr_accessor :logger, :level, :data, :time, :file, :line, :method_name
|
19
|
+
|
19
20
|
# call-seq:
|
20
21
|
# LogEvent.new( logger, level, [data], caller_tracing )
|
21
22
|
#
|
@@ -25,20 +26,26 @@ module Logging
|
|
25
26
|
# invoked to get the execution trace of the logging method.
|
26
27
|
#
|
27
28
|
def initialize( logger, level, data, caller_tracing )
|
28
|
-
|
29
|
+
self.logger = logger
|
30
|
+
self.level = level
|
31
|
+
self.data = data
|
32
|
+
self.time = Time.now.freeze
|
29
33
|
|
30
34
|
if caller_tracing
|
31
35
|
stack = Kernel.caller[CALLER_INDEX]
|
32
36
|
return if stack.nil?
|
33
37
|
|
34
38
|
match = CALLER_RGXP.match(stack)
|
35
|
-
|
36
|
-
|
37
|
-
|
39
|
+
self.file = match[1]
|
40
|
+
self.line = Integer(match[2])
|
41
|
+
self.method_name = match[3] unless match[3].nil?
|
42
|
+
|
43
|
+
if (bp = ::Logging.basepath) && !bp.empty? && file.index(bp) == 0
|
44
|
+
self.file = file.slice(bp.length + 1, file.length - bp.length)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
self.file = self.line = self.method_name = ''
|
38
48
|
end
|
39
|
-
|
40
|
-
super(logger, level, data, Time.now, f, l, m)
|
41
49
|
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
50
|
+
end
|
51
|
+
end
|
data/lib/logging/logger.rb
CHANGED
@@ -24,89 +24,108 @@ module Logging
|
|
24
24
|
#
|
25
25
|
class Logger
|
26
26
|
|
27
|
-
|
27
|
+
# Returns the root logger.
|
28
|
+
def self.root
|
29
|
+
::Logging::Repository.instance[:root]
|
30
|
+
end
|
28
31
|
|
29
32
|
class << self
|
33
|
+
alias_method :instantiate, :new # `instantiate` becomes the "real" `new`
|
34
|
+
end
|
30
35
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
# Overrides the new method such that only one Logger will be created
|
37
|
+
# for any given logger name.
|
38
|
+
def self.new( *args )
|
39
|
+
args.empty? ? super : self[args.shift]
|
40
|
+
end
|
35
41
|
|
36
|
-
|
42
|
+
# Returns a logger instance for the given name.
|
43
|
+
def self.[]( name )
|
44
|
+
repo = ::Logging::Repository.instance
|
45
|
+
name = repo.to_key(name)
|
46
|
+
logger = repo[name]
|
47
|
+
return logger unless logger.nil?
|
48
|
+
|
49
|
+
# Share the same mutex that's used by 'define_log_methods' because
|
50
|
+
# it iterates over the hash of loggers, and adding a new key to a hash
|
51
|
+
# while iterating over it produces an error.
|
52
|
+
::Logging::Logger.mutex.synchronize do
|
53
|
+
logger = repo[name]
|
54
|
+
return logger unless logger.nil? # thread-safe double checking
|
37
55
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
56
|
+
logger = instantiate(name)
|
57
|
+
repo[name] = logger
|
58
|
+
repo.children(name).each { |child| child.__send__(:parent=, logger) }
|
59
|
+
logger
|
42
60
|
end
|
61
|
+
end
|
43
62
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
63
|
+
# This is where the actual logging methods are defined. Two methods
|
64
|
+
# are created for each log level. The first is a query method used to
|
65
|
+
# determine if that perticular logging level is enabled. The second is
|
66
|
+
# the actual logging method that accepts a list of objects to be
|
67
|
+
# logged or a block. If a block is given, then the object returned
|
68
|
+
# from the block will be logged.
|
69
|
+
#
|
70
|
+
# Example
|
71
|
+
#
|
72
|
+
# log = Logging::Logger['my logger']
|
73
|
+
# log.level = :warn
|
74
|
+
#
|
75
|
+
# log.info? # => false
|
76
|
+
# log.warn? # => true
|
77
|
+
# log.warn 'this is your last warning'
|
78
|
+
# log.fatal 'I die!', exception
|
79
|
+
#
|
80
|
+
# log.debug do
|
81
|
+
# # expensive method to construct log message
|
82
|
+
# msg
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
def self.define_log_methods( logger )
|
86
|
+
code = log_methods_for_level(logger.level)
|
87
|
+
logger._meta_eval(code, __FILE__, __LINE__)
|
88
|
+
logger
|
89
|
+
end
|
54
90
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
91
|
+
# This generator is used to define the log methods for the given `level`.
|
92
|
+
# This code is evaluated in the context of a Logger instance.
|
93
|
+
#
|
94
|
+
# Returns log methods as a String
|
95
|
+
def self.log_methods_for_level( level )
|
96
|
+
code = []
|
97
|
+
::Logging::LEVELS.each do |name,num|
|
98
|
+
code << <<-CODE
|
99
|
+
undef :#{name} if method_defined? :#{name}
|
100
|
+
undef :#{name}? if method_defined? :#{name}?
|
101
|
+
CODE
|
102
|
+
|
103
|
+
if level > num
|
104
|
+
code << <<-CODE
|
105
|
+
def #{name}?( ) false end
|
106
|
+
def #{name}( data = nil ) false end
|
107
|
+
CODE
|
108
|
+
else
|
109
|
+
code << <<-CODE
|
110
|
+
def #{name}?( ) true end
|
111
|
+
def #{name}( data = nil )
|
112
|
+
data = yield if block_given?
|
113
|
+
log_event(::Logging::LogEvent.new(@name, #{num}, data, @caller_tracing))
|
114
|
+
true
|
115
|
+
end
|
116
|
+
CODE
|
59
117
|
end
|
60
118
|
end
|
119
|
+
code.join("\n")
|
120
|
+
end
|
61
121
|
|
62
|
-
|
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
|
122
|
+
@mutex = ReentrantMutex.new
|
104
123
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
124
|
+
# Returns a global ReentrantMutex for use when creating Logger instances
|
125
|
+
# and/or updating log levels.
|
126
|
+
def self.mutex
|
127
|
+
@mutex
|
128
|
+
end
|
110
129
|
|
111
130
|
attr_reader :name, :parent, :additive, :caller_tracing
|
112
131
|
|
@@ -197,7 +216,14 @@ module Logging
|
|
197
216
|
lvl = Integer(lvl)
|
198
217
|
return false if lvl < level
|
199
218
|
|
200
|
-
|
219
|
+
if data.nil?
|
220
|
+
if block_given?
|
221
|
+
data = yield
|
222
|
+
else
|
223
|
+
data = progname
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
201
227
|
log_event(::Logging::LogEvent.new(@name, lvl, data, @caller_tracing))
|
202
228
|
true
|
203
229
|
end
|
@@ -247,7 +273,7 @@ module Logging
|
|
247
273
|
# level = :all
|
248
274
|
#
|
249
275
|
# Set the level for this logger. The level can be either a +String+, a
|
250
|
-
# +Symbol+, or
|
276
|
+
# +Symbol+, or an +Integer+. An +ArgumentError+ is raised if this is not
|
251
277
|
# the case.
|
252
278
|
#
|
253
279
|
# There are two special levels -- "all" and "off". The former will
|
@@ -277,7 +303,7 @@ module Logging
|
|
277
303
|
else
|
278
304
|
lvl = case level
|
279
305
|
when String, Symbol; ::Logging::level_num(level)
|
280
|
-
when
|
306
|
+
when Integer; level
|
281
307
|
else
|
282
308
|
raise ArgumentError,
|
283
309
|
"level must be a String, Symbol, or Integer"
|
@@ -292,6 +318,11 @@ module Logging
|
|
292
318
|
self.level
|
293
319
|
end
|
294
320
|
|
321
|
+
# Returns `true` if the logger has its own level defined.
|
322
|
+
def has_own_level?
|
323
|
+
!@level.nil?
|
324
|
+
end
|
325
|
+
|
295
326
|
# Returns the list of appenders.
|
296
327
|
#
|
297
328
|
def appenders
|
@@ -353,17 +384,7 @@ module Logging
|
|
353
384
|
#
|
354
385
|
def clear_appenders( ) @appenders.clear end
|
355
386
|
|
356
|
-
|
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
|
387
|
+
protected
|
367
388
|
|
368
389
|
# call-seq:
|
369
390
|
# parent = ParentLogger
|
@@ -396,18 +417,20 @@ module Logging
|
|
396
417
|
#
|
397
418
|
# Recursively call this method on all our children loggers.
|
398
419
|
#
|
399
|
-
def define_log_methods( force = false )
|
400
|
-
return if
|
420
|
+
def define_log_methods( force = false, code = nil )
|
421
|
+
return if has_own_level? and !force
|
401
422
|
|
402
|
-
::Logging::Logger.
|
403
|
-
|
404
|
-
|
423
|
+
::Logging::Logger.mutex.synchronize do
|
424
|
+
::Logging::Logger.define_log_methods(self)
|
425
|
+
::Logging::Repository.instance.children(name).each do |child|
|
426
|
+
child.define_log_methods
|
427
|
+
end
|
405
428
|
end
|
406
429
|
self
|
407
430
|
end
|
408
431
|
|
409
432
|
# :stopdoc:
|
410
|
-
|
433
|
+
public
|
411
434
|
|
412
435
|
# call-seq:
|
413
436
|
# _meta_eval( code )
|
@@ -483,7 +506,7 @@ module Logging
|
|
483
506
|
@appenders.each do |appender|
|
484
507
|
str << indent_str
|
485
508
|
str << '- '
|
486
|
-
str << appender.
|
509
|
+
str << appender.to_s
|
487
510
|
str << "\n"
|
488
511
|
end
|
489
512
|
|
@@ -491,6 +514,5 @@ module Logging
|
|
491
514
|
end
|
492
515
|
# :startdoc:
|
493
516
|
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
517
|
+
end
|
518
|
+
end
|