lumberjack 2.0.4 → 2.1.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 +0 -17
- data/CHANGELOG.md +58 -0
- data/README.md +35 -0
- data/UPGRADE_GUIDE.md +1 -1
- data/VERSION +1 -1
- data/lib/lumberjack/attribute_formatter.rb +0 -51
- data/lib/lumberjack/context.rb +6 -1
- data/lib/lumberjack/context_locals.rb +10 -2
- data/lib/lumberjack/context_logger.rb +14 -4
- data/lib/lumberjack/device/buffer.rb +52 -37
- data/lib/lumberjack/device/multi.rb +2 -2
- data/lib/lumberjack/device/test.rb +70 -13
- data/lib/lumberjack/device/writer.rb +35 -12
- data/lib/lumberjack/device.rb +0 -2
- data/lib/lumberjack/device_registry.rb +7 -6
- data/lib/lumberjack/entry_formatter.rb +4 -2
- data/lib/lumberjack/formatter/structured_formatter.rb +4 -4
- data/lib/lumberjack/formatter/tags_formatter.rb +3 -3
- data/lib/lumberjack/formatter.rb +0 -11
- data/lib/lumberjack/formatter_registry.rb +7 -6
- data/lib/lumberjack/io_compatibility.rb +8 -0
- data/lib/lumberjack/log_entry.rb +13 -46
- data/lib/lumberjack/log_entry_matcher/indifferent_hash.rb +83 -0
- data/lib/lumberjack/log_entry_matcher/score.rb +12 -4
- data/lib/lumberjack/log_entry_matcher.rb +229 -28
- data/lib/lumberjack/logger.rb +19 -185
- data/lib/lumberjack/template.rb +65 -42
- data/lib/lumberjack/template_registry.rb +7 -6
- data/lib/lumberjack/utils.rb +1 -26
- data/lib/lumberjack.rb +5 -25
- data/lumberjack.gemspec +0 -2
- metadata +2 -21
- data/lib/lumberjack/device/date_rolling_log_file.rb +0 -22
- data/lib/lumberjack/device/size_rolling_log_file.rb +0 -22
- data/lib/lumberjack/formatter/tagged_message.rb +0 -17
- data/lib/lumberjack/tag_context.rb +0 -15
- data/lib/lumberjack/tag_formatter.rb +0 -31
- data/lib/lumberjack/tags.rb +0 -36
|
@@ -12,8 +12,16 @@ module Lumberjack
|
|
|
12
12
|
# device in testing scenarios but can be used anywhere log entry filtering
|
|
13
13
|
# is needed.
|
|
14
14
|
#
|
|
15
|
+
# A matcher can optionally be constructed with an entry formatter. Filter
|
|
16
|
+
# values are always compared raw first. If a raw comparison fails, the filter
|
|
17
|
+
# value is run through the formatter and compared again. Since log entries
|
|
18
|
+
# are formatted before they are written to a device, this allows expectations
|
|
19
|
+
# to be written with unformatted values (an Exception, for example) and still
|
|
20
|
+
# match the formatted values captured on the entry.
|
|
21
|
+
#
|
|
15
22
|
# @see Lumberjack::Device::Test
|
|
16
23
|
class LogEntryMatcher
|
|
24
|
+
require_relative "log_entry_matcher/indifferent_hash"
|
|
17
25
|
require_relative "log_entry_matcher/score"
|
|
18
26
|
|
|
19
27
|
# Create a new log entry matcher with optional filtering criteria. All
|
|
@@ -27,14 +35,29 @@ module Lumberjack
|
|
|
27
35
|
# Accepts numeric levels or symbolic names (:debug, :info, etc.)
|
|
28
36
|
# @param progname [Object, nil] Pattern to match against program names.
|
|
29
37
|
# Supports strings, regular expressions, or any object responding to ===
|
|
30
|
-
# @param attributes [Hash, nil] Hash of attribute patterns to match against
|
|
31
|
-
# log entry attributes. Supports nested attribute matching and dot notation
|
|
32
|
-
|
|
38
|
+
# @param attributes [Hash, Object, nil] Hash of attribute patterns to match against
|
|
39
|
+
# log entry attributes. Supports nested attribute matching and dot notation.
|
|
40
|
+
# Any other object is matched against the entire attributes hash with ===
|
|
41
|
+
# so matchers like RSpec's hash_including can be used.
|
|
42
|
+
# @param formatter [Lumberjack::EntryFormatter, Lumberjack::Logger, nil] Optional
|
|
43
|
+
# formatter used to format filter values when a raw comparison fails. A Logger
|
|
44
|
+
# can be passed to use its entry formatter. The message filter is formatted with
|
|
45
|
+
# the message formatter; when the result is a MessageAttributes, only the message
|
|
46
|
+
# part is used and the derived attributes are ignored. Attribute filter values are
|
|
47
|
+
# formatted with the attribute formatter using their dot notation names. Pattern
|
|
48
|
+
# objects (classes, regular expressions, ranges, procs, hashes, and test framework
|
|
49
|
+
# matchers) are never formatted.
|
|
50
|
+
# @raise [ArgumentError] If the formatter is not an EntryFormatter or a Logger.
|
|
51
|
+
def initialize(message: nil, severity: nil, progname: nil, attributes: nil, formatter: nil)
|
|
33
52
|
message = message.strip if message.is_a?(String)
|
|
34
53
|
@message_filter = message
|
|
35
54
|
@severity_filter = Severity.coerce(severity) if severity
|
|
36
55
|
@progname_filter = progname
|
|
37
|
-
|
|
56
|
+
if attributes
|
|
57
|
+
@attributes_filter = attributes.is_a?(Hash) ? Utils.expand_attributes(attributes) : attributes
|
|
58
|
+
end
|
|
59
|
+
@formatter = resolve_formatter(formatter)
|
|
60
|
+
@formatted_attribute_filters = {}
|
|
38
61
|
end
|
|
39
62
|
|
|
40
63
|
# Test whether a log entry matches all specified criteria. The entry must
|
|
@@ -44,16 +67,56 @@ module Lumberjack
|
|
|
44
67
|
# @param entry [Lumberjack::LogEntry] The log entry to test against the matcher
|
|
45
68
|
# @return [Boolean] True if the entry matches all specified criteria, false otherwise
|
|
46
69
|
def match?(entry)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
70
|
+
diff(entry).empty?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Compare a log entry against the matcher criteria and return only the fields
|
|
74
|
+
# that do not match. An empty hash means the entry matches, so
|
|
75
|
+
# +diff(entry).empty?+ is always equal to +match?(entry)+.
|
|
76
|
+
#
|
|
77
|
+
# The returned hash uses string keys for the fields ("message", "severity",
|
|
78
|
+
# "progname", and "attributes"). Each mismatched field maps to a hash with
|
|
79
|
+
# +:expected+ and +:actual+ (the entry value). Severity values are converted
|
|
80
|
+
# to labels on both sides for readability. When a formatter is set and the
|
|
81
|
+
# filter value was formatted, +:expected+ shows the formatted filter value
|
|
82
|
+
# so both sides of the mismatch are in the same form.
|
|
83
|
+
#
|
|
84
|
+
# Attribute mismatches are reported per attribute using dot notation keys.
|
|
85
|
+
# A missing attribute is reported with +actual: nil+. An attribute that was
|
|
86
|
+
# expected to be absent (a nil or empty filter value) is reported with the
|
|
87
|
+
# raw filter as +:expected+ and the entry value as +:actual+. When the
|
|
88
|
+
# attributes filter is not a hash (a matcher object applied to the whole
|
|
89
|
+
# attributes hash), a failure is reported as a single hash with +:expected+
|
|
90
|
+
# and +:actual+ keys instead of per attribute detail.
|
|
91
|
+
#
|
|
92
|
+
# @param entry [Lumberjack::LogEntry] The log entry to compare against the matcher
|
|
93
|
+
# @return [Hash] A hash of the fields that do not match; empty if the entry matches
|
|
94
|
+
def diff(entry)
|
|
95
|
+
result = {}
|
|
96
|
+
|
|
97
|
+
unless match_message?(entry.message)
|
|
98
|
+
result["message"] = {expected: expected_message, actual: entry.message}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
unless match_filter?(entry.severity, @severity_filter)
|
|
102
|
+
result["severity"] = {expected: Severity.level_to_label(@severity_filter), actual: entry.severity_label}
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
unless match_filter?(entry.progname, @progname_filter)
|
|
106
|
+
result["progname"] = {expected: @progname_filter, actual: entry.progname}
|
|
107
|
+
end
|
|
50
108
|
|
|
51
109
|
if @attributes_filter
|
|
52
|
-
attributes = Utils.expand_attributes(entry.attributes)
|
|
53
|
-
|
|
110
|
+
attributes = IndifferentHash.wrap(Utils.expand_attributes(entry.attributes))
|
|
111
|
+
if @attributes_filter.is_a?(Hash)
|
|
112
|
+
mismatches = attribute_mismatches(attributes, @attributes_filter)
|
|
113
|
+
result["attributes"] = mismatches unless mismatches.empty?
|
|
114
|
+
elsif !match_filter?(attributes, @attributes_filter)
|
|
115
|
+
result["attributes"] = {expected: @attributes_filter, actual: attributes}
|
|
116
|
+
end
|
|
54
117
|
end
|
|
55
118
|
|
|
56
|
-
|
|
119
|
+
result
|
|
57
120
|
end
|
|
58
121
|
|
|
59
122
|
# Find the closest matching log entry from a list of candidates. This method
|
|
@@ -81,6 +144,21 @@ module Lumberjack
|
|
|
81
144
|
)
|
|
82
145
|
end
|
|
83
146
|
|
|
147
|
+
# Coerce the formatter argument into an EntryFormatter or nil.
|
|
148
|
+
#
|
|
149
|
+
# @param formatter [Lumberjack::EntryFormatter, Lumberjack::Logger, nil] The formatter argument.
|
|
150
|
+
# @return [Lumberjack::EntryFormatter, nil] The resolved entry formatter.
|
|
151
|
+
def resolve_formatter(formatter)
|
|
152
|
+
return nil if formatter.nil?
|
|
153
|
+
return formatter if formatter.is_a?(Lumberjack::EntryFormatter)
|
|
154
|
+
|
|
155
|
+
if formatter.respond_to?(:formatter) && formatter.formatter.is_a?(Lumberjack::EntryFormatter)
|
|
156
|
+
formatter.formatter
|
|
157
|
+
else
|
|
158
|
+
raise ArgumentError.new("formatter must be a Lumberjack::EntryFormatter or Lumberjack::Logger")
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
84
162
|
# Apply a filter pattern against a value using case equality. Returns true
|
|
85
163
|
# if no filter is specified (nil) or if the filter matches the value.
|
|
86
164
|
#
|
|
@@ -93,34 +171,157 @@ module Lumberjack
|
|
|
93
171
|
filter === value
|
|
94
172
|
end
|
|
95
173
|
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
174
|
+
# Match the message filter against an entry message. If the raw comparison
|
|
175
|
+
# fails, the filter is formatted with the message formatter and compared again.
|
|
176
|
+
#
|
|
177
|
+
# @param message [Object] The entry message.
|
|
178
|
+
# @return [Boolean] True if the message matches.
|
|
179
|
+
def match_message?(message)
|
|
180
|
+
return true if match_filter?(message, @message_filter)
|
|
181
|
+
return false if @formatter.nil? || @message_filter.nil? || pattern_filter?(@message_filter)
|
|
182
|
+
|
|
183
|
+
formatted = formatted_message_filter
|
|
184
|
+
return false if formatted.equal?(@message_filter)
|
|
185
|
+
|
|
186
|
+
match_filter?(message, formatted)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# The message filter value to report in a diff. The formatted value is used
|
|
190
|
+
# when the formatter changed the filter so both sides of a mismatch are in
|
|
191
|
+
# the same form.
|
|
192
|
+
#
|
|
193
|
+
# @return [Object] The message filter value to report.
|
|
194
|
+
def expected_message
|
|
195
|
+
if @formatter && !@message_filter.nil? && !pattern_filter?(@message_filter)
|
|
196
|
+
formatted_message_filter
|
|
197
|
+
else
|
|
198
|
+
@message_filter
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Format the message filter with the message formatter. The result is
|
|
203
|
+
# memoized so the formatter is only invoked once per matcher.
|
|
99
204
|
#
|
|
100
|
-
# @
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
205
|
+
# @return [Object] The formatted message filter.
|
|
206
|
+
def formatted_message_filter
|
|
207
|
+
return @formatted_message_filter if defined?(@formatted_message_filter)
|
|
208
|
+
|
|
209
|
+
value = @message_filter
|
|
210
|
+
message_formatter = @formatter.message_formatter
|
|
211
|
+
if message_formatter.respond_to?(:format)
|
|
212
|
+
begin
|
|
213
|
+
value = message_formatter.format(@message_filter)
|
|
214
|
+
rescue
|
|
215
|
+
value = @message_filter
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
value = value.message if value.is_a?(MessageAttributes)
|
|
219
|
+
value = value.strip if value.is_a?(String)
|
|
220
|
+
@formatted_message_filter = value
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
# Recursively compare attribute filter patterns against entry attributes and
|
|
224
|
+
# collect the mismatches. Keys in the returned hash use dot notation.
|
|
225
|
+
#
|
|
226
|
+
# @param attributes [Hash] The expanded attributes hash from the log entry.
|
|
227
|
+
# @param filter [Hash] The filter patterns to match against the attributes.
|
|
228
|
+
# @param path [String, nil] The dot notation path of the current nesting level.
|
|
229
|
+
# @param allow_formatting [Boolean] Whether filter values can be formatted on a failed comparison.
|
|
230
|
+
# @return [Hash] The mismatched attributes keyed by dot notation name.
|
|
231
|
+
def attribute_mismatches(attributes, filter, path = nil, allow_formatting: true)
|
|
232
|
+
mismatches = {}
|
|
233
|
+
|
|
234
|
+
filter.each do |name, value_filter|
|
|
108
235
|
name = name.to_s
|
|
109
|
-
|
|
110
|
-
|
|
236
|
+
key = path ? "#{path}.#{name}" : name
|
|
237
|
+
attribute_value = attributes[name]
|
|
238
|
+
|
|
239
|
+
if attribute_value.is_a?(Hash)
|
|
111
240
|
if value_filter.is_a?(Hash)
|
|
112
|
-
|
|
241
|
+
mismatches.merge!(attribute_mismatches(attribute_value, value_filter, key, allow_formatting: allow_formatting))
|
|
113
242
|
else
|
|
114
|
-
|
|
243
|
+
add_leaf_mismatches(mismatches, key, attribute_value, value_filter, allow_formatting)
|
|
115
244
|
end
|
|
116
245
|
elsif value_filter.nil? || (value_filter.is_a?(Enumerable) && value_filter.empty?)
|
|
117
|
-
|
|
246
|
+
empty_value = attribute_value.nil? || (attribute_value.is_a?(Array) && attribute_value.empty?)
|
|
247
|
+
mismatches[key] = {expected: value_filter, actual: attribute_value} unless empty_value
|
|
118
248
|
elsif attributes.include?(name)
|
|
119
|
-
|
|
249
|
+
add_leaf_mismatches(mismatches, key, attribute_value, value_filter, allow_formatting)
|
|
120
250
|
else
|
|
121
|
-
|
|
251
|
+
mismatches[key] = {expected: value_filter, actual: nil}
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
mismatches
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Match a single attribute value against a filter and add any mismatches to
|
|
259
|
+
# the collector. If the raw comparison fails, the filter is formatted with the
|
|
260
|
+
# attribute formatter and compared again. Mismatches are reported with the
|
|
261
|
+
# formatted filter value so both sides are in the same form. A formatted result
|
|
262
|
+
# that is a hash is compared recursively against the entry value with formatting
|
|
263
|
+
# disabled since its values are already formatted, and mismatches are reported
|
|
264
|
+
# per attribute under the leaf's dot notation name.
|
|
265
|
+
#
|
|
266
|
+
# @param mismatches [Hash] The mismatch collector.
|
|
267
|
+
# @param path [String] The dot notation name of the attribute.
|
|
268
|
+
# @param value [Object] The entry attribute value.
|
|
269
|
+
# @param filter [Object] The filter pattern.
|
|
270
|
+
# @param allow_formatting [Boolean] Whether the filter can be formatted on a failed comparison.
|
|
271
|
+
# @return [void]
|
|
272
|
+
def add_leaf_mismatches(mismatches, path, value, filter, allow_formatting)
|
|
273
|
+
return if match_filter?(value, filter)
|
|
274
|
+
|
|
275
|
+
unless allow_formatting && @formatter && !pattern_filter?(filter)
|
|
276
|
+
mismatches[path] = {expected: filter, actual: value}
|
|
277
|
+
return
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
formatted = formatted_attribute_filter(path, filter)
|
|
281
|
+
if formatted.equal?(filter)
|
|
282
|
+
mismatches[path] = {expected: filter, actual: value}
|
|
283
|
+
elsif formatted.is_a?(Hash)
|
|
284
|
+
if value.is_a?(Hash)
|
|
285
|
+
mismatches.merge!(attribute_mismatches(value, Utils.expand_attributes(formatted), path, allow_formatting: false))
|
|
286
|
+
else
|
|
287
|
+
mismatches[path] = {expected: formatted, actual: value}
|
|
288
|
+
end
|
|
289
|
+
elsif !match_filter?(value, formatted)
|
|
290
|
+
mismatches[path] = {expected: formatted, actual: value}
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# Determine if a filter is a pattern that must never be formatted since
|
|
295
|
+
# formatting it would destroy its matching behavior.
|
|
296
|
+
#
|
|
297
|
+
# @param filter [Object] The filter to check.
|
|
298
|
+
# @return [Boolean] True if the filter is a pattern object.
|
|
299
|
+
def pattern_filter?(filter)
|
|
300
|
+
filter.is_a?(Module) || filter.is_a?(Regexp) || filter.is_a?(Range) ||
|
|
301
|
+
filter.is_a?(Proc) || filter.is_a?(Hash) || filter.respond_to?(:matches?)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Format an attribute filter value with the attribute formatter using its dot
|
|
305
|
+
# notation name so name based formatters apply. Results are memoized per name.
|
|
306
|
+
# The raw filter is returned if formatting fails or removes the attribute.
|
|
307
|
+
#
|
|
308
|
+
# @param path [String] The dot notation name of the attribute.
|
|
309
|
+
# @param filter [Object] The filter value to format.
|
|
310
|
+
# @return [Object] The formatted filter value.
|
|
311
|
+
def formatted_attribute_filter(path, filter)
|
|
312
|
+
return @formatted_attribute_filters[path] if @formatted_attribute_filters.include?(path)
|
|
313
|
+
|
|
314
|
+
attribute_formatter = @formatter.attribute_formatter
|
|
315
|
+
formatted = filter
|
|
316
|
+
if attribute_formatter.respond_to?(:format)
|
|
317
|
+
begin
|
|
318
|
+
result = attribute_formatter.format({path => filter})
|
|
319
|
+
formatted = result.fetch(path, filter) if result.is_a?(Hash)
|
|
320
|
+
rescue
|
|
321
|
+
formatted = filter
|
|
122
322
|
end
|
|
123
323
|
end
|
|
324
|
+
@formatted_attribute_filters[path] = formatted
|
|
124
325
|
end
|
|
125
326
|
end
|
|
126
327
|
end
|
data/lib/lumberjack/logger.rb
CHANGED
|
@@ -69,11 +69,9 @@ module Lumberjack
|
|
|
69
69
|
# log files will be rolled when they get to the size specified in shift_size and the number of
|
|
70
70
|
# files to keep will be determined by this value. Otherwise it will be interpreted as a date
|
|
71
71
|
# rolling value and must be one of "daily", "weekly", or "monthly". This parameter has no
|
|
72
|
-
# effect unless the device parameter is a file path or file stream.
|
|
73
|
-
# specified with the :roll keyword argument.
|
|
72
|
+
# effect unless the device parameter is a file path or file stream.
|
|
74
73
|
# @param shift_size [Integer] The size in bytes of the log files before rolling them. This can
|
|
75
74
|
# be passed as a string with a unit suffix of K, M, or G (e.g. "10M" for 10 megabytes).
|
|
76
|
-
# This can also be specified with the :max_size keyword argument.
|
|
77
75
|
# @param level [Integer, Symbol, String] The logging level below which messages will be ignored.
|
|
78
76
|
# @param progname [String] The name of the program that will be recorded with each log entry.
|
|
79
77
|
# @param formatter [Lumberjack::EntryFormatter, Lumberjack::Formatter, ::Logger::Formatter, :default, #call]
|
|
@@ -95,16 +93,7 @@ module Lumberjack
|
|
|
95
93
|
level: DEBUG, progname: nil, formatter: nil, datetime_format: nil,
|
|
96
94
|
binmode: false, shift_period_suffix: "%Y%m%d", **kwargs)
|
|
97
95
|
init_context_locals!
|
|
98
|
-
|
|
99
|
-
if shift_age.is_a?(Hash)
|
|
100
|
-
Lumberjack::Utils.deprecated("Logger.new(options)", "Passing a Hash as the second argument to Logger.new is deprecated and will be removed in version 2.1; use keyword arguments instead.")
|
|
101
|
-
options = shift_age
|
|
102
|
-
level = options[:level] if options.include?(:level)
|
|
103
|
-
progname = options[:progname] if options.include?(:progname)
|
|
104
|
-
formatter = options[:formatter] if options.include?(:formatter)
|
|
105
|
-
datetime_format = options[:datetime_format] if options.include?(:datetime_format)
|
|
106
|
-
kwargs = options.merge(kwargs)
|
|
107
|
-
end
|
|
96
|
+
@recursion_guard_key = :"lumberjack_logging_#{object_id}"
|
|
108
97
|
|
|
109
98
|
self.isolation_level = kwargs.delete(:isolation_level) || Lumberjack.isolation_level
|
|
110
99
|
|
|
@@ -113,36 +102,13 @@ module Lumberjack
|
|
|
113
102
|
device_options = kwargs.merge(shift_age: shift_age, shift_size: size_with_units(shift_size), binmode: binmode, shift_period_suffix: shift_period_suffix)
|
|
114
103
|
device_options[:standard_logger_formatter] = formatter if standard_logger_formatter?(formatter)
|
|
115
104
|
|
|
116
|
-
if device_options.include?(:roll)
|
|
117
|
-
Utils.deprecated("Logger.options(:roll)", "Lumberjack::Logger :roll option is deprecated and will be removed in version 2.1; use the shift_age argument instead.")
|
|
118
|
-
device_options[:shift_age] = device_options.delete(:roll) unless shift_age != 0
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
if device_options.include?(:max_size)
|
|
122
|
-
Utils.deprecated("Logger.options(:max_size)", "Lumberjack::Logger :max_size option is deprecated and will be removed in version 2.1; use the shift_size argument instead.")
|
|
123
|
-
device_options[:shift_age] = 10 if shift_age == 0
|
|
124
|
-
device_options[:shift_size] = device_options.delete(:max_size)
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
message_formatter = nil
|
|
128
|
-
if device_options.include?(:message_formatter)
|
|
129
|
-
Utils.deprecated("Logger.options(:message_formatter)", "Lumberjack::Logger :message_formatter option is deprecated and will be removed in version 2.1; use the formatter argument instead to specify an EntryFormatter.")
|
|
130
|
-
message_formatter = device_options.delete(:message_formatter)
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
attribute_formatter = nil
|
|
134
|
-
if device_options.include?(:tag_formatter)
|
|
135
|
-
Utils.deprecated("Logger.options(:tag_formatter)", "Lumberjack::Logger :tag_formatter option is deprecated and will be removed in version 2.1; use the formatter argument instead to specify an EntryFormatter.")
|
|
136
|
-
attribute_formatter = device_options.delete(:tag_formatter)
|
|
137
|
-
end
|
|
138
|
-
|
|
139
105
|
@logdev = Device.open_device(logdev, device_options)
|
|
140
106
|
|
|
141
107
|
@context = Context.new
|
|
142
108
|
self.level = level || DEBUG
|
|
143
109
|
self.progname = progname
|
|
144
110
|
|
|
145
|
-
self.formatter = build_entry_formatter(formatter
|
|
111
|
+
self.formatter = build_entry_formatter(formatter)
|
|
146
112
|
self.datetime_format = datetime_format if datetime_format
|
|
147
113
|
|
|
148
114
|
@closed = false
|
|
@@ -169,7 +135,7 @@ module Lumberjack
|
|
|
169
135
|
# @param value [Lumberjack::EntryFormatter, ::Logger::Formatter, #call] The formatter to use.
|
|
170
136
|
# @return [void]
|
|
171
137
|
def formatter=(value)
|
|
172
|
-
@formatter = build_entry_formatter(value
|
|
138
|
+
@formatter = build_entry_formatter(value)
|
|
173
139
|
end
|
|
174
140
|
|
|
175
141
|
# Get the timestamp format on the device if it has one.
|
|
@@ -219,20 +185,6 @@ module Lumberjack
|
|
|
219
185
|
formatter.attribute_formatter = value
|
|
220
186
|
end
|
|
221
187
|
|
|
222
|
-
# @deprecated Use {#attribute_formatter} instead.
|
|
223
|
-
def tag_formatter
|
|
224
|
-
Utils.deprecated("Logger#tag_formatter", "Lumberjack::Logger#tag_formatter is deprecated and will be removed in version 2.1; use attribute_formatter instead.") do
|
|
225
|
-
formatter.attributes.attribute_formatter
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
# @deprecated Use {#attribute_formatter=} instead.
|
|
230
|
-
def tag_formatter=(value)
|
|
231
|
-
Utils.deprecated("Logger#tag_formatter=", "Lumberjack::Logger#tag_formatter= is deprecated and will be removed in version 2.1; use attribute_formatter= instead.") do
|
|
232
|
-
formatter.attributes.attribute_formatter = value
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
|
|
236
188
|
# Flush the logging device. Messages are not guaranteed to be written until this method is called.
|
|
237
189
|
#
|
|
238
190
|
# @return [void]
|
|
@@ -269,125 +221,6 @@ module Lumberjack
|
|
|
269
221
|
self
|
|
270
222
|
end
|
|
271
223
|
|
|
272
|
-
# Set the program name that is associated with log messages. If a block
|
|
273
|
-
# is given, the program name will be valid only within the block.
|
|
274
|
-
#
|
|
275
|
-
# @param value [String] The program name to use.
|
|
276
|
-
# @return [void]
|
|
277
|
-
# @deprecated Use with_progname or progname= instead.
|
|
278
|
-
def set_progname(value, &block)
|
|
279
|
-
Utils.deprecated("Logger#set_progname", "Lumberjack::Logger#set_progname is deprecated and will be removed in version 2.1; use with_progname or progname= instead.") do
|
|
280
|
-
if block
|
|
281
|
-
with_progname(value, &block)
|
|
282
|
-
else
|
|
283
|
-
self.progname = value
|
|
284
|
-
end
|
|
285
|
-
end
|
|
286
|
-
end
|
|
287
|
-
|
|
288
|
-
# Alias method for #attributes to provide backward compatibility with version 1.x API. This
|
|
289
|
-
# method will eventually be removed.
|
|
290
|
-
#
|
|
291
|
-
# @return [Hash]
|
|
292
|
-
# @deprecated Use {#attributes} instead
|
|
293
|
-
def tags
|
|
294
|
-
Utils.deprecated("Logger#tags", "Lumberjack::Logger#tags is deprecated and will be removed in version 2.1; use attributes instead.") do
|
|
295
|
-
attributes
|
|
296
|
-
end
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
# Alias method for #attribute_value to provide backward compatibility with version 1.x API. This
|
|
300
|
-
# method will eventually be removed.
|
|
301
|
-
#
|
|
302
|
-
# @return [Hash]
|
|
303
|
-
# @deprecated Use {#attribute_value} instead
|
|
304
|
-
def tag_value(name)
|
|
305
|
-
Utils.deprecated("Logger#tag_value", "Lumberjack::Logger#tag_value is deprecated and will be removed in version 2.1; use attribute_value instead.") do
|
|
306
|
-
attribute_value(name)
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
|
|
310
|
-
# Use tag! instead
|
|
311
|
-
#
|
|
312
|
-
# @return [void]
|
|
313
|
-
# @deprecated Use {#tag!} instead.
|
|
314
|
-
def tag_globally(tags)
|
|
315
|
-
Utils.deprecated("Logger#tag_globally", "Lumberjack::Logger#tag_globally is deprecated and will be removed in version 2.1; use tag! instead.") do
|
|
316
|
-
tag!(tags)
|
|
317
|
-
end
|
|
318
|
-
end
|
|
319
|
-
|
|
320
|
-
# Use context? instead
|
|
321
|
-
#
|
|
322
|
-
# @return [Boolean]
|
|
323
|
-
# @deprecated Use {#in_context?} instead.
|
|
324
|
-
def in_tag_context?
|
|
325
|
-
Utils.deprecated("Logger#in_tag_context?", "Lumberjack::Logger#in_tag_context? is deprecated and will be removed in version 2.1; use in_context? instead.") do
|
|
326
|
-
context?
|
|
327
|
-
end
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
# Remove a tag from the current context block. If this is called inside a context block,
|
|
331
|
-
# the attributes will only be removed for the duration of that block. Otherwise they will be removed
|
|
332
|
-
# from the global attributes.
|
|
333
|
-
#
|
|
334
|
-
# @param tag_names [Array<String, Symbol>] The attributes to remove.
|
|
335
|
-
# @return [void]
|
|
336
|
-
# @deprecated Use untag or untag! instead.
|
|
337
|
-
def remove_tag(*tag_names)
|
|
338
|
-
Utils.deprecated("Logger#remove_tag", "Lumberjack::Logger#remove_tag is deprecated and will be removed in version 2.1; use untag or untag! instead.") do
|
|
339
|
-
attributes = current_context&.attributes
|
|
340
|
-
AttributesHelper.new(attributes).delete(*tag_names) if attributes
|
|
341
|
-
end
|
|
342
|
-
end
|
|
343
|
-
|
|
344
|
-
# Alias for append_to(:tagged) for compatibility with ActiveSupport support in Lumberjack 1.x.
|
|
345
|
-
# This functionality has been moved to the lumberjack_rails gem. Note that in that gem the
|
|
346
|
-
# tags are added to the :tags attribute instead of the :tagged attribute.
|
|
347
|
-
#
|
|
348
|
-
# @see append_to
|
|
349
|
-
# @deprecated This implementation is deprecated. Install the lumberjack_rails gem for full support.
|
|
350
|
-
def tagged(*tags, &block)
|
|
351
|
-
deprecation_message = "Install the lumberjack_rails gem for full support of the tagged method."
|
|
352
|
-
Utils.deprecated("Logger#tagged", deprecation_message) do
|
|
353
|
-
append_to(:tagged, *tags, &block)
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
|
|
357
|
-
# Alias for clear_attributes.
|
|
358
|
-
#
|
|
359
|
-
# @see clear_attributes
|
|
360
|
-
# @deprecated Use clear_attributes instead.
|
|
361
|
-
def untagged(&block)
|
|
362
|
-
Utils.deprecated("Logger#untagged", "Lumberjack::Logger#untagged is deprecated and will be removed in version 2.1; use clear_attributes instead.") do
|
|
363
|
-
clear_attributes(&block)
|
|
364
|
-
end
|
|
365
|
-
end
|
|
366
|
-
|
|
367
|
-
# Alias for with_level for compatibility with ActiveSupport loggers. This functionality
|
|
368
|
-
# has been moved to the lumberjack_rails gem.
|
|
369
|
-
#
|
|
370
|
-
# @see with_level
|
|
371
|
-
# @deprecated This implementation is deprecated. Install the lumberjack_rails gem for full support.
|
|
372
|
-
def log_at(level, &block)
|
|
373
|
-
deprecation_message = "Install the lumberjack_rails gem for full support of the log_at method."
|
|
374
|
-
Utils.deprecated("Logger#log_at", deprecation_message) do
|
|
375
|
-
with_level(level, &block)
|
|
376
|
-
end
|
|
377
|
-
end
|
|
378
|
-
|
|
379
|
-
# Alias for with_level for compatibilty with ActiveSupport loggers. This functionality
|
|
380
|
-
# has been moved to the lumberjack_rails gem.
|
|
381
|
-
#
|
|
382
|
-
# @see with_level
|
|
383
|
-
# @deprecated This implementation is deprecated. Install the lumberjack_rails gem for full support.
|
|
384
|
-
def silence(level = Logger::ERROR, &block)
|
|
385
|
-
deprecation_message = "Install the lumberjack_rails gem for full support of the silence method."
|
|
386
|
-
Utils.deprecated("Logger#silence", deprecation_message) do
|
|
387
|
-
with_level(level, &block)
|
|
388
|
-
end
|
|
389
|
-
end
|
|
390
|
-
|
|
391
224
|
# Add an entry to the log.
|
|
392
225
|
#
|
|
393
226
|
# @param severity [Integer, Symbol, String] The severity of the message.
|
|
@@ -400,25 +233,30 @@ module Lumberjack
|
|
|
400
233
|
return false unless device
|
|
401
234
|
|
|
402
235
|
# Prevent infinite recursion if logging is attempted from within a logging call.
|
|
403
|
-
|
|
236
|
+
# The guard is stored in fiber-local storage since recursion is a property of the
|
|
237
|
+
# current call stack, which belongs to exactly one fiber.
|
|
238
|
+
if Thread.current[@recursion_guard_key]
|
|
404
239
|
log_to_stderr(severity, message)
|
|
405
240
|
return false
|
|
406
241
|
end
|
|
407
242
|
|
|
408
243
|
severity = Severity.label_to_level(severity) unless severity.is_a?(Integer)
|
|
409
244
|
|
|
410
|
-
|
|
411
|
-
|
|
245
|
+
begin
|
|
246
|
+
Thread.current[@recursion_guard_key] = true
|
|
412
247
|
|
|
248
|
+
locals = current_context_locals
|
|
413
249
|
time = Time.now
|
|
414
|
-
progname ||=
|
|
250
|
+
progname ||= locals&.context&.progname || default_context&.progname
|
|
415
251
|
attributes = nil unless attributes.is_a?(Hash)
|
|
416
|
-
attributes =
|
|
252
|
+
attributes = merge_all_attributes(locals, attributes)
|
|
417
253
|
message, attributes = formatter.format(message, attributes) if formatter
|
|
418
254
|
|
|
419
255
|
entry = Lumberjack::LogEntry.new(time, severity, message, progname, Process.pid, attributes)
|
|
420
256
|
|
|
421
257
|
write_to_device(entry)
|
|
258
|
+
ensure
|
|
259
|
+
Thread.current[@recursion_guard_key] = nil
|
|
422
260
|
end
|
|
423
261
|
|
|
424
262
|
true
|
|
@@ -449,18 +287,14 @@ module Lumberjack
|
|
|
449
287
|
raise e if Lumberjack.raise_logger_errors?
|
|
450
288
|
end
|
|
451
289
|
|
|
452
|
-
def build_entry_formatter(formatter
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
unless entry_formatter
|
|
456
|
-
message_formatter ||= formatter if formatter.is_a?(Lumberjack::Formatter) || formatter == :default
|
|
457
|
-
entry_formatter = Lumberjack::EntryFormatter.new
|
|
458
|
-
end
|
|
290
|
+
def build_entry_formatter(formatter) # :nodoc:
|
|
291
|
+
return formatter if formatter.is_a?(Lumberjack::EntryFormatter)
|
|
459
292
|
|
|
460
|
-
|
|
293
|
+
entry_formatter = Lumberjack::EntryFormatter.new
|
|
461
294
|
|
|
295
|
+
message_formatter = formatter if formatter.is_a?(Lumberjack::Formatter)
|
|
296
|
+
message_formatter = Lumberjack::Formatter.default if formatter == :default
|
|
462
297
|
entry_formatter.message_formatter = message_formatter if message_formatter
|
|
463
|
-
entry_formatter.attribute_formatter = attribute_formatter if attribute_formatter
|
|
464
298
|
|
|
465
299
|
entry_formatter
|
|
466
300
|
end
|