lumberjack 1.2.10 → 1.3.1
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/ARCHITECTURE.md +244 -0
- data/CHANGELOG.md +46 -0
- data/README.md +146 -57
- data/VERSION +1 -1
- data/lib/lumberjack/context.rb +5 -5
- data/lib/lumberjack/device/rolling_log_file.rb +1 -1
- data/lib/lumberjack/device/writer.rb +12 -8
- data/lib/lumberjack/formatter/date_time_formatter.rb +1 -1
- data/lib/lumberjack/formatter/multiply_formatter.rb +25 -0
- data/lib/lumberjack/formatter/redact_formatter.rb +23 -0
- data/lib/lumberjack/formatter/round_formatter.rb +21 -0
- data/lib/lumberjack/formatter/tagged_message.rb +39 -0
- data/lib/lumberjack/formatter.rb +28 -13
- data/lib/lumberjack/log_entry.rb +58 -16
- data/lib/lumberjack/logger.rb +131 -34
- data/lib/lumberjack/rack/context.rb +20 -1
- data/lib/lumberjack/rack/request_id.rb +6 -2
- data/lib/lumberjack/rack/unit_of_work.rb +5 -1
- data/lib/lumberjack/tag_formatter.rb +102 -27
- data/lib/lumberjack/tagged_logger_support.rb +25 -10
- data/lib/lumberjack/tags.rb +1 -7
- data/lib/lumberjack/template.rb +1 -1
- data/lib/lumberjack/utils.rb +133 -0
- data/lib/lumberjack.rb +10 -5
- data/lumberjack.gemspec +2 -2
- metadata +12 -6
data/lib/lumberjack/logger.rb
CHANGED
@@ -21,7 +21,7 @@ module Lumberjack
|
|
21
21
|
# monitoring thread, but its use is highly recommended.
|
22
22
|
#
|
23
23
|
# Each log entry records the log message and severity along with the time it was logged, the
|
24
|
-
# program name, process id, and
|
24
|
+
# program name, process id, and an optional hash of tags. The message will be converted to a string, but
|
25
25
|
# otherwise, it is up to the device how these values are recorded. Messages are converted to strings
|
26
26
|
# using a Formatter associated with the logger.
|
27
27
|
class Logger
|
@@ -36,8 +36,8 @@ module Lumberjack
|
|
36
36
|
# Set the name of the program to attach to log entries.
|
37
37
|
attr_writer :progname
|
38
38
|
|
39
|
-
# The
|
40
|
-
attr_accessor :
|
39
|
+
# The Formatter used only for log entry messages.
|
40
|
+
attr_accessor :message_formatter
|
41
41
|
|
42
42
|
# The TagFormatter used for formatting tags for output
|
43
43
|
attr_accessor :tag_formatter
|
@@ -51,31 +51,30 @@ module Lumberjack
|
|
51
51
|
# If it is :null, it will be a Null device that won't record any output.
|
52
52
|
# Otherwise, it will be assumed to be file path and wrapped in a Device::LogFile class.
|
53
53
|
#
|
54
|
-
# This method can take the following options:
|
55
|
-
#
|
56
|
-
# * :level - The logging level below which messages will be ignored.
|
57
|
-
# * :formatter - The formatter to use for outputting messages to the log.
|
58
|
-
# * :datetime_format - The format to use for log timestamps.
|
59
|
-
# * :tag_formatter - The TagFormatter to use for formatting tags.
|
60
|
-
# * :progname - The name of the program that will be recorded with each log entry.
|
61
|
-
# * :flush_seconds - The maximum number of seconds between flush calls.
|
62
|
-
# * :roll - If the log device is a file path, it will be a Device::DateRollingLogFile if this is set.
|
63
|
-
# * :max_size - If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
|
64
|
-
#
|
65
54
|
# All other options are passed to the device constuctor.
|
66
55
|
#
|
67
56
|
# @param [Lumberjack::Device, Object, Symbol, String] device The device to log to.
|
68
57
|
# @param [Hash] options The options for the logger.
|
58
|
+
# @option options [Integer, Symbol, String] :level The logging level below which messages will be ignored.
|
59
|
+
# @option options [Lumberjack::Formatter] :formatter The formatter to use for outputting messages to the log.
|
60
|
+
# @option options [String] :datetime_format The format to use for log timestamps.
|
61
|
+
# @option options [Lumberjack::Formatter] :message_formatter The MessageFormatter to use for formatting log messages.
|
62
|
+
# @option options [Lumberjack::TagFormatter] :tag_formatter The TagFormatter to use for formatting tags.
|
63
|
+
# @option options [String] :progname The name of the program that will be recorded with each log entry.
|
64
|
+
# @option options [Numeric] :flush_seconds The maximum number of seconds between flush calls.
|
65
|
+
# @option options [Boolean] :roll If the log device is a file path, it will be a Device::DateRollingLogFile if this is set.
|
66
|
+
# @option options [Integer] :max_size If the log device is a file path, it will be a Device::SizeRollingLogFile if this is set.
|
69
67
|
def initialize(device = $stdout, options = {})
|
70
68
|
options = options.dup
|
71
69
|
self.level = options.delete(:level) || INFO
|
72
70
|
self.progname = options.delete(:progname)
|
73
71
|
max_flush_seconds = options.delete(:flush_seconds).to_f
|
74
72
|
|
75
|
-
@
|
73
|
+
@logdev = open_device(device, options) if device
|
76
74
|
self.formatter = (options[:formatter] || Formatter.new)
|
77
|
-
@
|
78
|
-
|
75
|
+
@message_formatter = options[:message_formatter] || Formatter.empty
|
76
|
+
@tag_formatter = options[:tag_formatter] || TagFormatter.new
|
77
|
+
time_format = options[:datetime_format] || options[:time_format]
|
79
78
|
self.datetime_format = time_format if time_format
|
80
79
|
@last_flushed_at = Time.now
|
81
80
|
@silencer = true
|
@@ -85,6 +84,23 @@ module Lumberjack
|
|
85
84
|
create_flusher_thread(max_flush_seconds) if max_flush_seconds > 0
|
86
85
|
end
|
87
86
|
|
87
|
+
# Get the logging device that is used to write log entries.
|
88
|
+
#
|
89
|
+
# @return [Lumberjack::Device] The logging device.
|
90
|
+
def device
|
91
|
+
@logdev
|
92
|
+
end
|
93
|
+
|
94
|
+
# Set the logging device to a new device.
|
95
|
+
#
|
96
|
+
# @param [Lumberjack::Device] device The new logging device.
|
97
|
+
# @return [void]
|
98
|
+
def device=(device)
|
99
|
+
@logdev = if device
|
100
|
+
open_device(device, options)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
88
104
|
# Get the timestamp format on the device if it has one.
|
89
105
|
#
|
90
106
|
# @return [String, nil] The timestamp format or nil if the device doesn't support it.
|
@@ -194,25 +210,30 @@ module Lumberjack
|
|
194
210
|
Thread.current[:lumberjack_logging] = true
|
195
211
|
|
196
212
|
time = Time.now
|
213
|
+
|
197
214
|
message = message.call if message.is_a?(Proc)
|
198
|
-
|
215
|
+
msg_class_formatter = message_formatter&.formatter_for(message.class)
|
216
|
+
if msg_class_formatter
|
217
|
+
message = msg_class_formatter.call(message)
|
218
|
+
elsif formatter
|
219
|
+
message = formatter.format(message)
|
220
|
+
end
|
221
|
+
message_tags = nil
|
222
|
+
if message.is_a?(Formatter::TaggedMessage)
|
223
|
+
message_tags = message.tags
|
224
|
+
message = message.message
|
225
|
+
end
|
226
|
+
|
199
227
|
progname ||= self.progname
|
200
228
|
|
201
229
|
current_tags = self.tags
|
202
230
|
tags = nil unless tags.is_a?(Hash)
|
203
|
-
|
204
|
-
|
205
|
-
else
|
206
|
-
tags = if tags.nil?
|
207
|
-
current_tags.dup
|
208
|
-
else
|
209
|
-
current_tags.merge(Tags.stringify_keys(tags))
|
210
|
-
end
|
211
|
-
end
|
231
|
+
tags = merge_tags(current_tags, tags)
|
232
|
+
tags = merge_tags(tags, message_tags) if message_tags
|
212
233
|
tags = Tags.expand_runtime_values(tags)
|
213
234
|
tags = tag_formatter.format(tags) if tag_formatter
|
214
235
|
|
215
|
-
entry = LogEntry.new(time, severity, message, progname,
|
236
|
+
entry = LogEntry.new(time, severity, message, progname, Process.pid, tags)
|
216
237
|
write_to_device(entry)
|
217
238
|
ensure
|
218
239
|
Thread.current[:lumberjack_logging] = nil
|
@@ -441,6 +462,14 @@ module Lumberjack
|
|
441
462
|
end
|
442
463
|
end
|
443
464
|
|
465
|
+
# Provided for compatibility with ActiveSupport::LoggerThreadSafeLevel to temporarily set the log level.
|
466
|
+
#
|
467
|
+
# @param [Integer, String, Symbol] level The log level to use inside the block.
|
468
|
+
# @return [Object] The result of the block.
|
469
|
+
def log_at(level, &block)
|
470
|
+
silence(level, &block)
|
471
|
+
end
|
472
|
+
|
444
473
|
# Set the program name that is associated with log messages. If a block
|
445
474
|
# is given, the program name will be valid only within the block.
|
446
475
|
#
|
@@ -462,10 +491,11 @@ module Lumberjack
|
|
462
491
|
end
|
463
492
|
|
464
493
|
# Set a hash of tags on logger. If a block is given, the tags will only be set
|
465
|
-
# for the duration of the block.
|
466
|
-
#
|
467
|
-
#
|
468
|
-
#
|
494
|
+
# for the duration of the block. Otherwise the tags will be applied on the current
|
495
|
+
# logger context for the duration of that context.
|
496
|
+
#
|
497
|
+
# If there is no block or context, the tags will be applied to the global context.
|
498
|
+
# This behavior is deprecated. Use the `tag_globally` method to set global tags instead.
|
469
499
|
#
|
470
500
|
# @param [Hash] tags The tags to set.
|
471
501
|
# @return [void]
|
@@ -479,11 +509,31 @@ module Lumberjack
|
|
479
509
|
thread_tags.merge!(tags)
|
480
510
|
nil
|
481
511
|
else
|
482
|
-
|
483
|
-
|
512
|
+
Lumberjack::Utils.deprecated("Lumberjack::Logger#tag", "Lumberjack::Logger#tag must be called with a block or inside a context block. In version 2.0 it will no longer be used for setting global tags. Use Lumberjack::Logger#tag_globally instead.") do
|
513
|
+
tag_globally(tags)
|
514
|
+
end
|
484
515
|
end
|
485
516
|
end
|
486
517
|
|
518
|
+
# Set up a context block for the logger. All tags added within the block will be cleared when
|
519
|
+
# the block exits.
|
520
|
+
#
|
521
|
+
def context(&block)
|
522
|
+
thread_tags = thread_local_value(:lumberjack_logger_tags)&.dup
|
523
|
+
thread_tags ||= {}
|
524
|
+
push_thread_local_value(:lumberjack_logger_tags, thread_tags, &block)
|
525
|
+
end
|
526
|
+
|
527
|
+
# Add global tags to the logger that will appear on all log entries.
|
528
|
+
#
|
529
|
+
# @param [Hash] tags The tags to set.
|
530
|
+
# @return [void]
|
531
|
+
def tag_globally(tags)
|
532
|
+
tags = Tags.stringify_keys(tags)
|
533
|
+
@tags.merge!(tags)
|
534
|
+
nil
|
535
|
+
end
|
536
|
+
|
487
537
|
# Remove a tag from the current tag context. If this is called inside a block to a
|
488
538
|
# call to `tag`, the tags will only be removed for the duration of that block. Otherwise
|
489
539
|
# they will be removed from the global tags.
|
@@ -513,6 +563,31 @@ module Lumberjack
|
|
513
563
|
tags
|
514
564
|
end
|
515
565
|
|
566
|
+
# Get the value of a tag by name from the current tag context.
|
567
|
+
#
|
568
|
+
# @param [String, Symbol] name The name of the tag to get.
|
569
|
+
# @return [Object, nil] The value of the tag or nil if the tag does not exist.
|
570
|
+
def tag_value(name)
|
571
|
+
all_tags = tags
|
572
|
+
return nil if tags.empty?
|
573
|
+
|
574
|
+
name = name.join(".") if name.is_a?(Array)
|
575
|
+
name = name.to_s
|
576
|
+
return all_tags[name] if all_tags.include?(name)
|
577
|
+
|
578
|
+
flattened_tags = Lumberjack::Utils.flatten_tags(all_tags)
|
579
|
+
return flattened_tags[name] if flattened_tags.include?(name)
|
580
|
+
|
581
|
+
flattened_tags.keys.select { |key| key.include?(".") }.each do |key|
|
582
|
+
parts = key.split(".")
|
583
|
+
while (subkey = parts.pop)
|
584
|
+
flattened_tags[parts.join(".")] = {subkey => flattened_tags[(parts + [subkey]).join(".")]}
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
flattened_tags[name]
|
589
|
+
end
|
590
|
+
|
516
591
|
# Remove all tags on the current logger and logging context within a block.
|
517
592
|
# You can still set new block scoped tags within theuntagged block and provide
|
518
593
|
# tags on individual log methods.
|
@@ -533,6 +608,14 @@ module Lumberjack
|
|
533
608
|
end
|
534
609
|
end
|
535
610
|
|
611
|
+
# Return true if the thread is currently in a Lumberjack::Context block.
|
612
|
+
# When the logger is in a context block, tagging will only apply to that block.
|
613
|
+
#
|
614
|
+
# @return [Boolean]
|
615
|
+
def in_tag_context?
|
616
|
+
!!thread_local_value(:lumberjack_logger_tags)
|
617
|
+
end
|
618
|
+
|
536
619
|
private
|
537
620
|
|
538
621
|
# Dereference arguments to log calls so we can have methods with compatibility with ::Logger
|
@@ -560,6 +643,20 @@ module Lumberjack
|
|
560
643
|
add_entry(severity, message, progname, tags)
|
561
644
|
end
|
562
645
|
|
646
|
+
# Merge a tags hash into an existing tags hash.
|
647
|
+
def merge_tags(current_tags, tags)
|
648
|
+
if current_tags.nil? || current_tags.empty?
|
649
|
+
tags = Tags.stringify_keys(tags) unless tags.nil?
|
650
|
+
else
|
651
|
+
tags = if tags.nil?
|
652
|
+
current_tags.dup
|
653
|
+
else
|
654
|
+
current_tags.merge(Tags.stringify_keys(tags))
|
655
|
+
end
|
656
|
+
end
|
657
|
+
tags
|
658
|
+
end
|
659
|
+
|
563
660
|
# Set a local value for a thread tied to this object.
|
564
661
|
def set_thread_local_value(name, value) # :nodoc:
|
565
662
|
values = Thread.current[name]
|
@@ -3,16 +3,35 @@
|
|
3
3
|
module Lumberjack
|
4
4
|
module Rack
|
5
5
|
# Middleware to create a global context for Lumberjack for the scope of a rack request.
|
6
|
+
#
|
7
|
+
# The optional `env_tags` parameter can be used to set up global tags from the request
|
8
|
+
# environment. This is useful for setting tags that are relevant to the entire request
|
9
|
+
# like the request id, host, etc.
|
6
10
|
class Context
|
7
|
-
|
11
|
+
# @param [Object] app The rack application.
|
12
|
+
# @param [Hash] env_tags A hash of tags to set from the request environment. If a tag value is
|
13
|
+
# a Proc, it will be called with the request `env` as an argument to allow dynamic tag values
|
14
|
+
# based on request data.
|
15
|
+
def initialize(app, env_tags = nil)
|
8
16
|
@app = app
|
17
|
+
@env_tags = env_tags
|
9
18
|
end
|
10
19
|
|
11
20
|
def call(env)
|
12
21
|
Lumberjack.context do
|
22
|
+
apply_tags(env) if @env_tags
|
13
23
|
@app.call(env)
|
14
24
|
end
|
15
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def apply_tags(env)
|
30
|
+
tags = @env_tags.transform_values do |value|
|
31
|
+
value.is_a?(Proc) ? value.call(env) : value
|
32
|
+
end
|
33
|
+
Lumberjack.tag(tags)
|
34
|
+
end
|
16
35
|
end
|
17
36
|
end
|
18
37
|
end
|
@@ -5,12 +5,16 @@ module Lumberjack
|
|
5
5
|
# Support for using the Rails ActionDispatch request id in the log.
|
6
6
|
# The format is expected to be a random UUID and only the first chunk is used for terseness
|
7
7
|
# if the abbreviated argument is true.
|
8
|
+
#
|
9
|
+
# @deprecated Use tags instead of request id for unit of work. Will be removed in version 2.0.
|
8
10
|
class RequestId
|
9
11
|
REQUEST_ID = "action_dispatch.request_id"
|
10
12
|
|
11
13
|
def initialize(app, abbreviated = false)
|
12
|
-
|
13
|
-
|
14
|
+
Lumberjack::Utils.deprecated("Lumberjack::Rack::RequestId", "Lumberjack::Rack::RequestId will be removed in version 2.0") do
|
15
|
+
@app = app
|
16
|
+
@abbreviated = abbreviated
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
def call(env)
|
@@ -2,9 +2,13 @@
|
|
2
2
|
|
3
3
|
module Lumberjack
|
4
4
|
module Rack
|
5
|
+
# @deprecated Use the Lumberjack::Rack::Context middleware instead to set a global tag
|
6
|
+
# with an identifier to tie log entries together in a unit of work. Will be removed in version 2.0.
|
5
7
|
class UnitOfWork
|
6
8
|
def initialize(app)
|
7
|
-
|
9
|
+
Lumberjack::Utils.deprecated("Lumberjack::Rack::UnitOfWork", "Lumberjack::Rack::UnitOfWork will be removed in version 2.0") do
|
10
|
+
@app = app
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
14
|
def call(env)
|
@@ -11,13 +11,14 @@ module Lumberjack
|
|
11
11
|
class TagFormatter
|
12
12
|
def initialize
|
13
13
|
@formatters = {}
|
14
|
+
@class_formatters = {}
|
14
15
|
@default_formatter = nil
|
15
16
|
end
|
16
17
|
|
17
18
|
# Add a default formatter applied to all tag values. This can either be a Lumberjack::Formatter
|
18
19
|
# or an object that responds to `call` or a block.
|
19
20
|
#
|
20
|
-
# @param [Lumberjack::Formatter, #call, nil]
|
21
|
+
# @param formatter [Lumberjack::Formatter, #call, nil] The formatter to use.
|
21
22
|
# If this is nil, then the block will be used as the formatter.
|
22
23
|
# @return [Lumberjack::TagFormatter] self
|
23
24
|
def default(formatter = nil, &block)
|
@@ -35,22 +36,37 @@ module Lumberjack
|
|
35
36
|
self
|
36
37
|
end
|
37
38
|
|
38
|
-
# Add a formatter for specific tag names. This can either be a Lumberjack::Formatter
|
39
|
-
# or an object that responds to `call` or a block. The
|
40
|
-
#
|
39
|
+
# Add a formatter for specific tag names or object classes. This can either be a Lumberjack::Formatter
|
40
|
+
# or an object that responds to `call` or a block. The formatter will be applied if it matches either a tag name
|
41
|
+
# or if the tag value is an instance of a registered class. Tag name formatters will take precedence
|
42
|
+
# over class formatters. The default formatter will not be applied to a value if a tag formatter
|
43
|
+
# is applied to it.
|
41
44
|
#
|
42
|
-
#
|
43
|
-
#
|
45
|
+
# Name formatters can be applied to nested hashes using dot syntax. For example, if you add a formatter
|
46
|
+
# for "foo.bar", it will be applied to the value of the "bar" key in the "foo" tag if that value is a hash.
|
47
|
+
#
|
48
|
+
# Class formatters will be applied recursively to nested hashes and arrays.
|
49
|
+
#
|
50
|
+
# @param names_or_classes [String, Module, Array<String, Module>] The tag names or object classes
|
51
|
+
# to apply the formatter to.
|
52
|
+
# @param formatter [Lumberjack::Formatter, #call, nil] The formatter to use.
|
44
53
|
# If this is nil, then the block will be used as the formatter.
|
45
54
|
# @return [Lumberjack::TagFormatter] self
|
46
|
-
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# tag_formatter.add("password", &:redact)
|
58
|
+
def add(names_or_classes, formatter = nil, &block)
|
47
59
|
formatter ||= block
|
48
60
|
formatter = dereference_formatter(formatter)
|
49
61
|
if formatter.nil?
|
50
62
|
remove(key)
|
51
63
|
else
|
52
|
-
Array(
|
53
|
-
|
64
|
+
Array(names_or_classes).each do |key|
|
65
|
+
if key.is_a?(Module)
|
66
|
+
@class_formatters[key] = formatter
|
67
|
+
else
|
68
|
+
@formatters[key.to_s] = formatter
|
69
|
+
end
|
54
70
|
end
|
55
71
|
end
|
56
72
|
self
|
@@ -58,11 +74,15 @@ module Lumberjack
|
|
58
74
|
|
59
75
|
# Remove formatters for specific tag names. The default formatter will still be applied.
|
60
76
|
#
|
61
|
-
# @param [String, Array<String>]
|
77
|
+
# @param names_or_classes [String, Module, Array<String, Module>] The tag names or classes to remove the formatter from.
|
62
78
|
# @return [Lumberjack::TagFormatter] self
|
63
|
-
def remove(
|
64
|
-
Array(
|
65
|
-
|
79
|
+
def remove(names_or_classes)
|
80
|
+
Array(names_or_classes).each do |key|
|
81
|
+
if key.is_a?(Module)
|
82
|
+
@class_formatters.delete(key)
|
83
|
+
else
|
84
|
+
@formatters.delete(key.to_s)
|
85
|
+
end
|
66
86
|
end
|
67
87
|
self
|
68
88
|
end
|
@@ -78,28 +98,66 @@ module Lumberjack
|
|
78
98
|
|
79
99
|
# Format a hash of tags using the formatters
|
80
100
|
#
|
81
|
-
# @param [Hash]
|
101
|
+
# @param tags [Hash] The tags to format.
|
82
102
|
# @return [Hash] The formatted tags.
|
83
103
|
def format(tags)
|
84
104
|
return nil if tags.nil?
|
85
|
-
if @default_formatter.nil? &&
|
86
|
-
tags
|
105
|
+
if @default_formatter.nil? && @formatters.empty? && @class_formatters.empty?
|
106
|
+
return tags
|
107
|
+
end
|
108
|
+
|
109
|
+
formated_tags(tags)
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def formated_tags(tags, skip_classes: nil, prefix: nil)
|
115
|
+
formatted = {}
|
116
|
+
|
117
|
+
tags.each do |name, value|
|
118
|
+
name = name.to_s
|
119
|
+
formatted[name] = formatted_tag_value(name, value, skip_classes: skip_classes, prefix: prefix)
|
120
|
+
end
|
121
|
+
|
122
|
+
formatted
|
123
|
+
end
|
124
|
+
|
125
|
+
def formatted_tag_value(name, value, skip_classes: nil, prefix: nil)
|
126
|
+
prefixed_name = prefix ? "#{prefix}#{name}" : name
|
127
|
+
using_class_formatter = false
|
128
|
+
|
129
|
+
formatter = @formatters[prefixed_name]
|
130
|
+
if formatter.nil? && (skip_classes.nil? || !skip_classes.include?(value.class))
|
131
|
+
formatter = class_formatter(value.class)
|
132
|
+
using_class_formatter = true if formatter
|
133
|
+
end
|
134
|
+
|
135
|
+
formatter ||= @default_formatter
|
136
|
+
|
137
|
+
formatted_value = if formatter.is_a?(Lumberjack::Formatter)
|
138
|
+
formatter.format(value)
|
139
|
+
elsif formatter.respond_to?(:call)
|
140
|
+
formatter.call(value)
|
87
141
|
else
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
142
|
+
value
|
143
|
+
end
|
144
|
+
|
145
|
+
if formatted_value.is_a?(Enumerable)
|
146
|
+
skip_classes ||= []
|
147
|
+
skip_classes << value.class if using_class_formatter
|
148
|
+
sub_prefix = "#{prefixed_name}."
|
149
|
+
|
150
|
+
formatted_value = if formatted_value.is_a?(Hash)
|
151
|
+
formated_tags(formatted_value, skip_classes: skip_classes, prefix: sub_prefix)
|
152
|
+
else
|
153
|
+
formatted_value.collect do |item|
|
154
|
+
formatted_tag_value(nil, item, skip_classes: skip_classes, prefix: sub_prefix)
|
95
155
|
end
|
96
|
-
formatted[name.to_s] = value
|
97
156
|
end
|
98
|
-
formatted
|
99
157
|
end
|
100
|
-
end
|
101
158
|
|
102
|
-
|
159
|
+
formatted_value
|
160
|
+
end
|
103
161
|
|
104
162
|
def dereference_formatter(formatter)
|
105
163
|
if formatter.is_a?(TaggedLoggerSupport::Formatter)
|
@@ -111,5 +169,22 @@ module Lumberjack
|
|
111
169
|
formatter
|
112
170
|
end
|
113
171
|
end
|
172
|
+
|
173
|
+
def class_formatter(klass)
|
174
|
+
formatter = @class_formatters[klass]
|
175
|
+
return formatter if formatter
|
176
|
+
|
177
|
+
formatters = @class_formatters.select { |k, _| klass <= k }
|
178
|
+
return formatters.values.first if formatters.length <= 1
|
179
|
+
|
180
|
+
superclass = klass.superclass
|
181
|
+
while superclass
|
182
|
+
formatter = formatters[superclass]
|
183
|
+
return formatter if formatter
|
184
|
+
superclass = superclass.superclass
|
185
|
+
end
|
186
|
+
|
187
|
+
formatters.values.first
|
188
|
+
end
|
114
189
|
end
|
115
190
|
end
|
@@ -38,15 +38,19 @@ module Lumberjack
|
|
38
38
|
end
|
39
39
|
|
40
40
|
# Compatibility with ActiveSupport::TaggedLogging which only supports adding tags as strings.
|
41
|
-
#
|
42
|
-
# Otherwise it will be appended to a list named "tagged".
|
41
|
+
# Tags will be added to the "tagged" key in the logger's tags hash as an array.
|
43
42
|
def tagged(*tags, &block)
|
44
|
-
|
45
|
-
tags.flatten.
|
46
|
-
|
47
|
-
|
43
|
+
tagged_values = Array(tag_value("tagged"))
|
44
|
+
flattened_tags = tags.flatten.collect(&:to_s).reject do |tag|
|
45
|
+
tag.respond_to?(:blank?) ? tag.blank? : tag.empty?
|
46
|
+
end
|
47
|
+
tagged_values += flattened_tags unless flattened_tags.empty?
|
48
|
+
|
49
|
+
if block || in_tag_context?
|
50
|
+
tag("tagged" => tagged_values, &block)
|
51
|
+
else
|
52
|
+
tag_globally("tagged" => tagged_values)
|
48
53
|
end
|
49
|
-
tag(tag_hash, &block)
|
50
54
|
end
|
51
55
|
|
52
56
|
def push_tags(*tags)
|
@@ -54,13 +58,24 @@ module Lumberjack
|
|
54
58
|
end
|
55
59
|
|
56
60
|
def pop_tags(size = 1)
|
57
|
-
tagged_values =
|
61
|
+
tagged_values = tag_value("tagged")
|
62
|
+
return unless tagged_values.is_a?(Array)
|
63
|
+
|
58
64
|
tagged_values = ((tagged_values.size > size) ? tagged_values[0, tagged_values.size - size] : nil)
|
59
|
-
|
65
|
+
|
66
|
+
if in_tag_context?
|
67
|
+
tag("tagged" => tagged_values)
|
68
|
+
else
|
69
|
+
tag_globally("tagged" => tagged_values)
|
70
|
+
end
|
60
71
|
end
|
61
72
|
|
62
73
|
def clear_tags!
|
63
|
-
|
74
|
+
if in_tag_context?
|
75
|
+
tag("tagged" => nil)
|
76
|
+
else
|
77
|
+
tag_globally("tagged" => nil)
|
78
|
+
end
|
64
79
|
end
|
65
80
|
end
|
66
81
|
end
|
data/lib/lumberjack/tags.rb
CHANGED
@@ -12,14 +12,8 @@ module Lumberjack
|
|
12
12
|
return nil if hash.nil?
|
13
13
|
if hash.keys.all? { |key| key.is_a?(String) }
|
14
14
|
hash
|
15
|
-
elsif hash.respond_to?(:transform_keys)
|
16
|
-
hash.transform_keys(&:to_s)
|
17
15
|
else
|
18
|
-
|
19
|
-
hash.each do |key, value|
|
20
|
-
copy[key.to_s] = value
|
21
|
-
end
|
22
|
-
copy
|
16
|
+
hash.transform_keys(&:to_s)
|
23
17
|
end
|
24
18
|
end
|
25
19
|
|
data/lib/lumberjack/template.rb
CHANGED
@@ -99,7 +99,7 @@ module Lumberjack
|
|
99
99
|
return [nil] * (tag_vars.size + 1) if tags.nil? || tags.size == 0
|
100
100
|
|
101
101
|
tags_string = +""
|
102
|
-
tags.each do |name, value|
|
102
|
+
Lumberjack::Utils.flatten_tags(tags).each do |name, value|
|
103
103
|
unless value.nil? || tag_vars.include?(name)
|
104
104
|
value = value.to_s
|
105
105
|
value = value.gsub(Lumberjack::LINE_SEPARATOR, " ") if value.include?(Lumberjack::LINE_SEPARATOR)
|