lumberjack 1.2.9 → 1.3.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/ARCHITECTURE.md +244 -0
- data/CHANGELOG.md +78 -2
- data/README.md +176 -58
- data/VERSION +1 -1
- data/lib/lumberjack/context.rb +5 -5
- data/lib/lumberjack/device/date_rolling_log_file.rb +1 -1
- data/lib/lumberjack/device/log_file.rb +1 -1
- data/lib/lumberjack/device/multi.rb +1 -1
- data/lib/lumberjack/device/null.rb +1 -1
- data/lib/lumberjack/device/rolling_log_file.rb +2 -2
- data/lib/lumberjack/device/size_rolling_log_file.rb +1 -1
- data/lib/lumberjack/device/writer.rb +13 -9
- data/lib/lumberjack/device.rb +1 -1
- data/lib/lumberjack/formatter/date_time_formatter.rb +2 -2
- data/lib/lumberjack/formatter/exception_formatter.rb +2 -2
- data/lib/lumberjack/formatter/id_formatter.rb +1 -1
- data/lib/lumberjack/formatter/inspect_formatter.rb +1 -1
- data/lib/lumberjack/formatter/multiply_formatter.rb +25 -0
- data/lib/lumberjack/formatter/object_formatter.rb +1 -1
- data/lib/lumberjack/formatter/pretty_print_formatter.rb +1 -1
- data/lib/lumberjack/formatter/redact_formatter.rb +23 -0
- data/lib/lumberjack/formatter/round_formatter.rb +21 -0
- data/lib/lumberjack/formatter/string_formatter.rb +1 -1
- data/lib/lumberjack/formatter/strip_formatter.rb +1 -1
- data/lib/lumberjack/formatter/structured_formatter.rb +1 -1
- data/lib/lumberjack/formatter/tagged_message.rb +39 -0
- data/lib/lumberjack/formatter/truncate_formatter.rb +1 -1
- data/lib/lumberjack/formatter.rb +29 -14
- data/lib/lumberjack/log_entry.rb +25 -15
- data/lib/lumberjack/logger.rb +132 -40
- data/lib/lumberjack/rack/context.rb +21 -2
- data/lib/lumberjack/rack/request_id.rb +7 -3
- data/lib/lumberjack/rack/unit_of_work.rb +6 -2
- data/lib/lumberjack/rack.rb +1 -1
- data/lib/lumberjack/severity.rb +13 -1
- data/lib/lumberjack/tag_formatter.rb +102 -27
- data/lib/lumberjack/tagged_logger_support.rb +6 -1
- data/lib/lumberjack/tags.rb +1 -7
- data/lib/lumberjack/template.rb +3 -3
- data/lib/lumberjack/utils.rb +133 -0
- data/lib/lumberjack.rb +12 -6
- data/lumberjack.gemspec +2 -2
- metadata +12 -6
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lumberjack
|
4
|
+
class Formatter
|
5
|
+
# This class can be used as the return value from a formatter `call` method to
|
6
|
+
# extract additional tags from an object being logged. This can be useful when there
|
7
|
+
# using structured logging to include important metadata in the log message.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # Automatically add tags with error details when logging an exception.
|
11
|
+
# logger.add_formatter(Exception, ->(e) {
|
12
|
+
# Lumberjack::Formatter::TaggedMessage.new(e.message, {
|
13
|
+
# error: {
|
14
|
+
# message: e.message,
|
15
|
+
# class: e.class.name,
|
16
|
+
# trace: e.backtrace
|
17
|
+
# }
|
18
|
+
# })
|
19
|
+
# })
|
20
|
+
class TaggedMessage
|
21
|
+
attr_reader :message, :tags
|
22
|
+
|
23
|
+
# @param [Formatter] formatter The formatter to apply the transformation to.
|
24
|
+
# @param [Proc] transform The transformation function to apply to the formatted string.
|
25
|
+
def initialize(message, tags)
|
26
|
+
@message = message
|
27
|
+
@tags = tags || {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_s
|
31
|
+
inspect
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
{message: @message, tags: @tags}.inspect
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/lumberjack/formatter.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Lumberjack
|
4
4
|
# This class controls the conversion of log entry messages into a loggable format. This allows you
|
@@ -16,12 +16,16 @@ module Lumberjack
|
|
16
16
|
require_relative "formatter/exception_formatter"
|
17
17
|
require_relative "formatter/id_formatter"
|
18
18
|
require_relative "formatter/inspect_formatter"
|
19
|
+
require_relative "formatter/multiply_formatter"
|
19
20
|
require_relative "formatter/object_formatter"
|
20
21
|
require_relative "formatter/pretty_print_formatter"
|
22
|
+
require_relative "formatter/redact_formatter"
|
23
|
+
require_relative "formatter/round_formatter"
|
21
24
|
require_relative "formatter/string_formatter"
|
22
25
|
require_relative "formatter/strip_formatter"
|
23
26
|
require_relative "formatter/structured_formatter"
|
24
27
|
require_relative "formatter/truncate_formatter"
|
28
|
+
require_relative "formatter/tagged_message"
|
25
29
|
|
26
30
|
class << self
|
27
31
|
# Returns a new empty formatter with no mapping. For historical reasons, a formatter
|
@@ -66,12 +70,12 @@ module Lumberjack
|
|
66
70
|
# help avoid loading dependency issues. This applies only to classes; modules cannot be
|
67
71
|
# passed in as strings.
|
68
72
|
#
|
69
|
-
# @param [Class, Module, String, Array<Class, Module, String>]
|
70
|
-
# @param [Symbol, Class, String, #call]
|
73
|
+
# @param klass [Class, Module, String, Array<Class, Module, String>] The class or module to add a formatter for.
|
74
|
+
# @param formatter [Symbol, Class, String, #call] The formatter to use for the class.
|
71
75
|
# If a symbol is passed in, it will be used to load one of the predefined formatters.
|
72
76
|
# If a class is passed in, it will be initialized with the args passed in.
|
73
77
|
# Otherwise, the object will be used as the formatter and must respond to call method.
|
74
|
-
# @param [Array]
|
78
|
+
# @param args [Array] Arguments to pass to the formatter when it is initialized.
|
75
79
|
# @yield [obj] A block that will be used as the formatter for the class.
|
76
80
|
# @yieldparam [Object] obj The object to format.
|
77
81
|
# @yieldreturn [String] The formatted string.
|
@@ -129,7 +133,7 @@ module Lumberjack
|
|
129
133
|
# help avoid loading dependency issues. This applies only to classes; modules cannot be
|
130
134
|
# passed in as strings.
|
131
135
|
#
|
132
|
-
# @param [Class, Module, String, Array<Class, Module, String>]
|
136
|
+
# @param klass [Class, Module, String, Array<Class, Module, String>] The class or module to remove the formatters for.
|
133
137
|
# @return [self] Returns itself so that remove statements can be chained together.
|
134
138
|
def remove(klass)
|
135
139
|
Array(klass).each do |k|
|
@@ -152,9 +156,16 @@ module Lumberjack
|
|
152
156
|
self
|
153
157
|
end
|
154
158
|
|
159
|
+
# Return true if their are no registered formatters.
|
160
|
+
#
|
161
|
+
# @return [Boolean] true if there are no registered formatters, false otherwise.
|
162
|
+
def empty?
|
163
|
+
@class_formatters.empty? && @module_formatters.empty?
|
164
|
+
end
|
165
|
+
|
155
166
|
# Format a message object by applying all formatters attached to it.
|
156
167
|
#
|
157
|
-
# @param [Object]
|
168
|
+
# @param message [Object] The message object to format.
|
158
169
|
# @return [Object] The formatted object.
|
159
170
|
def format(message)
|
160
171
|
formatter = formatter_for(message.class)
|
@@ -168,18 +179,22 @@ module Lumberjack
|
|
168
179
|
# Compatibility with the Logger::Formatter signature. This method will just convert the message
|
169
180
|
# object to a string and ignores the other parameters.
|
170
181
|
#
|
171
|
-
# @param [Integer, String, Symbol]
|
172
|
-
# @param [Time]
|
173
|
-
# @param [String]
|
174
|
-
# @param [Object]
|
182
|
+
# @param severity [Integer, String, Symbol] The severity of the message.
|
183
|
+
# @param timestamp [Time] The time the message was logged.
|
184
|
+
# @param progname [String] The name of the program logging the message.
|
185
|
+
# @param msg [Object] The message object to format.
|
175
186
|
def call(severity, timestamp, progname, msg)
|
176
|
-
|
187
|
+
formatted_message = format(msg)
|
188
|
+
formatted_message = formatted_message.message if formatted_message.is_a?(TaggedMessage)
|
189
|
+
"#{formatted_message}#{Lumberjack::LINE_SEPARATOR}"
|
177
190
|
end
|
178
191
|
|
179
|
-
private
|
180
|
-
|
181
192
|
# Find the formatter for a class by looking it up using the class hierarchy.
|
182
|
-
|
193
|
+
#
|
194
|
+
# @api private
|
195
|
+
def formatter_for(klass)
|
196
|
+
return nil if empty?
|
197
|
+
|
183
198
|
check_modules = true
|
184
199
|
until klass.nil?
|
185
200
|
formatter = @class_formatters[klass.name]
|
data/lib/lumberjack/log_entry.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Lumberjack
|
4
4
|
# An entry in a log is a data structure that captures the log message as well as
|
@@ -8,16 +8,17 @@ module Lumberjack
|
|
8
8
|
|
9
9
|
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S"
|
10
10
|
|
11
|
+
# @deprecated Will be removed in version 2.0.
|
11
12
|
UNIT_OF_WORK_ID = "unit_of_work_id"
|
12
13
|
|
13
14
|
# Create a new log entry.
|
14
15
|
#
|
15
|
-
# @param [Time]
|
16
|
-
# @param [Integer, String]
|
17
|
-
# @param [String]
|
18
|
-
# @param [String]
|
19
|
-
# @param [Integer]
|
20
|
-
# @param [Hash]
|
16
|
+
# @param time [Time] The time the log entry was created.
|
17
|
+
# @param severity [Integer, String] The severity of the log entry.
|
18
|
+
# @param message [String] The message to log.
|
19
|
+
# @param progname [String] The name of the program that created the log entry.
|
20
|
+
# @param pid [Integer] The process id of the program that created the log entry.
|
21
|
+
# @param tags [Hash<String, Object>] A hash of tags to associate with the log entry.
|
21
22
|
def initialize(time, severity, message, progname, pid, tags)
|
22
23
|
@time = time
|
23
24
|
@severity = (severity.is_a?(Integer) ? severity : Severity.label_to_level(severity))
|
@@ -44,17 +45,21 @@ module Lumberjack
|
|
44
45
|
to_s
|
45
46
|
end
|
46
47
|
|
47
|
-
#
|
48
|
+
# @deprecated - backward compatibility with 1.0 API. Will be removed in version 2.0.
|
48
49
|
def unit_of_work_id
|
49
|
-
|
50
|
+
Lumberjack::Utils.deprecated("Lumberjack::LogEntry#unit_of_work_id", "Lumberjack::LogEntry#unit_of_work_id will be removed in version 2.0") do
|
51
|
+
tags[UNIT_OF_WORK_ID] if tags
|
52
|
+
end
|
50
53
|
end
|
51
54
|
|
52
|
-
#
|
55
|
+
# @deprecated - backward compatibility with 1.0 API. Will be removed in version 2.0.
|
53
56
|
def unit_of_work_id=(value)
|
54
|
-
|
55
|
-
tags
|
56
|
-
|
57
|
-
|
57
|
+
Lumberjack::Utils.deprecated("Lumberjack::LogEntry#unit_of_work_id=", "Lumberjack::LogEntry#unit_of_work_id= will be removed in version 2.0") do
|
58
|
+
if tags
|
59
|
+
tags[UNIT_OF_WORK_ID] = value
|
60
|
+
else
|
61
|
+
@tags = {UNIT_OF_WORK_ID => value}
|
62
|
+
end
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
@@ -63,10 +68,15 @@ module Lumberjack
|
|
63
68
|
tags[name.to_s] if tags
|
64
69
|
end
|
65
70
|
|
71
|
+
# Return true if the log entry has no message and no tags.
|
72
|
+
def empty?
|
73
|
+
(message.nil? || message == "") && (tags.nil? || tags.empty?)
|
74
|
+
end
|
75
|
+
|
66
76
|
private
|
67
77
|
|
68
78
|
def tags_to_s
|
69
|
-
tags_string = ""
|
79
|
+
tags_string = +""
|
70
80
|
tags&.each { |name, value| tags_string << " #{name}:#{value.inspect}" }
|
71
81
|
tags_string
|
72
82
|
end
|
data/lib/lumberjack/logger.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Lumberjack
|
4
4
|
# Logger is a thread safe logging object. It has a compatible API with the Ruby
|
@@ -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.
|
@@ -118,15 +134,19 @@ module Lumberjack
|
|
118
134
|
# @param [Integer, Symbol, String] value The severity level.
|
119
135
|
# @return [void]
|
120
136
|
def level=(value)
|
121
|
-
@level =
|
122
|
-
value
|
123
|
-
else
|
124
|
-
Severity.label_to_level(value)
|
125
|
-
end
|
137
|
+
@level = Severity.coerce(value)
|
126
138
|
end
|
127
139
|
|
128
140
|
alias_method :sev_threshold=, :level=
|
129
141
|
|
142
|
+
# Adjust the log level during the block execution for the current Fiber only.
|
143
|
+
#
|
144
|
+
# @param [Integer, Symbol, String] severity The severity level.
|
145
|
+
# @return [Object] The result of the block.
|
146
|
+
def with_level(severity, &block)
|
147
|
+
push_thread_local_value(:lumberjack_logger_level, Severity.coerce(severity), &block)
|
148
|
+
end
|
149
|
+
|
130
150
|
# Set the Lumberjack::Formatter used to format objects for logging as messages.
|
131
151
|
#
|
132
152
|
# @param [Lumberjack::Formatter, Object] value The formatter to use.
|
@@ -190,25 +210,30 @@ module Lumberjack
|
|
190
210
|
Thread.current[:lumberjack_logging] = true
|
191
211
|
|
192
212
|
time = Time.now
|
213
|
+
|
193
214
|
message = message.call if message.is_a?(Proc)
|
194
|
-
|
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
|
+
|
195
227
|
progname ||= self.progname
|
196
228
|
|
197
229
|
current_tags = self.tags
|
198
230
|
tags = nil unless tags.is_a?(Hash)
|
199
|
-
|
200
|
-
|
201
|
-
else
|
202
|
-
tags = if tags.nil?
|
203
|
-
current_tags.dup
|
204
|
-
else
|
205
|
-
current_tags.merge(Tags.stringify_keys(tags))
|
206
|
-
end
|
207
|
-
end
|
231
|
+
tags = merge_tags(current_tags, tags)
|
232
|
+
tags = merge_tags(tags, message_tags) if message_tags
|
208
233
|
tags = Tags.expand_runtime_values(tags)
|
209
234
|
tags = tag_formatter.format(tags) if tag_formatter
|
210
235
|
|
211
|
-
entry = LogEntry.new(time, severity, message, progname,
|
236
|
+
entry = LogEntry.new(time, severity, message, progname, Process.pid, tags)
|
212
237
|
write_to_device(entry)
|
213
238
|
ensure
|
214
239
|
Thread.current[:lumberjack_logging] = nil
|
@@ -437,6 +462,14 @@ module Lumberjack
|
|
437
462
|
end
|
438
463
|
end
|
439
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
|
+
|
440
473
|
# Set the program name that is associated with log messages. If a block
|
441
474
|
# is given, the program name will be valid only within the block.
|
442
475
|
#
|
@@ -458,10 +491,11 @@ module Lumberjack
|
|
458
491
|
end
|
459
492
|
|
460
493
|
# Set a hash of tags on logger. If a block is given, the tags will only be set
|
461
|
-
# for the duration of the block.
|
462
|
-
#
|
463
|
-
#
|
464
|
-
#
|
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.
|
465
499
|
#
|
466
500
|
# @param [Hash] tags The tags to set.
|
467
501
|
# @return [void]
|
@@ -475,11 +509,22 @@ module Lumberjack
|
|
475
509
|
thread_tags.merge!(tags)
|
476
510
|
nil
|
477
511
|
else
|
478
|
-
|
479
|
-
|
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
|
480
515
|
end
|
481
516
|
end
|
482
517
|
|
518
|
+
# Add global tags to the logger that will appear on all log entries.
|
519
|
+
#
|
520
|
+
# @param [Hash] tags The tags to set.
|
521
|
+
# @return [void]
|
522
|
+
def tag_globally(tags)
|
523
|
+
tags = Tags.stringify_keys(tags)
|
524
|
+
@tags.merge!(tags)
|
525
|
+
nil
|
526
|
+
end
|
527
|
+
|
483
528
|
# Remove a tag from the current tag context. If this is called inside a block to a
|
484
529
|
# call to `tag`, the tags will only be removed for the duration of that block. Otherwise
|
485
530
|
# they will be removed from the global tags.
|
@@ -509,6 +554,31 @@ module Lumberjack
|
|
509
554
|
tags
|
510
555
|
end
|
511
556
|
|
557
|
+
# Get the value of a tag by name from the current tag context.
|
558
|
+
#
|
559
|
+
# @param [String, Symbol] name The name of the tag to get.
|
560
|
+
# @return [Object, nil] The value of the tag or nil if the tag does not exist.
|
561
|
+
def tag_value(name)
|
562
|
+
all_tags = tags
|
563
|
+
return nil if tags.empty?
|
564
|
+
|
565
|
+
name = name.join(".") if name.is_a?(Array)
|
566
|
+
name = name.to_s
|
567
|
+
return all_tags[name] if all_tags.include?(name)
|
568
|
+
|
569
|
+
flattened_tags = Lumberjack::Utils.flatten_tags(all_tags)
|
570
|
+
return flattened_tags[name] if flattened_tags.include?(name)
|
571
|
+
|
572
|
+
flattened_tags.keys.select { |key| key.include?(".") }.each do |key|
|
573
|
+
parts = key.split(".")
|
574
|
+
while (subkey = parts.pop)
|
575
|
+
flattened_tags[parts.join(".")] = {subkey => flattened_tags[(parts + [subkey]).join(".")]}
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
flattened_tags[name]
|
580
|
+
end
|
581
|
+
|
512
582
|
# Remove all tags on the current logger and logging context within a block.
|
513
583
|
# You can still set new block scoped tags within theuntagged block and provide
|
514
584
|
# tags on individual log methods.
|
@@ -529,6 +599,14 @@ module Lumberjack
|
|
529
599
|
end
|
530
600
|
end
|
531
601
|
|
602
|
+
# Return true if the thread is currently in a Lumberjack::Context block.
|
603
|
+
# When the logger is in a context block, tagging will only apply to that block.
|
604
|
+
#
|
605
|
+
# @return [Boolean]
|
606
|
+
def in_tag_context?
|
607
|
+
!!thread_local_value(:lumberjack_logger_tags)
|
608
|
+
end
|
609
|
+
|
532
610
|
private
|
533
611
|
|
534
612
|
# Dereference arguments to log calls so we can have methods with compatibility with ::Logger
|
@@ -556,6 +634,20 @@ module Lumberjack
|
|
556
634
|
add_entry(severity, message, progname, tags)
|
557
635
|
end
|
558
636
|
|
637
|
+
# Merge a tags hash into an existing tags hash.
|
638
|
+
def merge_tags(current_tags, tags)
|
639
|
+
if current_tags.nil? || current_tags.empty?
|
640
|
+
tags = Tags.stringify_keys(tags) unless tags.nil?
|
641
|
+
else
|
642
|
+
tags = if tags.nil?
|
643
|
+
current_tags.dup
|
644
|
+
else
|
645
|
+
current_tags.merge(Tags.stringify_keys(tags))
|
646
|
+
end
|
647
|
+
end
|
648
|
+
tags
|
649
|
+
end
|
650
|
+
|
559
651
|
# Set a local value for a thread tied to this object.
|
560
652
|
def set_thread_local_value(name, value) # :nodoc:
|
561
653
|
values = Thread.current[name]
|
@@ -1,18 +1,37 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
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
|
@@ -1,16 +1,20 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Lumberjack
|
4
4
|
module Rack
|
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)
|
@@ -1,10 +1,14 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
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)
|
data/lib/lumberjack/rack.rb
CHANGED
data/lib/lumberjack/severity.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Lumberjack
|
4
4
|
# The standard severity levels for logging messages.
|
@@ -29,6 +29,18 @@ module Lumberjack
|
|
29
29
|
def label_to_level(label)
|
30
30
|
SEVERITY_LABELS.index(label.to_s.upcase) || UNKNOWN
|
31
31
|
end
|
32
|
+
|
33
|
+
# Coerce a value to a severity level.
|
34
|
+
#
|
35
|
+
# @param [Integer, String, Symbol] value The value to coerce.
|
36
|
+
# @return [Integer] The severity level.
|
37
|
+
def coerce(value)
|
38
|
+
if value.is_a?(Integer)
|
39
|
+
value
|
40
|
+
else
|
41
|
+
label_to_level(value)
|
42
|
+
end
|
43
|
+
end
|
32
44
|
end
|
33
45
|
end
|
34
46
|
end
|