logging 1.8.2 → 2.0.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 +4 -4
- data/.travis.yml +3 -3
- data/History.txt +20 -0
- data/README.md +159 -0
- data/Rakefile +9 -5
- data/examples/appenders.rb +0 -4
- data/examples/layouts.rb +1 -8
- data/examples/names.rb +4 -4
- data/lib/logging.rb +24 -76
- data/lib/logging/appender.rb +71 -16
- data/lib/logging/appenders.rb +0 -2
- data/lib/logging/appenders/buffering.rb +32 -16
- data/lib/logging/appenders/file.rb +2 -2
- data/lib/logging/appenders/io.rb +1 -1
- data/lib/logging/appenders/rolling_file.rb +228 -165
- data/lib/logging/appenders/string_io.rb +1 -1
- data/lib/logging/appenders/syslog.rb +4 -4
- data/lib/logging/color_scheme.rb +20 -3
- data/lib/logging/diagnostic_context.rb +142 -17
- data/lib/logging/filter.rb +18 -0
- data/lib/logging/filters.rb +4 -0
- data/lib/logging/filters/level.rb +29 -0
- data/lib/logging/layout.rb +2 -2
- data/lib/logging/layouts/parseable.rb +5 -2
- data/lib/logging/layouts/pattern.rb +309 -168
- data/lib/logging/log_event.rb +5 -5
- data/lib/logging/logger.rb +55 -68
- data/lib/logging/repository.rb +24 -39
- data/lib/logging/root_logger.rb +1 -1
- data/lib/logging/utils.rb +4 -65
- data/lib/logging/version.rb +8 -0
- data/lib/rspec/logging_helper.rb +3 -3
- data/logging.gemspec +46 -0
- data/test/appenders/test_buffered_io.rb +29 -0
- data/test/appenders/test_file.rb +2 -2
- data/test/appenders/test_rolling_file.rb +62 -1
- data/test/layouts/test_color_pattern.rb +1 -1
- data/test/layouts/test_json.rb +3 -0
- data/test/layouts/test_pattern.rb +6 -2
- data/test/layouts/test_yaml.rb +4 -1
- data/test/test_appender.rb +56 -0
- data/test/test_filter.rb +33 -0
- data/test/test_layout.rb +4 -8
- data/test/test_log_event.rb +3 -3
- data/test/test_logger.rb +81 -57
- data/test/test_logging.rb +0 -59
- data/test/test_mapped_diagnostic_context.rb +49 -1
- data/test/test_nested_diagnostic_context.rb +16 -1
- data/test/test_repository.rb +24 -32
- data/test/test_utils.rb +14 -50
- metadata +35 -53
- data/README.rdoc +0 -143
- data/data/bad_logging_1.rb +0 -13
- data/data/bad_logging_2.rb +0 -21
- data/data/logging.rb +0 -42
- data/data/logging.yaml +0 -63
- data/data/simple_logging.rb +0 -13
- data/examples/consolidation.rb +0 -83
- data/lib/logging/appenders/email.rb +0 -178
- data/lib/logging/appenders/growl.rb +0 -200
- data/lib/logging/config/configurator.rb +0 -187
- data/lib/logging/config/yaml_configurator.rb +0 -190
- data/lib/logging/stats.rb +0 -277
- data/test/appenders/test_email.rb +0 -170
- data/test/appenders/test_growl.rb +0 -138
- data/test/config/test_configurator.rb +0 -69
- data/test/config/test_yaml_configurator.rb +0 -39
- data/test/test_consolidate.rb +0 -45
- data/test/test_stats.rb +0 -273
- data/version.txt +0 -1
@@ -93,16 +93,16 @@ module Logging::Appenders
|
|
93
93
|
# through LOG_LOCAL7.
|
94
94
|
#
|
95
95
|
def initialize( name, opts = {} )
|
96
|
-
@ident = opts.
|
97
|
-
@logopt = opts.
|
98
|
-
@facility = opts.
|
96
|
+
@ident = opts.fetch(:ident, name)
|
97
|
+
@logopt = Integer(opts.fetch(:logopt, (LOG_PID | LOG_CONS)))
|
98
|
+
@facility = Integer(opts.fetch(:facility, LOG_USER))
|
99
99
|
@syslog = ::Syslog.open(@ident, @logopt, @facility)
|
100
100
|
|
101
101
|
# provides a mapping from the default Logging levels
|
102
102
|
# to the syslog levels
|
103
103
|
@map = [LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERR, LOG_CRIT]
|
104
104
|
|
105
|
-
map = opts.
|
105
|
+
map = opts.fetch(:map, nil)
|
106
106
|
self.map = map unless map.nil?
|
107
107
|
|
108
108
|
super
|
data/lib/logging/color_scheme.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
|
2
1
|
# color_scheme.rb
|
3
2
|
#
|
4
3
|
# Created by Jeremy Hinegardner on 2007-01-24
|
5
4
|
# Copyright 2007. All rights reserved
|
6
5
|
#
|
7
|
-
# This is
|
6
|
+
# This file is licensed under the terms of the MIT License.
|
7
|
+
# See the README for licensing details.
|
8
|
+
#
|
8
9
|
|
9
10
|
module Logging
|
10
11
|
|
@@ -71,7 +72,7 @@ module Logging
|
|
71
72
|
# end of this file. Multiple color codes can be aliased by grouping them
|
72
73
|
# in an array as shown in the example above.
|
73
74
|
#
|
74
|
-
# Since color schemes are
|
75
|
+
# Since color schemes are primarily intended to be used with the Pattern
|
75
76
|
# layout, there are a few special options of note. First the log levels
|
76
77
|
# are enumerated in their own hash:
|
77
78
|
#
|
@@ -239,6 +240,22 @@ module Logging
|
|
239
240
|
ON_CYAN = "\e[46m".freeze # Set the terminal's background ANSI color to cyan.
|
240
241
|
ON_WHITE = "\e[47m".freeze # Set the terminal's background ANSI color to white.
|
241
242
|
|
243
|
+
BRIGHT_RED = "\e[1;31m".freeze # Set the terminal's foreground ANSI color to bright red.
|
244
|
+
BRIGHT_GREEN = "\e[1;32m".freeze # Set the terminal's foreground ANSI color to bright green.
|
245
|
+
BRIGHT_YELLOW = "\e[1;33m".freeze # Set the terminal's foreground ANSI color to bright yellow.
|
246
|
+
BRIGHT_BLUE = "\e[1;34m".freeze # Set the terminal's foreground ANSI color to bright blue.
|
247
|
+
BRIGHT_MAGENTA = "\e[1;35m".freeze # Set the terminal's foreground ANSI color to bright magenta.
|
248
|
+
BRIGHT_CYAN = "\e[1;36m".freeze # Set the terminal's foreground ANSI color to bright cyan.
|
249
|
+
BRIGHT_WHITE = "\e[1;37m".freeze # Set the terminal's foreground ANSI color to bright white.
|
250
|
+
|
251
|
+
ON_BRIGHT_RED = "\e[1;41m".freeze # Set the terminal's background ANSI color to bright red.
|
252
|
+
ON_BRIGHT_GREEN = "\e[1;42m".freeze # Set the terminal's background ANSI color to bright green.
|
253
|
+
ON_BRIGHT_YELLOW = "\e[1;43m".freeze # Set the terminal's background ANSI color to bright yellow.
|
254
|
+
ON_BRIGHT_BLUE = "\e[1;44m".freeze # Set the terminal's background ANSI color to bright blue.
|
255
|
+
ON_BRIGHT_MAGENTA = "\e[1;45m".freeze # Set the terminal's background ANSI color to bright magenta.
|
256
|
+
ON_BRIGHT_CYAN = "\e[1;46m".freeze # Set the terminal's background ANSI color to bright cyan.
|
257
|
+
ON_BRIGHT_WHITE = "\e[1;47m".freeze # Set the terminal's background ANSI color to bright white.
|
258
|
+
|
242
259
|
end # ColorScheme
|
243
260
|
|
244
261
|
# setup the default color scheme
|
@@ -34,7 +34,10 @@ module Logging
|
|
34
34
|
extend self
|
35
35
|
|
36
36
|
# The name used to retrieve the MDC from thread-local storage.
|
37
|
-
NAME =
|
37
|
+
NAME = :logging_mapped_diagnostic_context
|
38
|
+
|
39
|
+
# The name used to retrieve the MDC stack from thread-local storage.
|
40
|
+
STACK_NAME = :logging_mapped_diagnostic_context_stack
|
38
41
|
|
39
42
|
# Public: Put a context value as identified with the key parameter into
|
40
43
|
# the current thread's context map.
|
@@ -45,7 +48,8 @@ module Logging
|
|
45
48
|
# Returns the value.
|
46
49
|
#
|
47
50
|
def []=( key, value )
|
48
|
-
|
51
|
+
clear_context
|
52
|
+
peek.store(key.to_s, value)
|
49
53
|
end
|
50
54
|
|
51
55
|
# Public: Get the context value identified with the key parameter.
|
@@ -67,9 +71,52 @@ module Logging
|
|
67
71
|
# present.
|
68
72
|
#
|
69
73
|
def delete( key )
|
70
|
-
|
74
|
+
clear_context
|
75
|
+
peek.delete(key.to_s)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Public: Add all the key/value pairs from the given hash to the current
|
79
|
+
# mapped diagnostic context. The keys will be converted to strings.
|
80
|
+
# Existing keys of the same name will be overwritten.
|
81
|
+
#
|
82
|
+
# hash - The Hash of values to add to the current context.
|
83
|
+
#
|
84
|
+
# Returns this context.
|
85
|
+
#
|
86
|
+
def update( hash )
|
87
|
+
clear_context
|
88
|
+
sanitize(hash, peek)
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# Public: Push a new Hash of key/value pairs onto the stack of contexts.
|
93
|
+
#
|
94
|
+
# hash - The Hash of values to push onto the context stack.
|
95
|
+
#
|
96
|
+
# Returns this context.
|
97
|
+
# Raises an ArgumentError if hash is not a Hash.
|
98
|
+
#
|
99
|
+
def push( hash )
|
100
|
+
clear_context
|
101
|
+
stack << sanitize(hash)
|
102
|
+
self
|
71
103
|
end
|
72
104
|
|
105
|
+
# Public: Remove the most recently pushed Hash from the stack of contexts.
|
106
|
+
# If no contexts have been pushed then no action will be taken. The
|
107
|
+
# default context cannot be popped off the stack; please use the `clear`
|
108
|
+
# method if you want to remove all key/value pairs from the context.
|
109
|
+
#
|
110
|
+
# Returns nil or the Hash removed from the stack.
|
111
|
+
#
|
112
|
+
def pop
|
113
|
+
return unless Thread.current[STACK_NAME]
|
114
|
+
return unless stack.length > 1
|
115
|
+
clear_context
|
116
|
+
stack.pop
|
117
|
+
end
|
118
|
+
|
119
|
+
|
73
120
|
# Public: Clear all mapped diagnostic information if any. This method is
|
74
121
|
# useful in cases where the same thread can be potentially used over and
|
75
122
|
# over in different unrelated contexts.
|
@@ -77,7 +124,8 @@ module Logging
|
|
77
124
|
# Returns the MappedDiagnosticContext.
|
78
125
|
#
|
79
126
|
def clear
|
80
|
-
|
127
|
+
clear_context
|
128
|
+
Thread.current[STACK_NAME] = nil
|
81
129
|
self
|
82
130
|
end
|
83
131
|
|
@@ -92,24 +140,90 @@ module Logging
|
|
92
140
|
def inherit( obj )
|
93
141
|
case obj
|
94
142
|
when Hash
|
95
|
-
Thread.current[
|
143
|
+
Thread.current[STACK_NAME] = [obj.dup]
|
96
144
|
when Thread
|
97
145
|
return if Thread.current == obj
|
98
146
|
Thread.exclusive {
|
99
|
-
|
147
|
+
if obj[STACK_NAME]
|
148
|
+
hash = flatten(obj[STACK_NAME])
|
149
|
+
Thread.current[STACK_NAME] = [hash]
|
150
|
+
end
|
100
151
|
}
|
101
152
|
end
|
102
153
|
|
103
154
|
self
|
104
155
|
end
|
105
156
|
|
106
|
-
# Returns the Hash acting as the storage for this
|
157
|
+
# Returns the Hash acting as the storage for this MappedDiagnosticContext.
|
107
158
|
# A new storage Hash is created for each Thread running in the
|
108
159
|
# application.
|
109
160
|
#
|
110
161
|
def context
|
111
|
-
Thread.current[NAME]
|
162
|
+
c = Thread.current[NAME]
|
163
|
+
return c unless c.nil?
|
164
|
+
|
165
|
+
return Thread.current[NAME] = {} unless Thread.current[STACK_NAME]
|
166
|
+
|
167
|
+
Thread.current[NAME] = flatten(stack)
|
168
|
+
end
|
169
|
+
|
170
|
+
# Returns the stack of Hash objects that are storing the diagnostic
|
171
|
+
# context information. This stack is guarnteed to always contain at least
|
172
|
+
# one Hash.
|
173
|
+
#
|
174
|
+
def stack
|
175
|
+
Thread.current[STACK_NAME] ||= [{}]
|
112
176
|
end
|
177
|
+
|
178
|
+
# Returns the most current Hash from the stack of contexts.
|
179
|
+
#
|
180
|
+
def peek
|
181
|
+
stack.last
|
182
|
+
end
|
183
|
+
|
184
|
+
# Remove the flattened context.
|
185
|
+
#
|
186
|
+
def clear_context
|
187
|
+
Thread.current[NAME] = nil
|
188
|
+
self
|
189
|
+
end
|
190
|
+
|
191
|
+
# Given a Hash convert all keys into Strings. The values are not altered
|
192
|
+
# in any way. The converted keys and their values are stored in the target
|
193
|
+
# Hash if provided. Otherwise a new Hash is created and returned.
|
194
|
+
#
|
195
|
+
# hash - The Hash of values to push onto the context stack.
|
196
|
+
# target - The target Hash to store the key value pairs.
|
197
|
+
#
|
198
|
+
# Returns a new Hash with all keys converted to Strings.
|
199
|
+
# Raises an ArgumentError if hash is not a Hash.
|
200
|
+
#
|
201
|
+
def sanitize( hash, target = {} )
|
202
|
+
unless Hash === hash
|
203
|
+
raise ArgumentError, "Expecting a Hash but received a #{hash.class.name}"
|
204
|
+
end
|
205
|
+
|
206
|
+
hash.each { |k,v| target[k.to_s] = v }
|
207
|
+
return target
|
208
|
+
end
|
209
|
+
|
210
|
+
# Given an Array of Hash objects, flatten all the key/value pairs from the
|
211
|
+
# Hash objects in the ary into a single Hash. The flattening occurs left
|
212
|
+
# to right. So that the key/value in the very last Hash overrides any
|
213
|
+
# other key from the previous Hash objcts.
|
214
|
+
#
|
215
|
+
# ary - An Array of Hash objects.
|
216
|
+
#
|
217
|
+
# Returns a Hash.
|
218
|
+
#
|
219
|
+
def flatten( ary )
|
220
|
+
return ary.first.dup if ary.length == 1
|
221
|
+
|
222
|
+
hash = {}
|
223
|
+
ary.each { |h| hash.update h }
|
224
|
+
return hash
|
225
|
+
end
|
226
|
+
|
113
227
|
end # MappedDiagnosticContext
|
114
228
|
|
115
229
|
|
@@ -154,7 +268,7 @@ module Logging
|
|
154
268
|
extend self
|
155
269
|
|
156
270
|
# The name used to retrieve the NDC from thread-local storage.
|
157
|
-
NAME =
|
271
|
+
NAME = :logging_nested_diagnostic_context
|
158
272
|
|
159
273
|
# Public: Push new diagnostic context information for the current thread.
|
160
274
|
# The contents of the message parameter is determined solely by the
|
@@ -166,9 +280,16 @@ module Logging
|
|
166
280
|
#
|
167
281
|
def push( message )
|
168
282
|
context.push(message)
|
283
|
+
if block_given?
|
284
|
+
begin
|
285
|
+
yield
|
286
|
+
ensure
|
287
|
+
context.pop
|
288
|
+
end
|
289
|
+
end
|
169
290
|
self
|
170
291
|
end
|
171
|
-
|
292
|
+
alias_method :<<, :push
|
172
293
|
|
173
294
|
# Public: Clients should call this method before leaving a diagnostic
|
174
295
|
# context. The returned value is the last pushed message. If no
|
@@ -199,7 +320,7 @@ module Logging
|
|
199
320
|
# Returns the NestedDiagnosticContext.
|
200
321
|
#
|
201
322
|
def clear
|
202
|
-
|
323
|
+
Thread.current[NAME] = nil
|
203
324
|
self
|
204
325
|
end
|
205
326
|
|
@@ -262,8 +383,9 @@ module Logging
|
|
262
383
|
if all
|
263
384
|
Thread.exclusive {
|
264
385
|
Thread.list.each { |thread|
|
265
|
-
thread[MappedDiagnosticContext::NAME]
|
266
|
-
thread[NestedDiagnosticContext::NAME]
|
386
|
+
thread[MappedDiagnosticContext::NAME] = nil if thread[MappedDiagnosticContext::NAME]
|
387
|
+
thread[NestedDiagnosticContext::NAME] = nil if thread[NestedDiagnosticContext::NAME]
|
388
|
+
thread[MappedDiagnosticContext::STACK_NAME] = nil if thread[MappedDiagnosticContext::STACK_NAME]
|
267
389
|
}
|
268
390
|
}
|
269
391
|
else
|
@@ -283,7 +405,7 @@ class Thread
|
|
283
405
|
|
284
406
|
%w[new start fork].each do |m|
|
285
407
|
class_eval <<-__, __FILE__, __LINE__
|
286
|
-
|
408
|
+
alias_method :_orig_#{m}, :#{m}
|
287
409
|
private :_orig_#{m}
|
288
410
|
def #{m}( *a, &b )
|
289
411
|
create_with_logging_context(:_orig_#{m}, *a ,&b)
|
@@ -309,14 +431,17 @@ class Thread
|
|
309
431
|
def create_with_logging_context( m, *a, &b )
|
310
432
|
mdc, ndc = nil
|
311
433
|
|
312
|
-
if Thread.current[Logging::MappedDiagnosticContext::
|
313
|
-
mdc =
|
434
|
+
if Thread.current[Logging::MappedDiagnosticContext::STACK_NAME]
|
435
|
+
mdc = Logging::MappedDiagnosticContext.context.dup
|
314
436
|
end
|
315
437
|
|
316
438
|
if Thread.current[Logging::NestedDiagnosticContext::NAME]
|
317
|
-
ndc =
|
439
|
+
ndc = Logging::NestedDiagnosticContext.context.dup
|
318
440
|
end
|
319
441
|
|
442
|
+
# This calls the actual `Thread#new` method to create the Thread instance.
|
443
|
+
# If your memory profiling tool says this method is leaking memory, then
|
444
|
+
# you are leaking Thread instances somewhere.
|
320
445
|
self.send(m, *a) { |*args|
|
321
446
|
Logging::MappedDiagnosticContext.inherit(mdc)
|
322
447
|
Logging::NestedDiagnosticContext.inherit(ndc)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Logging
|
2
|
+
|
3
|
+
# The `Filter` class allows for filtering messages based on event
|
4
|
+
# properties independently of the standard minimum-level restriction.
|
5
|
+
#
|
6
|
+
# All other Filters inherit from this class, and must override the
|
7
|
+
# `allow` method to return the event if it should be allowed into the log.
|
8
|
+
# Otherwise the `allow` method should return `nil`.
|
9
|
+
class Filter
|
10
|
+
|
11
|
+
# Returns the event if it should be allowed into the log. Returns `nil` if
|
12
|
+
# the event should _not_ be allowed into the log. Subclasses should override
|
13
|
+
# this method and provide their own filtering semantics.
|
14
|
+
def allow( event )
|
15
|
+
event
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Logging
|
4
|
+
module Filters
|
5
|
+
|
6
|
+
# The `Level` filter class provides a simple level-based filtering mechanism
|
7
|
+
# that filters messages to only include those from an enumerated list of
|
8
|
+
# levels to log.
|
9
|
+
class Level < ::Logging::Filter
|
10
|
+
|
11
|
+
# Creates a new level filter that will only allow the given _levels_ to
|
12
|
+
# propagate through to the logging destination. The _levels_ should be
|
13
|
+
# given in symbolic form.
|
14
|
+
#
|
15
|
+
# Examples
|
16
|
+
# Logging::Filters::Level.new(:debug, :info)
|
17
|
+
#
|
18
|
+
def initialize( *levels )
|
19
|
+
levels = levels.map { |level| ::Logging::level_num(level) }
|
20
|
+
@levels = Set.new levels
|
21
|
+
end
|
22
|
+
|
23
|
+
def allow( event )
|
24
|
+
@levels.include?(event.level) ? event : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/logging/layout.rb
CHANGED
@@ -34,14 +34,14 @@ class Layout
|
|
34
34
|
default = ::Logging.const_defined?('OBJ_FORMAT') ?
|
35
35
|
::Logging::OBJ_FORMAT : nil
|
36
36
|
|
37
|
-
f = opts.
|
37
|
+
f = opts.fetch(:format_as, default)
|
38
38
|
f = f.intern if f.instance_of? String
|
39
39
|
|
40
40
|
@obj_format = case f
|
41
41
|
when :inspect, :yaml, :json; f
|
42
42
|
else :string end
|
43
43
|
|
44
|
-
b = opts.
|
44
|
+
b = opts.fetch(:backtrace, ::Logging.backtrace)
|
45
45
|
@backtrace = case b
|
46
46
|
when :on, 'on', true; true
|
47
47
|
when :off, 'off', false; false
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'socket'
|
1
2
|
|
2
3
|
module Logging::Layouts
|
3
4
|
|
@@ -39,6 +40,7 @@ module Logging::Layouts
|
|
39
40
|
# was issued.
|
40
41
|
# 'method' Used to output the method name where the logging request
|
41
42
|
# was issued.
|
43
|
+
# 'hostname' Used to output the hostname
|
42
44
|
# 'pid' Used to output the process ID of the currently running
|
43
45
|
# program.
|
44
46
|
# 'millis' Used to output the number of milliseconds elapsed from
|
@@ -102,6 +104,7 @@ module Logging::Layouts
|
|
102
104
|
'file' => 'event.file'.freeze,
|
103
105
|
'line' => 'event.line'.freeze,
|
104
106
|
'method' => 'event.method'.freeze,
|
107
|
+
'hostname' => "'#{Socket.gethostname}'".freeze,
|
105
108
|
'pid' => 'Process.pid'.freeze,
|
106
109
|
'millis' => 'Integer((event.time-@created_at)*1000)'.freeze,
|
107
110
|
'thread_id' => 'Thread.current.object_id'.freeze,
|
@@ -180,8 +183,8 @@ module Logging::Layouts
|
|
180
183
|
def initialize( opts = {} )
|
181
184
|
super
|
182
185
|
@created_at = Time.now
|
183
|
-
@style = opts.
|
184
|
-
self.items = opts.
|
186
|
+
@style = opts.fetch(:style, 'json').to_s.intern
|
187
|
+
self.items = opts.fetch(:items, %w[timestamp level logger message])
|
185
188
|
end
|
186
189
|
|
187
190
|
attr_reader :items
|
@@ -1,14 +1,14 @@
|
|
1
|
-
|
2
1
|
module Logging::Layouts
|
3
2
|
|
4
3
|
# Accessor / Factory for the Pattern layout.
|
5
4
|
#
|
5
|
+
# Returns a new Pattern layout instance
|
6
6
|
def self.pattern( *args )
|
7
7
|
return ::Logging::Layouts::Pattern if args.empty?
|
8
8
|
::Logging::Layouts::Pattern.new(*args)
|
9
9
|
end
|
10
10
|
|
11
|
-
# A flexible layout configurable
|
11
|
+
# A flexible layout configurable via a conversion pattern string.
|
12
12
|
#
|
13
13
|
# The goal of this class is to format a LogEvent and return the results as
|
14
14
|
# a String. The results depend on the conversion pattern.
|
@@ -57,6 +57,7 @@ module Logging::Layouts
|
|
57
57
|
# the log event.
|
58
58
|
# [M] Used to output the method name where the logging request was
|
59
59
|
# issued.
|
60
|
+
# [h] Used to output the hostname
|
60
61
|
# [p] Used to output the process ID of the currently running program.
|
61
62
|
# [r] Used to output the number of milliseconds elapsed from the
|
62
63
|
# construction of the Layout until creation of the log event.
|
@@ -74,7 +75,7 @@ module Logging::Layouts
|
|
74
75
|
# [%] The sequence '%%' outputs a single percent sign.
|
75
76
|
#
|
76
77
|
# The logger name directive 'c' accepts an optional precision that will
|
77
|
-
# only print the rightmost number of
|
78
|
+
# only print the rightmost number of name space identifiers for the logger.
|
78
79
|
# By default the logger name is printed in full. For example, for the
|
79
80
|
# logger name "Foo::Bar::Baz" the pattern %c{2} will output "Bar::Baz".
|
80
81
|
#
|
@@ -150,184 +151,51 @@ module Logging::Layouts
|
|
150
151
|
|
151
152
|
# :stopdoc:
|
152
153
|
|
153
|
-
# Arguments to sprintf keyed to directive letters
|
154
|
-
DIRECTIVE_TABLE = {
|
155
|
-
'c' => 'event.logger'.freeze,
|
156
|
-
'd' => 'format_date(event.time)'.freeze,
|
157
|
-
'F' => 'event.file'.freeze,
|
158
|
-
'l' => '::Logging::LNAMES[event.level]'.freeze,
|
159
|
-
'L' => 'event.line'.freeze,
|
160
|
-
'm' => 'format_obj(event.data)'.freeze,
|
161
|
-
'M' => 'event.method'.freeze,
|
162
|
-
'p' => 'Process.pid'.freeze,
|
163
|
-
'r' => 'Integer((event.time-@created_at)*1000).to_s'.freeze,
|
164
|
-
't' => 'Thread.current.object_id.to_s'.freeze,
|
165
|
-
'T' => 'Thread.current[:name]'.freeze,
|
166
|
-
'X' => :placeholder,
|
167
|
-
'x' => :placeholder,
|
168
|
-
'%' => :placeholder
|
169
|
-
}.freeze
|
170
|
-
|
171
|
-
# Matches the first directive encountered and the stuff around it.
|
172
|
-
#
|
173
|
-
# * $1 is the stuff before directive or "" if not applicable
|
174
|
-
# * $2 is the %#.# match within directive group
|
175
|
-
# * $3 is the directive letter
|
176
|
-
# * $4 is the precision specifier for the logger name
|
177
|
-
# * $5 is the stuff after the directive or "" if not applicable
|
178
|
-
DIRECTIVE_RGXP = %r/([^%]*)(?:(%-?\d*(?:\.\d+)?)([a-zA-Z%])(?:\{([^\}]+)\})?)?(.*)/m
|
179
|
-
|
180
154
|
# default date format
|
181
|
-
ISO8601 = "%Y-%m-%
|
182
|
-
|
183
|
-
# Human name aliases for directives - used for colorization of tokens
|
184
|
-
COLOR_ALIAS_TABLE = {
|
185
|
-
'c' => :logger,
|
186
|
-
'd' => :date,
|
187
|
-
'm' => :message,
|
188
|
-
'p' => :pid,
|
189
|
-
'r' => :time,
|
190
|
-
'T' => :thread,
|
191
|
-
't' => :thread_id,
|
192
|
-
'F' => :file,
|
193
|
-
'L' => :line,
|
194
|
-
'M' => :method,
|
195
|
-
'X' => :mdc,
|
196
|
-
'x' => :ndc
|
197
|
-
}.freeze
|
155
|
+
ISO8601 = "%Y-%m-%dT%H:%M:%S".freeze
|
198
156
|
|
199
157
|
# call-seq:
|
200
|
-
# Pattern.create_date_format_methods(
|
158
|
+
# Pattern.create_date_format_methods( pl )
|
201
159
|
#
|
202
160
|
# This method will create the +date_format+ method in the given Pattern
|
203
|
-
# Layout
|
161
|
+
# Layout _pl_ based on the configured date pattern and/or date method
|
204
162
|
# specified by the user.
|
205
163
|
#
|
206
|
-
def self.create_date_format_methods(
|
164
|
+
def self.create_date_format_methods( pl )
|
207
165
|
code = "undef :format_date if method_defined? :format_date\n"
|
208
166
|
code << "def format_date( time )\n"
|
209
|
-
if
|
210
|
-
if
|
167
|
+
if pl.date_method.nil?
|
168
|
+
if pl.date_pattern =~ %r/%s/
|
211
169
|
code << <<-CODE
|
212
|
-
dp = '#{
|
170
|
+
dp = '#{pl.date_pattern}'.gsub('%s','%06d' % time.usec)
|
213
171
|
time.strftime dp
|
214
172
|
CODE
|
215
173
|
else
|
216
|
-
code << "time.strftime '#{
|
174
|
+
code << "time.strftime '#{pl.date_pattern}'\n"
|
217
175
|
end
|
218
176
|
else
|
219
|
-
code << "time.#{
|
177
|
+
code << "time.#{pl.date_method}\n"
|
220
178
|
end
|
221
179
|
code << "end\n"
|
222
180
|
::Logging.log_internal(0) {code}
|
223
181
|
|
224
|
-
|
182
|
+
pl._meta_eval(code, __FILE__, __LINE__)
|
225
183
|
end
|
226
184
|
|
227
185
|
# call-seq:
|
228
|
-
# Pattern.create_format_method(
|
186
|
+
# Pattern.create_format_method( pl )
|
229
187
|
#
|
230
|
-
# This method will create the
|
231
|
-
# Layout
|
188
|
+
# This method will create the `format` method in the given Pattern
|
189
|
+
# Layout `pl` based on the configured format pattern specified by the
|
232
190
|
# user.
|
233
191
|
#
|
234
|
-
def self.create_format_method(
|
235
|
-
|
236
|
-
|
237
|
-
pattern = pf.pattern.dup
|
238
|
-
color_scheme = pf.color_scheme
|
239
|
-
args = []
|
240
|
-
name_map_count = 0
|
241
|
-
|
242
|
-
while true
|
243
|
-
m = DIRECTIVE_RGXP.match(pattern)
|
244
|
-
format_string << m[1] unless m[1].empty?
|
245
|
-
|
246
|
-
case m[3]
|
247
|
-
when '%'; format_string << '%%'
|
248
|
-
when 'c'
|
249
|
-
fmt = m[2] + 's'
|
250
|
-
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[m[3]]) if color_scheme and !color_scheme.lines?
|
251
|
-
|
252
|
-
format_string << fmt
|
253
|
-
args << DIRECTIVE_TABLE[m[3]].dup
|
254
|
-
if m[4]
|
255
|
-
precision = Integer(m[4]) rescue nil
|
256
|
-
if precision
|
257
|
-
raise ArgumentError, "logger name precision must be an integer greater than zero: #{precision}" unless precision > 0
|
258
|
-
args.last <<
|
259
|
-
".split(::Logging::Repository::PATH_DELIMITER)" \
|
260
|
-
".last(#{m[4]}).join(::Logging::Repository::PATH_DELIMITER)"
|
261
|
-
else
|
262
|
-
format_string << "{#{m[4]}}"
|
263
|
-
end
|
264
|
-
end
|
265
|
-
when 'l'
|
266
|
-
if color_scheme and color_scheme.levels?
|
267
|
-
name_map = ::Logging::LNAMES.map { |name| color_scheme.color(("#{m[2]}s" % name), name) }
|
268
|
-
var = "@name_map_#{name_map_count}"
|
269
|
-
pf.instance_variable_set(var.to_sym, name_map)
|
270
|
-
name_map_count += 1
|
271
|
-
|
272
|
-
format_string << '%s'
|
273
|
-
format_string << "{#{m[4]}}" if m[4]
|
274
|
-
args << "#{var}[event.level]"
|
275
|
-
else
|
276
|
-
format_string << m[2] + 's'
|
277
|
-
format_string << "{#{m[4]}}" if m[4]
|
278
|
-
args << DIRECTIVE_TABLE[m[3]]
|
279
|
-
end
|
280
|
-
|
281
|
-
when 'X'
|
282
|
-
raise ArgumentError, "MDC must have a key reference" unless m[4]
|
283
|
-
fmt = m[2] + 's'
|
284
|
-
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[m[3]]) if color_scheme and !color_scheme.lines?
|
285
|
-
|
286
|
-
format_string << fmt
|
287
|
-
args << "::Logging.mdc['#{m[4]}']"
|
288
|
-
|
289
|
-
when 'x'
|
290
|
-
fmt = m[2] + 's'
|
291
|
-
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[m[3]]) if color_scheme and !color_scheme.lines?
|
292
|
-
|
293
|
-
format_string << fmt
|
294
|
-
separator = m[4].to_s
|
295
|
-
separator = ' ' if separator.empty?
|
296
|
-
args << "::Logging.ndc.context.join('#{separator}')"
|
297
|
-
|
298
|
-
when *DIRECTIVE_TABLE.keys
|
299
|
-
fmt = m[2] + 's'
|
300
|
-
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[m[3]]) if color_scheme and !color_scheme.lines?
|
301
|
-
|
302
|
-
format_string << fmt
|
303
|
-
format_string << "{#{m[4]}}" if m[4]
|
304
|
-
args << DIRECTIVE_TABLE[m[3]]
|
305
|
-
|
306
|
-
when nil; break
|
307
|
-
else
|
308
|
-
raise ArgumentError, "illegal format character - '#{m[3]}'"
|
309
|
-
end
|
310
|
-
|
311
|
-
break if m[5].empty?
|
312
|
-
pattern = m[5]
|
313
|
-
end
|
192
|
+
def self.create_format_method( pl )
|
193
|
+
builder = FormatMethodBuilder.new(pl)
|
194
|
+
code = builder.build_code
|
314
195
|
|
315
|
-
|
196
|
+
::Logging.log_internal(0) { code }
|
316
197
|
|
317
|
-
|
318
|
-
sprintf << format_string
|
319
|
-
sprintf << ', ' + args.join(', ') unless args.empty?
|
320
|
-
sprintf << ")"
|
321
|
-
|
322
|
-
if color_scheme and color_scheme.lines?
|
323
|
-
sprintf = "color_scheme.color(#{sprintf}, ::Logging::LNAMES[event.level])"
|
324
|
-
end
|
325
|
-
|
326
|
-
code = "undef :format if method_defined? :format\n"
|
327
|
-
code << "def format( event )\n#{sprintf}\nend\n"
|
328
|
-
::Logging.log_internal(0) {code}
|
329
|
-
|
330
|
-
pf._meta_eval(code, __FILE__, __LINE__)
|
198
|
+
pl._meta_eval(code, __FILE__, __LINE__)
|
331
199
|
end
|
332
200
|
# :startdoc:
|
333
201
|
|
@@ -353,22 +221,22 @@ module Logging::Layouts
|
|
353
221
|
super
|
354
222
|
@created_at = Time.now
|
355
223
|
|
356
|
-
@date_pattern = opts.
|
357
|
-
@date_method = opts.
|
358
|
-
@date_pattern = ISO8601 if @date_pattern.nil?
|
224
|
+
@date_pattern = opts.fetch(:date_pattern, nil)
|
225
|
+
@date_method = opts.fetch(:date_method, nil)
|
226
|
+
@date_pattern = ISO8601 if @date_pattern.nil? && @date_method.nil?
|
359
227
|
|
360
|
-
@pattern = opts.
|
228
|
+
@pattern = opts.fetch(:pattern,
|
361
229
|
"[%d] %-#{::Logging::MAX_LEVEL_LENGTH}l -- %c : %m\n")
|
362
230
|
|
363
|
-
cs_name = opts.
|
231
|
+
cs_name = opts.fetch(:color_scheme, nil)
|
364
232
|
@color_scheme =
|
365
233
|
case cs_name
|
366
234
|
when false, nil; nil
|
367
235
|
when true; ::Logging::ColorScheme[:default]
|
368
236
|
else ::Logging::ColorScheme[cs_name] end
|
369
237
|
|
370
|
-
|
371
|
-
|
238
|
+
self.class.create_date_format_methods(self)
|
239
|
+
self.class.create_format_method(self)
|
372
240
|
end
|
373
241
|
|
374
242
|
attr_reader :pattern, :date_pattern, :date_method, :color_scheme
|
@@ -409,18 +277,291 @@ module Logging::Layouts
|
|
409
277
|
|
410
278
|
# :stopdoc:
|
411
279
|
|
412
|
-
#
|
413
|
-
# _meta_eval( code )
|
414
|
-
#
|
415
|
-
# Evaluates the given string of _code_ if the singleton class of this
|
280
|
+
# Evaluates the given string of `code` if the singleton class of this
|
416
281
|
# Pattern Layout object.
|
417
282
|
#
|
283
|
+
# Returns this Pattern Layout instance.
|
418
284
|
def _meta_eval( code, file = nil, line = nil )
|
419
285
|
meta = class << self; self end
|
420
286
|
meta.class_eval code, file, line
|
287
|
+
self
|
421
288
|
end
|
422
|
-
# :startdoc:
|
423
289
|
|
424
|
-
|
425
|
-
|
290
|
+
# This class is used to build the `format` method for the Pattern layout. It
|
291
|
+
# parses the user defined pattern and emits Ruby source code (as a string)
|
292
|
+
# that can be `eval`d in the context of the Pattern layout instance.
|
293
|
+
class FormatMethodBuilder
|
294
|
+
# Matches the first directive encountered and the stuff around it.
|
295
|
+
#
|
296
|
+
# * $1 is the stuff before directive or "" if not applicable
|
297
|
+
# * $2 is the %#.# match within directive group
|
298
|
+
# * $3 is the directive letter
|
299
|
+
# * $4 is the precision specifier for the logger name
|
300
|
+
# * $5 is the stuff after the directive or "" if not applicable
|
301
|
+
DIRECTIVE_RGXP = %r/([^%]*)(?:(%-?\d*(?:\.\d+)?)([a-zA-Z%])(?:\{([^\}]+)\})?)?(.*)/m
|
302
|
+
|
303
|
+
# Arguments to sprintf keyed to directive letters
|
304
|
+
DIRECTIVE_TABLE = {
|
305
|
+
'c' => 'event.logger'.freeze,
|
306
|
+
'd' => 'format_date(event.time)'.freeze,
|
307
|
+
'F' => 'event.file'.freeze,
|
308
|
+
'l' => '::Logging::LNAMES[event.level]'.freeze,
|
309
|
+
'L' => 'event.line'.freeze,
|
310
|
+
'm' => 'format_obj(event.data)'.freeze,
|
311
|
+
'M' => 'event.method'.freeze,
|
312
|
+
'h' => "'#{Socket.gethostname}'".freeze,
|
313
|
+
'p' => 'Process.pid'.freeze,
|
314
|
+
'r' => 'Integer((event.time-@created_at)*1000).to_s'.freeze,
|
315
|
+
't' => 'Thread.current.object_id.to_s'.freeze,
|
316
|
+
'T' => 'Thread.current[:name]'.freeze,
|
317
|
+
'X' => :placeholder,
|
318
|
+
'x' => :placeholder,
|
319
|
+
'%' => :placeholder
|
320
|
+
}.freeze
|
321
|
+
|
322
|
+
# Human name aliases for directives - used for colorization of tokens
|
323
|
+
COLOR_ALIAS_TABLE = {
|
324
|
+
'c' => :logger,
|
325
|
+
'd' => :date,
|
326
|
+
'm' => :message,
|
327
|
+
'h' => :hostname,
|
328
|
+
'p' => :pid,
|
329
|
+
'r' => :time,
|
330
|
+
'T' => :thread,
|
331
|
+
't' => :thread_id,
|
332
|
+
'F' => :file,
|
333
|
+
'L' => :line,
|
334
|
+
'M' => :method,
|
335
|
+
'X' => :mdc,
|
336
|
+
'x' => :ndc
|
337
|
+
}.freeze
|
338
|
+
|
339
|
+
attr_reader :layout
|
340
|
+
attr_accessor :pattern
|
341
|
+
attr_reader :color_scheme
|
342
|
+
attr_reader :sprintf_args
|
343
|
+
attr_reader :format_string
|
344
|
+
attr_accessor :name_map_count
|
345
|
+
|
346
|
+
# Creates the format method builder and initializes some variables from
|
347
|
+
# the given Patter layout instance.
|
348
|
+
#
|
349
|
+
# pattern_layout - The Pattern Layout instance
|
350
|
+
#
|
351
|
+
def initialize( pattern_layout )
|
352
|
+
@layout = pattern_layout
|
353
|
+
@pattern = layout.pattern.dup
|
354
|
+
@color_scheme = layout.color_scheme
|
355
|
+
|
356
|
+
@sprintf_args = []
|
357
|
+
@format_string = '"'
|
358
|
+
@name_map_count = 0
|
359
|
+
end
|
360
|
+
|
361
|
+
# Returns `true` if the log messages should be colorized.
|
362
|
+
def colorize?
|
363
|
+
color_scheme && !color_scheme.lines?
|
364
|
+
end
|
365
|
+
|
366
|
+
# Returns `true` if the log messages should be colorized by line.
|
367
|
+
def colorize_lines?
|
368
|
+
color_scheme && color_scheme.lines?
|
369
|
+
end
|
426
370
|
|
371
|
+
# Returns `true` if the log levels have special colorization defined.
|
372
|
+
def colorize_levels?
|
373
|
+
color_scheme && color_scheme.levels?
|
374
|
+
end
|
375
|
+
|
376
|
+
# This method returns a String which can be `eval`d in the context of the
|
377
|
+
# Pattern layout. When it is `eval`d, a `format` method is defined in the
|
378
|
+
# Pattern layout.
|
379
|
+
#
|
380
|
+
# At the heart of the format method is `sprintf`. The conversion pattern
|
381
|
+
# specified in the Pattern layout is parsed and converted into a format
|
382
|
+
# string and corresponding arguments list. The format string and arguments
|
383
|
+
# are then processed by `sprintf` to format log events.
|
384
|
+
#
|
385
|
+
# Returns a Ruby code as a String.
|
386
|
+
def build_code
|
387
|
+
build_format_string
|
388
|
+
|
389
|
+
sprintf = "sprintf("
|
390
|
+
sprintf << format_string
|
391
|
+
sprintf << ', ' + sprintf_args.join(', ') unless sprintf_args.empty?
|
392
|
+
sprintf << ")"
|
393
|
+
|
394
|
+
if colorize_lines?
|
395
|
+
sprintf = "color_scheme.color(#{sprintf}, ::Logging::LNAMES[event.level])"
|
396
|
+
end
|
397
|
+
|
398
|
+
code = "undef :format if method_defined? :format\n"
|
399
|
+
code << "def format( event )\n#{sprintf}\nend\n"
|
400
|
+
end
|
401
|
+
|
402
|
+
# This method builds the format string used by `sprintf` to format log
|
403
|
+
# events. The conversion pattern given by the user is iteratively parsed
|
404
|
+
# by a regular expression into separate format directives. Each directive
|
405
|
+
# builds up the format string and the corresponding arguments list that
|
406
|
+
# will be formatted.
|
407
|
+
#
|
408
|
+
# The actual building of the format string is handled by separate
|
409
|
+
# directive specific methods. Those handlers also populate the arguments
|
410
|
+
# list passed to `sprintf`.
|
411
|
+
#
|
412
|
+
# Returns the format String.
|
413
|
+
def build_format_string
|
414
|
+
while true
|
415
|
+
match = DIRECTIVE_RGXP.match(pattern)
|
416
|
+
_, pre, format, directive, precision, post = *match
|
417
|
+
|
418
|
+
format_string << pre unless pre.empty?
|
419
|
+
|
420
|
+
case directive
|
421
|
+
when '%'; format_string << '%%'
|
422
|
+
when 'c'; handle_logger( format, directive, precision )
|
423
|
+
when 'l'; handle_level( format, directive, precision )
|
424
|
+
when 'X'; handle_mdc( format, directive, precision )
|
425
|
+
when 'x'; handle_ndc( format, directive, precision )
|
426
|
+
|
427
|
+
when *DIRECTIVE_TABLE.keys
|
428
|
+
handle_directives(format, directive, precision)
|
429
|
+
|
430
|
+
when nil; break
|
431
|
+
else
|
432
|
+
raise ArgumentError, "illegal format character - '#{directive}'"
|
433
|
+
end
|
434
|
+
|
435
|
+
break if post.empty?
|
436
|
+
self.pattern = post
|
437
|
+
end
|
438
|
+
|
439
|
+
format_string << '"'
|
440
|
+
end
|
441
|
+
|
442
|
+
# Add the logger name to the `format_string` and the `sprintf_args`. The
|
443
|
+
# `slice` argument is a little interesting - this is the number of logger
|
444
|
+
# name segments to keep. If we have a logger named "Foo::Bar::Baz" and our
|
445
|
+
# `slice` is 2, then "Bar::Baz" will appear in the generated log message.
|
446
|
+
# So the `slice` selects the last two parts of the logger name.
|
447
|
+
#
|
448
|
+
# format - format String
|
449
|
+
# directive - the directive character ('c')
|
450
|
+
# slice - the number of name segments to keep
|
451
|
+
#
|
452
|
+
# Returns nil
|
453
|
+
def handle_logger( format, directive, slice )
|
454
|
+
fmt = format + 's'
|
455
|
+
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize?
|
456
|
+
|
457
|
+
format_string << fmt
|
458
|
+
sprintf_args << DIRECTIVE_TABLE[directive].dup
|
459
|
+
|
460
|
+
if slice
|
461
|
+
numeric = Integer(slice) rescue nil
|
462
|
+
if numeric
|
463
|
+
raise ArgumentError, "logger name slice must be an integer greater than zero: #{numeric}" unless numeric > 0
|
464
|
+
sprintf_args.last <<
|
465
|
+
".split(::Logging::Repository::PATH_DELIMITER)" \
|
466
|
+
".last(#{slice}).join(::Logging::Repository::PATH_DELIMITER)"
|
467
|
+
else
|
468
|
+
format_string << "{#{slice}}"
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
nil
|
473
|
+
end
|
474
|
+
|
475
|
+
# Add the log event level to the `format_string` and the `sprintf_args`.
|
476
|
+
# The color scheme is taken into account when formatting the log event
|
477
|
+
# level.
|
478
|
+
#
|
479
|
+
# format - format String
|
480
|
+
# directive - the directive character ('l')
|
481
|
+
# precision - added back to the format string
|
482
|
+
#
|
483
|
+
# Returns nil
|
484
|
+
def handle_level( format, directive, precision )
|
485
|
+
if colorize_levels?
|
486
|
+
name_map = ::Logging::LNAMES.map { |name| color_scheme.color(("#{format}s" % name), name) }
|
487
|
+
var = "@name_map_#{name_map_count}"
|
488
|
+
layout.instance_variable_set(var.to_sym, name_map)
|
489
|
+
self.name_map_count += 1
|
490
|
+
|
491
|
+
format_string << '%s'
|
492
|
+
format_string << "{#{precision}}" if precision
|
493
|
+
sprintf_args << "#{var}[event.level]"
|
494
|
+
else
|
495
|
+
format_string << format + 's'
|
496
|
+
format_string << "{#{precision}}" if precision
|
497
|
+
sprintf_args << DIRECTIVE_TABLE[directive]
|
498
|
+
end
|
499
|
+
|
500
|
+
nil
|
501
|
+
end
|
502
|
+
|
503
|
+
# Add a Mapped Diagnostic Context to the `format_string` and the
|
504
|
+
# `sprintf_args`. Only one MDC value is added at a time, so this directive
|
505
|
+
# can appear multiple times using various keys.
|
506
|
+
#
|
507
|
+
# format - format String
|
508
|
+
# directive - the directive character ('X')
|
509
|
+
# key - which MDC value to add to the log message
|
510
|
+
#
|
511
|
+
# Returns nil
|
512
|
+
def handle_mdc( format, directive, key )
|
513
|
+
raise ArgumentError, "MDC must have a key reference" unless key
|
514
|
+
fmt = format + 's'
|
515
|
+
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize?
|
516
|
+
|
517
|
+
format_string << fmt
|
518
|
+
sprintf_args << "::Logging.mdc['#{key}']"
|
519
|
+
|
520
|
+
nil
|
521
|
+
end
|
522
|
+
|
523
|
+
# Add a Nested Diagnostic Context to the `format_string` and the
|
524
|
+
# `sprintf_args`. Since the NDC is an Array of values, the directive will
|
525
|
+
# appear only once in the conversion pattern. A `separator` is inserted
|
526
|
+
# between the values in generated log message.
|
527
|
+
#
|
528
|
+
# format - format String
|
529
|
+
# directive - the directive character ('x')
|
530
|
+
# separator - used to separate the values in the NDC array
|
531
|
+
#
|
532
|
+
# Returns nil
|
533
|
+
def handle_ndc( format, directive, separator )
|
534
|
+
fmt = format + 's'
|
535
|
+
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize?
|
536
|
+
|
537
|
+
format_string << fmt
|
538
|
+
separator = separator.to_s
|
539
|
+
separator = ' ' if separator.empty?
|
540
|
+
sprintf_args << "::Logging.ndc.context.join('#{separator}')"
|
541
|
+
|
542
|
+
nil
|
543
|
+
end
|
544
|
+
|
545
|
+
# Handles the rest of the directives; none of these need any special
|
546
|
+
# handling.
|
547
|
+
#
|
548
|
+
# format - format String
|
549
|
+
# directive - the directive character
|
550
|
+
# precision - added back to the format string
|
551
|
+
#
|
552
|
+
# Returns nil
|
553
|
+
def handle_directives( format, directive, precision )
|
554
|
+
fmt = format + 's'
|
555
|
+
fmt = color_scheme.color(fmt, COLOR_ALIAS_TABLE[directive]) if colorize?
|
556
|
+
|
557
|
+
format_string << fmt
|
558
|
+
format_string << "{#{precision}}" if precision
|
559
|
+
sprintf_args << DIRECTIVE_TABLE[directive]
|
560
|
+
|
561
|
+
nil
|
562
|
+
end
|
563
|
+
end
|
564
|
+
# :startdoc:
|
565
|
+
|
566
|
+
end
|
567
|
+
end
|