logging 2.0.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|