logging 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -6
- data/History.txt +15 -0
- data/LICENSE +22 -0
- data/README.md +20 -41
- data/examples/layouts.rb +1 -1
- data/examples/lazy.rb +1 -1
- data/examples/reusing_layouts.rb +51 -0
- data/lib/logging.rb +52 -3
- data/lib/logging/appender.rb +2 -2
- data/lib/logging/appenders/console.rb +1 -1
- data/lib/logging/appenders/rolling_file.rb +11 -1
- data/lib/logging/color_scheme.rb +1 -1
- data/lib/logging/diagnostic_context.rb +99 -74
- data/lib/logging/layout.rb +46 -1
- data/lib/logging/layouts/parseable.rb +7 -4
- data/lib/logging/layouts/pattern.rb +4 -2
- data/lib/logging/log_event.rb +18 -11
- data/lib/logging/logger.rb +2 -2
- data/lib/logging/rails_compat.rb +4 -13
- data/lib/logging/version.rb +1 -1
- data/logging.gemspec +32 -33
- data/test/layouts/test_json.rb +13 -0
- data/test/layouts/test_pattern.rb +15 -2
- data/test/layouts/test_yaml.rb +14 -0
- data/test/test_layout.rb +40 -0
- data/test/test_log_event.rb +8 -0
- data/test/test_logging.rb +28 -0
- data/test/test_mapped_diagnostic_context.rb +15 -6
- data/test/test_nested_diagnostic_context.rb +6 -1
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee30a5922d46012d8fc4e14db5cc86ea7dce9c6a
|
4
|
+
data.tar.gz: 7183a4f01f0dd1000ab86d05c8b40e605dbb4b10
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 377702172ae965d27c082acd60914e0f3420a0e0bdfc5d981ac3cfad7c8f3bf46095007511075b6a9db9225963911967d3d63989a3ee6dc42588269092796a72
|
7
|
+
data.tar.gz: 1a6f33f20259879ca8cc9adcbd9a3bfb14c44f03a15311711f11ff4bf98edfd9821000e8b9afcb5401080a693e391bb83e56bd0055e1eedcbba6ce7ba4a92f2b
|
data/.travis.yml
CHANGED
data/History.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
== 2.2.0 / 2017-03-09
|
2
|
+
|
3
|
+
Enhancements
|
4
|
+
- diagnostic context inheritance is now optional [PR #160]
|
5
|
+
- add support for setting a UTC offset [PR #157]
|
6
|
+
- setting a basepath for call tracing [PR #154]
|
7
|
+
|
8
|
+
Bug Fixes
|
9
|
+
- use thread-local variables for diagnostic contexts [PR #162]
|
10
|
+
- replace `Fixnum` with `Integer` [PR #161]
|
11
|
+
- fixed a race condition in the rolling file appender [PR #151]
|
12
|
+
|
13
|
+
Deprecations
|
14
|
+
- dropped Ruby 1.9 support
|
15
|
+
|
1
16
|
== 2.1.0 / 2016-03-13
|
2
17
|
|
3
18
|
Enhancements
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2007-2016 Tim Pease
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
'Software'), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
19
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
20
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
21
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
22
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
## Logging
|
2
|
-
by Tim Pease [![](https://secure.travis-ci.org/TwP/logging.
|
2
|
+
by Tim Pease [![](https://secure.travis-ci.org/TwP/logging.svg)](https://travis-ci.org/TwP/logging)
|
3
3
|
|
4
4
|
* [Homepage](http://rubygems.org/gems/logging)
|
5
5
|
* [Github Project](https://github.com/TwP/logging)
|
6
6
|
|
7
7
|
### Description
|
8
8
|
|
9
|
-
Logging is a flexible logging library for use in Ruby programs based on the
|
9
|
+
**Logging** is a flexible logging library for use in Ruby programs based on the
|
10
10
|
design of Java's log4j library. It features a hierarchical logging system,
|
11
11
|
custom level names, multiple output destinations per log event, custom
|
12
12
|
formatting, and more.
|
@@ -82,23 +82,23 @@ class SecondClass
|
|
82
82
|
end
|
83
83
|
```
|
84
84
|
|
85
|
-
There are many more examples in the [examples folder](
|
86
|
-
|
87
|
-
|
88
|
-
* [simple.rb](
|
89
|
-
* [rspec_integration.rb](
|
90
|
-
* [loggers.rb](
|
91
|
-
* [classes.rb](
|
92
|
-
* [hierarchies.rb](
|
93
|
-
* [names.rb](
|
94
|
-
* [lazy.rb](
|
95
|
-
* [appenders.rb](
|
96
|
-
* [layouts.rb](
|
97
|
-
* [
|
98
|
-
* [
|
99
|
-
* [
|
100
|
-
* [fork.rb](
|
101
|
-
* [mdc.rb](
|
85
|
+
There are many more examples in the [examples folder](/examples) of the logging
|
86
|
+
package. The recommended reading order is the following:
|
87
|
+
|
88
|
+
* [simple.rb](/examples/simple.rb)
|
89
|
+
* [rspec_integration.rb](/examples/rspec_integration.rb)
|
90
|
+
* [loggers.rb](/examples/loggers.rb)
|
91
|
+
* [classes.rb](/examples/classes.rb)
|
92
|
+
* [hierarchies.rb](/examples/hierarchies.rb)
|
93
|
+
* [names.rb](/examples/names.rb)
|
94
|
+
* [lazy.rb](/examples/lazy.rb)
|
95
|
+
* [appenders.rb](/examples/appenders.rb)
|
96
|
+
* [layouts.rb](/examples/layouts.rb)
|
97
|
+
* [reusing_layouts.rb](/examples/reusing_layouts.rb)
|
98
|
+
* [formatting.rb](/examples/formatting.rb)
|
99
|
+
* [colorization.rb](/examples/colorization.rb)
|
100
|
+
* [fork.rb](/examples/fork.rb)
|
101
|
+
* [mdc.rb](/examples/mdc.rb)
|
102
102
|
|
103
103
|
### Extending
|
104
104
|
|
@@ -135,25 +135,4 @@ After this is done you can rake `rake -T` to see the available rake tasks.
|
|
135
135
|
|
136
136
|
### License
|
137
137
|
|
138
|
-
The MIT License
|
139
|
-
|
140
|
-
Copyright (c) 2015 Tim Pease
|
141
|
-
|
142
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
143
|
-
a copy of this software and associated documentation files (the
|
144
|
-
'Software'), to deal in the Software without restriction, including
|
145
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
146
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
147
|
-
permit persons to whom the Software is furnished to do so, subject to
|
148
|
-
the following conditions:
|
149
|
-
|
150
|
-
The above copyright notice and this permission notice shall be
|
151
|
-
included in all copies or substantial portions of the Software.
|
152
|
-
|
153
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
154
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
155
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
156
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
157
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
158
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
159
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
138
|
+
The MIT License - see the [LICENSE](/LICENSE) file for the full text.
|
data/examples/layouts.rb
CHANGED
@@ -33,7 +33,7 @@
|
|
33
33
|
log.level = :debug
|
34
34
|
|
35
35
|
log.debug "a very nice little debug message"
|
36
|
-
log.info "things are operating
|
36
|
+
log.info "things are operating normally"
|
37
37
|
log.warn "this is your last warning"
|
38
38
|
log.error StandardError.new("something went horribly wrong")
|
39
39
|
log.fatal "I Die!"
|
data/examples/lazy.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# It happens sometimes that it is very expensive to construct a logging
|
4
4
|
# message; for example, if a large object structure has to be traversed
|
5
|
-
# during
|
5
|
+
# during execution of an `object.to_s` method. It would be convenient to
|
6
6
|
# delay creation of the message until the log event actually takes place.
|
7
7
|
#
|
8
8
|
# For example, with a logger configured only to show WARN messages and higher,
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
#
|
3
|
+
# The formatting of log messages is controlled by the layout given to the
|
4
|
+
# appender. By default all appenders use the Basic layout. It's pretty
|
5
|
+
# basic. However, a more sophisticated Pattern layout can be used or one of
|
6
|
+
# the Parseable layouts -- JSON or YAML.
|
7
|
+
#
|
8
|
+
# The available layouts are:
|
9
|
+
#
|
10
|
+
# Logging.layouts.basic
|
11
|
+
# Logging.layouts.pattern
|
12
|
+
# Logging.layouts.json
|
13
|
+
# Logging.layouts.yaml
|
14
|
+
#
|
15
|
+
# After you configure a layout, you can reuse that layout among different
|
16
|
+
# appenders if you so choose. This enables you to have some the style of log
|
17
|
+
# output being sent to multiple destinations.
|
18
|
+
#
|
19
|
+
# We will store a Layout instance in a local variable, and then pass that
|
20
|
+
# instance to each appender.
|
21
|
+
#
|
22
|
+
|
23
|
+
require 'logging'
|
24
|
+
|
25
|
+
# create our pattern layout instance
|
26
|
+
layout = Logging.layouts.pattern \
|
27
|
+
:pattern => '[%d] %-5l %c: %m\n',
|
28
|
+
:date_pattern => '%Y-%m-%d %H:%M:%S'
|
29
|
+
|
30
|
+
# only show "info" or higher messages on STDOUT using our layout
|
31
|
+
Logging.appenders.stdout \
|
32
|
+
:level => :info,
|
33
|
+
:layout => layout
|
34
|
+
|
35
|
+
# send all log events to the development log (including debug) using our layout
|
36
|
+
Logging.appenders.rolling_file \
|
37
|
+
'development.log',
|
38
|
+
:age => 'daily',
|
39
|
+
:layout => layout
|
40
|
+
|
41
|
+
log = Logging.logger['Foo::Bar']
|
42
|
+
log.add_appenders 'stdout', 'development.log'
|
43
|
+
log.level = :debug
|
44
|
+
|
45
|
+
log.debug "a very nice little debug message"
|
46
|
+
log.info "things are operating normally"
|
47
|
+
log.warn "this is your last warning"
|
48
|
+
log.error StandardError.new("something went horribly wrong")
|
49
|
+
log.fatal "I Die!"
|
50
|
+
|
51
|
+
# :startdoc:
|
data/lib/logging.rb
CHANGED
@@ -95,9 +95,9 @@ module Logging
|
|
95
95
|
layout = ::Logging::Layouts::Pattern.new(l_opts)
|
96
96
|
|
97
97
|
a_opts = Hash.new
|
98
|
-
a_opts[:size] = size if size.
|
98
|
+
a_opts[:size] = size if size.is_a?(Integer)
|
99
99
|
a_opts[:age] = age if age.instance_of?(String)
|
100
|
-
a_opts[:keep] = keep if keep.
|
100
|
+
a_opts[:keep] = keep if keep.is_a?(Integer)
|
101
101
|
a_opts[:filename] = dev if dev.instance_of?(String)
|
102
102
|
a_opts[:layout] = layout
|
103
103
|
a_opts.merge! opts
|
@@ -311,6 +311,53 @@ module Logging
|
|
311
311
|
end
|
312
312
|
end
|
313
313
|
|
314
|
+
# Set the default UTC offset used when formatting time values sent to the
|
315
|
+
# appenders. If left unset, the default local time zone will be used for
|
316
|
+
# time values. This method accepts the `utc_offset` format supported by the
|
317
|
+
# `Time#localtime` method in Ruby.
|
318
|
+
#
|
319
|
+
# Passing "UTC" or `0` as the UTC offset will cause all times to be reported
|
320
|
+
# in the UTC timezone.
|
321
|
+
#
|
322
|
+
# Logging.utc_offset = "-07:00" # Mountain Standard Time in North America
|
323
|
+
# Logging.utc_offset = "+01:00" # Central European Time
|
324
|
+
# Logging.utc_offset = "UTC" # UTC
|
325
|
+
# Logging.utc_offset = 0 # UTC
|
326
|
+
#
|
327
|
+
def utc_offset=( value )
|
328
|
+
@utc_offset = case value
|
329
|
+
when nil; nil
|
330
|
+
when "UTC", "GMT", 0; 0
|
331
|
+
else
|
332
|
+
Time.now.localtime(value)
|
333
|
+
value
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
attr_reader :utc_offset
|
338
|
+
|
339
|
+
# Used to define a `basepath` that will be removed from filenames when
|
340
|
+
# reporting tracing information for log events. Normally you would set this
|
341
|
+
# to the root of your project:
|
342
|
+
#
|
343
|
+
# Logging.basepath = "/home/user/nifty_project"
|
344
|
+
#
|
345
|
+
# Or if you are in a Rails environment:
|
346
|
+
#
|
347
|
+
# Logging.basepath = Rails.root.to_s
|
348
|
+
#
|
349
|
+
# The basepath is expanded to a full path with trailing slashes removed.
|
350
|
+
# This setting will be cleared by a call to `Logging.reset`.
|
351
|
+
def basepath=( path )
|
352
|
+
if path.nil? || path.to_s.empty?
|
353
|
+
@basepath = nil
|
354
|
+
else
|
355
|
+
@basepath = File.expand_path(path)
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
attr_reader :basepath
|
360
|
+
|
314
361
|
# Returns the library path for the module. If any arguments are given,
|
315
362
|
# they will be joined to the end of the library path using
|
316
363
|
# <tt>File.join</tt>.
|
@@ -405,7 +452,7 @@ module Logging
|
|
405
452
|
# to false. It uses its own appender to send messages to stderr.
|
406
453
|
#
|
407
454
|
def show_configuration( io = STDOUT, logger = 'root', indent = 0 )
|
408
|
-
logger = ::Logging::Logger[logger] unless ::Logging::Logger
|
455
|
+
logger = ::Logging::Logger[logger] unless logger.is_a?(::Logging::Logger)
|
409
456
|
|
410
457
|
io << logger._dump_configuration(indent)
|
411
458
|
|
@@ -466,8 +513,10 @@ module Logging
|
|
466
513
|
LEVELS.clear
|
467
514
|
LNAMES.clear
|
468
515
|
remove_instance_variable :@backtrace if defined? @backtrace
|
516
|
+
remove_instance_variable :@basepath if defined? @basepath
|
469
517
|
remove_const :MAX_LEVEL_LENGTH if const_defined? :MAX_LEVEL_LENGTH
|
470
518
|
remove_const :OBJ_FORMAT if const_defined? :OBJ_FORMAT
|
519
|
+
self.utc_offset = nil
|
471
520
|
self
|
472
521
|
end
|
473
522
|
|
data/lib/logging/appender.rb
CHANGED
@@ -114,7 +114,7 @@ class Appender
|
|
114
114
|
#
|
115
115
|
# Set the level for this appender; log events below this level will be
|
116
116
|
# ignored by this appender. The level can be either a +String+, a
|
117
|
-
# +Symbol+, or
|
117
|
+
# +Symbol+, or an +Integer+. An +ArgumentError+ is raised if this is not
|
118
118
|
# the case.
|
119
119
|
#
|
120
120
|
# There are two special levels -- "all" and "off". The former will
|
@@ -138,7 +138,7 @@ class Appender
|
|
138
138
|
def level=( level )
|
139
139
|
lvl = case level
|
140
140
|
when String, Symbol; ::Logging::level_num(level)
|
141
|
-
when
|
141
|
+
when Integer; level
|
142
142
|
when nil; 0
|
143
143
|
else
|
144
144
|
raise ArgumentError,
|
@@ -24,7 +24,7 @@ module Logging::Appenders
|
|
24
24
|
name = self.class.name.split("::").last.downcase
|
25
25
|
io = Object.const_get(name.upcase)
|
26
26
|
|
27
|
-
opts =
|
27
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
28
28
|
name = args.shift unless args.empty?
|
29
29
|
|
30
30
|
opts[:encoding] = io.external_encoding if io.respond_to? :external_encoding
|
@@ -141,6 +141,15 @@ module Logging::Appenders
|
|
141
141
|
@roller.copy_file
|
142
142
|
end
|
143
143
|
|
144
|
+
# Returns the modification time of the copy file if one exists. Otherwise
|
145
|
+
# returns `nil`.
|
146
|
+
def copy_file_mtime
|
147
|
+
return nil unless ::File.exist?(copy_file)
|
148
|
+
::File.mtime(copy_file)
|
149
|
+
rescue Errno::ENOENT
|
150
|
+
nil
|
151
|
+
end
|
152
|
+
|
144
153
|
# Write the given _event_ to the log file. The log file will be rolled
|
145
154
|
# if the maximum file size is exceeded or if the file is older than the
|
146
155
|
# maximum age.
|
@@ -166,7 +175,8 @@ module Logging::Appenders
|
|
166
175
|
|
167
176
|
# Returns +true+ if the log file needs to be rolled.
|
168
177
|
def roll_required?
|
169
|
-
|
178
|
+
mtime = copy_file_mtime
|
179
|
+
return false if mtime && (Time.now - mtime) < 180
|
170
180
|
|
171
181
|
# check if max size has been exceeded
|
172
182
|
s = @size ? ::File.size(filename) > @size : false
|
data/lib/logging/color_scheme.rb
CHANGED
@@ -40,7 +40,7 @@ module Logging
|
|
40
40
|
# Store a color scheme by name.
|
41
41
|
#
|
42
42
|
def []=( name, value )
|
43
|
-
raise ArgumentError, "Silly! That's not a ColorSchmeme!" unless ColorScheme
|
43
|
+
raise ArgumentError, "Silly! That's not a ColorSchmeme!" unless value.is_a?(ColorScheme)
|
44
44
|
@color_schemes[name.to_s] = value
|
45
45
|
end
|
46
46
|
|
@@ -110,7 +110,7 @@ module Logging
|
|
110
110
|
# Returns nil or the Hash removed from the stack.
|
111
111
|
#
|
112
112
|
def pop
|
113
|
-
return unless Thread.current
|
113
|
+
return unless Thread.current.thread_variable_get(STACK_NAME)
|
114
114
|
return unless stack.length > 1
|
115
115
|
clear_context
|
116
116
|
stack.pop
|
@@ -125,7 +125,7 @@ module Logging
|
|
125
125
|
#
|
126
126
|
def clear
|
127
127
|
clear_context
|
128
|
-
Thread.current
|
128
|
+
Thread.current.thread_variable_set(STACK_NAME, nil)
|
129
129
|
self
|
130
130
|
end
|
131
131
|
|
@@ -140,15 +140,14 @@ module Logging
|
|
140
140
|
def inherit( obj )
|
141
141
|
case obj
|
142
142
|
when Hash
|
143
|
-
Thread.current
|
143
|
+
Thread.current.thread_variable_set(STACK_NAME, [obj.dup])
|
144
144
|
when Thread
|
145
145
|
return if Thread.current == obj
|
146
|
-
DIAGNOSTIC_MUTEX.synchronize
|
147
|
-
if obj
|
148
|
-
|
149
|
-
Thread.current[STACK_NAME] = [hash]
|
146
|
+
DIAGNOSTIC_MUTEX.synchronize do
|
147
|
+
if hash = obj.thread_variable_get(STACK_NAME)
|
148
|
+
Thread.current.thread_variable_set(STACK_NAME, [flatten(hash)])
|
150
149
|
end
|
151
|
-
|
150
|
+
end
|
152
151
|
end
|
153
152
|
|
154
153
|
self
|
@@ -159,12 +158,18 @@ module Logging
|
|
159
158
|
# application.
|
160
159
|
#
|
161
160
|
def context
|
162
|
-
c = Thread.current
|
163
|
-
return c unless c.nil?
|
161
|
+
c = Thread.current.thread_variable_get(NAME)
|
164
162
|
|
165
|
-
|
163
|
+
if c.nil?
|
164
|
+
c = if Thread.current.thread_variable_get(STACK_NAME)
|
165
|
+
flatten(stack)
|
166
|
+
else
|
167
|
+
Hash.new
|
168
|
+
end
|
169
|
+
Thread.current.thread_variable_set(NAME, c)
|
170
|
+
end
|
166
171
|
|
167
|
-
|
172
|
+
return c
|
168
173
|
end
|
169
174
|
|
170
175
|
# Returns the stack of Hash objects that are storing the diagnostic
|
@@ -172,7 +177,12 @@ module Logging
|
|
172
177
|
# one Hash.
|
173
178
|
#
|
174
179
|
def stack
|
175
|
-
Thread.current
|
180
|
+
s = Thread.current.thread_variable_get(STACK_NAME)
|
181
|
+
if s.nil?
|
182
|
+
s = [{}]
|
183
|
+
Thread.current.thread_variable_set(STACK_NAME, s)
|
184
|
+
end
|
185
|
+
return s
|
176
186
|
end
|
177
187
|
|
178
188
|
# Returns the most current Hash from the stack of contexts.
|
@@ -184,7 +194,7 @@ module Logging
|
|
184
194
|
# Remove the flattened context.
|
185
195
|
#
|
186
196
|
def clear_context
|
187
|
-
Thread.current
|
197
|
+
Thread.current.thread_variable_set(NAME, nil)
|
188
198
|
self
|
189
199
|
end
|
190
200
|
|
@@ -199,7 +209,7 @@ module Logging
|
|
199
209
|
# Raises an ArgumentError if hash is not a Hash.
|
200
210
|
#
|
201
211
|
def sanitize( hash, target = {} )
|
202
|
-
unless Hash
|
212
|
+
unless hash.is_a?(Hash)
|
203
213
|
raise ArgumentError, "Expecting a Hash but received a #{hash.class.name}"
|
204
214
|
end
|
205
215
|
|
@@ -320,7 +330,7 @@ module Logging
|
|
320
330
|
# Returns the NestedDiagnosticContext.
|
321
331
|
#
|
322
332
|
def clear
|
323
|
-
Thread.current
|
333
|
+
Thread.current.thread_variable_set(NAME, nil)
|
324
334
|
self
|
325
335
|
end
|
326
336
|
|
@@ -335,12 +345,12 @@ module Logging
|
|
335
345
|
def inherit( obj )
|
336
346
|
case obj
|
337
347
|
when Array
|
338
|
-
Thread.current
|
348
|
+
Thread.current.thread_variable_set(NAME, obj.dup)
|
339
349
|
when Thread
|
340
350
|
return if Thread.current == obj
|
341
|
-
DIAGNOSTIC_MUTEX.synchronize
|
342
|
-
Thread.current
|
343
|
-
|
351
|
+
DIAGNOSTIC_MUTEX.synchronize do
|
352
|
+
Thread.current.thread_variable_set(NAME, obj.thread_variable_get(NAME).dup) if obj.thread_variable_get(NAME)
|
353
|
+
end
|
344
354
|
end
|
345
355
|
|
346
356
|
self
|
@@ -351,7 +361,12 @@ module Logging
|
|
351
361
|
# running in the application.
|
352
362
|
#
|
353
363
|
def context
|
354
|
-
Thread.current
|
364
|
+
c = Thread.current.thread_variable_get(NAME)
|
365
|
+
if c.nil?
|
366
|
+
c = Array.new
|
367
|
+
Thread.current.thread_variable_set(NAME, c)
|
368
|
+
end
|
369
|
+
return c
|
355
370
|
end
|
356
371
|
end # NestedDiagnosticContext
|
357
372
|
|
@@ -381,13 +396,13 @@ module Logging
|
|
381
396
|
#
|
382
397
|
def self.clear_diagnostic_contexts( all = false )
|
383
398
|
if all
|
384
|
-
DIAGNOSTIC_MUTEX.synchronize
|
385
|
-
Thread.list.each
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
399
|
+
DIAGNOSTIC_MUTEX.synchronize do
|
400
|
+
Thread.list.each do |t|
|
401
|
+
t.thread_variable_set(MappedDiagnosticContext::NAME, nil) if t.thread_variable?(MappedDiagnosticContext::NAME)
|
402
|
+
t.thread_variable_set(NestedDiagnosticContext::NAME, nil) if t.thread_variable?(NestedDiagnosticContext::NAME)
|
403
|
+
t.thread_variable_set(MappedDiagnosticContext::STACK_NAME, nil) if t.thread_variable?(MappedDiagnosticContext::STACK_NAME)
|
404
|
+
end
|
405
|
+
end
|
391
406
|
else
|
392
407
|
MappedDiagnosticContext.clear
|
393
408
|
NestedDiagnosticContext.clear
|
@@ -397,61 +412,71 @@ module Logging
|
|
397
412
|
end
|
398
413
|
|
399
414
|
DIAGNOSTIC_MUTEX = Mutex.new
|
400
|
-
|
401
|
-
end # module Logging
|
402
|
-
|
415
|
+
end
|
403
416
|
|
404
417
|
# :stopdoc:
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
end
|
415
|
-
__
|
416
|
-
end
|
418
|
+
Logging::INHERIT_CONTEXT =
|
419
|
+
if ENV.key?("LOGGING_INHERIT_CONTEXT")
|
420
|
+
case ENV["LOGGING_INHERIT_CONTEXT"].downcase
|
421
|
+
when 'false', 'no', '0'; false
|
422
|
+
when false, nil; false
|
423
|
+
else true end
|
424
|
+
else
|
425
|
+
true
|
426
|
+
end
|
417
427
|
|
418
|
-
|
428
|
+
if Logging::INHERIT_CONTEXT
|
429
|
+
class Thread
|
430
|
+
class << self
|
419
431
|
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
# parent thread does not exist in the binding associated with the block
|
429
|
-
# being executed in the child thread. The same is true for the parent
|
430
|
-
# thread's mdc and ndc. If any of those references end up in the binding,
|
431
|
-
# then they cannot be garbage collected until the child thread exits.
|
432
|
-
#
|
433
|
-
def create_with_logging_context( m, *a, &b )
|
434
|
-
mdc, ndc = nil
|
435
|
-
|
436
|
-
if Thread.current[Logging::MappedDiagnosticContext::STACK_NAME]
|
437
|
-
mdc = Logging::MappedDiagnosticContext.context.dup
|
432
|
+
%w[new start fork].each do |m|
|
433
|
+
class_eval <<-__, __FILE__, __LINE__
|
434
|
+
alias_method :_orig_#{m}, :#{m}
|
435
|
+
private :_orig_#{m}
|
436
|
+
def #{m}( *a, &b )
|
437
|
+
create_with_logging_context(:_orig_#{m}, *a ,&b)
|
438
|
+
end
|
439
|
+
__
|
438
440
|
end
|
439
441
|
|
440
|
-
|
441
|
-
|
442
|
+
private
|
443
|
+
|
444
|
+
# In order for the diagnostic contexts to behave properly we need to
|
445
|
+
# inherit state from the parent thread. The only way I have found to do
|
446
|
+
# this in Ruby is to override `new` and capture the contexts from the
|
447
|
+
# parent Thread at the time the child Thread is created. The code below does
|
448
|
+
# just this. If there is a more idiomatic way of accomplishing this in Ruby,
|
449
|
+
# please let me know!
|
450
|
+
#
|
451
|
+
# Also, great care is taken in this code to ensure that a reference to the
|
452
|
+
# parent thread does not exist in the binding associated with the block
|
453
|
+
# being executed in the child thread. The same is true for the parent
|
454
|
+
# thread's mdc and ndc. If any of those references end up in the binding,
|
455
|
+
# then they cannot be garbage collected until the child thread exits.
|
456
|
+
#
|
457
|
+
def create_with_logging_context( m, *a, &b )
|
458
|
+
mdc, ndc = nil
|
459
|
+
|
460
|
+
if Thread.current.thread_variable_get(Logging::MappedDiagnosticContext::STACK_NAME)
|
461
|
+
mdc = Logging::MappedDiagnosticContext.context.dup
|
462
|
+
end
|
463
|
+
|
464
|
+
if Thread.current.thread_variable_get(Logging::NestedDiagnosticContext::NAME)
|
465
|
+
ndc = Logging::NestedDiagnosticContext.context.dup
|
466
|
+
end
|
467
|
+
|
468
|
+
# This calls the actual `Thread#new` method to create the Thread instance.
|
469
|
+
# If your memory profiling tool says this method is leaking memory, then
|
470
|
+
# you are leaking Thread instances somewhere.
|
471
|
+
self.send(m, *a) { |*args|
|
472
|
+
Logging::MappedDiagnosticContext.inherit(mdc)
|
473
|
+
Logging::NestedDiagnosticContext.inherit(ndc)
|
474
|
+
b.call(*args)
|
475
|
+
}
|
442
476
|
end
|
443
477
|
|
444
|
-
# This calls the actual `Thread#new` method to create the Thread instance.
|
445
|
-
# If your memory profiling tool says this method is leaking memory, then
|
446
|
-
# you are leaking Thread instances somewhere.
|
447
|
-
self.send(m, *a) { |*args|
|
448
|
-
Logging::MappedDiagnosticContext.inherit(mdc)
|
449
|
-
Logging::NestedDiagnosticContext.inherit(ndc)
|
450
|
-
b.call(*args)
|
451
|
-
}
|
452
478
|
end
|
453
|
-
|
454
479
|
end
|
455
|
-
end
|
480
|
+
end
|
456
481
|
# :startdoc:
|
457
482
|
|