logging 2.1.0 → 2.2.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 +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://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
|
|