lumberjack 1.2.10 → 1.4.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 +84 -0
- data/README.md +168 -63
- data/VERSION +1 -1
- data/lib/lumberjack/context.rb +17 -10
- 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 +76 -17
- data/lib/lumberjack/logger.rb +144 -52
- 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_context.rb +78 -0
- 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 +182 -0
- data/lib/lumberjack.rb +12 -5
- data/lumberjack.gemspec +8 -2
- metadata +17 -7
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lumberjack
|
4
|
+
# A tag context provides an interface for manipulating a tag hash.
|
5
|
+
class TagContext
|
6
|
+
def initialize(tags)
|
7
|
+
@tags = tags
|
8
|
+
end
|
9
|
+
|
10
|
+
# Merge new tags into the context tags. Tag values will be flattened using dot notation
|
11
|
+
# on the keys. So `{ a: { b: 'c' } }` will become `{ 'a.b' => 'c' }`.
|
12
|
+
#
|
13
|
+
# If a block is given, then the tags will only be added for the duration of the block.
|
14
|
+
#
|
15
|
+
# @param tags [Hash] The tags to set.
|
16
|
+
# @return [void]
|
17
|
+
def tag(tags)
|
18
|
+
@tags.merge!(Utils.flatten_tags(tags))
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get a tag value.
|
22
|
+
#
|
23
|
+
# @param name [String, Symbol] The tag key.
|
24
|
+
# @return [Object] The tag value.
|
25
|
+
def [](name)
|
26
|
+
return nil if @tags.empty?
|
27
|
+
|
28
|
+
name = name.to_s
|
29
|
+
return @tags[name] if @tags.include?(name)
|
30
|
+
|
31
|
+
# Check for partial matches in dot notation and return the hash representing the partial match.
|
32
|
+
prefix_key = "#{name}."
|
33
|
+
matching_tags = {}
|
34
|
+
@tags.each do |key, value|
|
35
|
+
if key.start_with?(prefix_key)
|
36
|
+
# Remove the prefix to get the relative key
|
37
|
+
relative_key = key[prefix_key.length..-1]
|
38
|
+
matching_tags[relative_key] = value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return nil if matching_tags.empty?
|
43
|
+
matching_tags
|
44
|
+
end
|
45
|
+
|
46
|
+
# Set a tag value.
|
47
|
+
#
|
48
|
+
# @param name [String, Symbol] The tag name.
|
49
|
+
# @param value [Object] The tag value.
|
50
|
+
# @return [void]
|
51
|
+
def []=(name, value)
|
52
|
+
if value.is_a?(Hash)
|
53
|
+
@tags.merge!(Utils.flatten_tags(name => value))
|
54
|
+
else
|
55
|
+
@tags[name.to_s] = value
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Remove tags from the context.
|
60
|
+
#
|
61
|
+
# @param names [Array<String, Symbol>] The tag names to remove.
|
62
|
+
# @return [void]
|
63
|
+
def delete(*names)
|
64
|
+
names.each do |name|
|
65
|
+
prefix_key = "#{name}."
|
66
|
+
@tags.delete_if { |k, _| k == name.to_s || k.start_with?(prefix_key) }
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return a copy of the tags as a hash.
|
72
|
+
#
|
73
|
+
# @return [Hash]
|
74
|
+
def to_h
|
75
|
+
@tags.dup
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -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)
|
@@ -0,0 +1,182 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "socket"
|
4
|
+
|
5
|
+
module Lumberjack
|
6
|
+
module Utils
|
7
|
+
UNDEFINED = Object.new.freeze
|
8
|
+
private_constant :UNDEFINED
|
9
|
+
|
10
|
+
NON_SLUGGABLE_PATTERN = /[^A-Za-z0-9_.-]+/.freeze
|
11
|
+
private_constant :NON_SLUGGABLE_PATTERN
|
12
|
+
|
13
|
+
@deprecations = nil
|
14
|
+
@deprecations_lock = nil
|
15
|
+
@hostname = UNDEFINED
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Print warning when deprecated methods are called the first time. This can be disabled
|
19
|
+
# by setting the environment variable `LUMBERJACK_NO_DEPRECATION_WARNINGS` to "true".
|
20
|
+
# You can see every usage of a deprecated method along with a full stack trace by setting
|
21
|
+
# the environment variable `VERBOSE_LUMBERJACK_DEPRECATION_WARNING` to "true".
|
22
|
+
#
|
23
|
+
# @param method [String] The name of the deprecated method.
|
24
|
+
# @param message [String] Optional message to include in the warning.
|
25
|
+
# @yield The block to execute after the warning.
|
26
|
+
def deprecated(method, message)
|
27
|
+
@deprecations_lock ||= Mutex.new
|
28
|
+
unless @deprecations&.include?(method)
|
29
|
+
@deprecations_lock.synchronize do
|
30
|
+
@deprecations ||= {}
|
31
|
+
unless @deprecations.include?(method)
|
32
|
+
trace = caller[3..-1]
|
33
|
+
unless ENV["VERBOSE_LUMBERJACK_DEPRECATION_WARNING"] == "true"
|
34
|
+
trace = [trace.first]
|
35
|
+
@deprecations[method] = true
|
36
|
+
end
|
37
|
+
message = "DEPRECATION WARNING: #{message} Called from #{trace.join("\n")}"
|
38
|
+
warn(message) unless ENV["LUMBERJACK_NO_DEPRECATION_WARNINGS"] == "true"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
yield
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get the hostname of the machine. The returned value will be in UTF-8 encoding.
|
47
|
+
#
|
48
|
+
# @return [String] The hostname of the machine.
|
49
|
+
def hostname
|
50
|
+
if @hostname.equal?(UNDEFINED)
|
51
|
+
@hostname = force_utf8(Socket.gethostname)
|
52
|
+
end
|
53
|
+
@hostname
|
54
|
+
end
|
55
|
+
|
56
|
+
# Set the hostname to a specific value. If this is not specified, it will use the system hostname.
|
57
|
+
#
|
58
|
+
# @param hostname [String]
|
59
|
+
# @return [void]
|
60
|
+
def hostname=(hostname)
|
61
|
+
@hostname = force_utf8(hostname)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Generate a global process ID that includes the hostname and process ID.
|
65
|
+
#
|
66
|
+
# @return [String] The global process ID.
|
67
|
+
def global_pid
|
68
|
+
if hostname
|
69
|
+
"#{hostname}-#{Process.pid}"
|
70
|
+
else
|
71
|
+
Process.pid.to_s
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Generate a global thread ID that includes the global process ID and the thread name.
|
76
|
+
#
|
77
|
+
# @return [String] The global thread ID.
|
78
|
+
def global_thread_id
|
79
|
+
"#{global_pid}-#{thread_name}"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Get the name of a thread. The value will be based on the thread's name if it exists.
|
83
|
+
# Otherwise a unique id is generated based on the thread's object id. Only alphanumeric
|
84
|
+
# characters, underscores, dashes, and periods are kept in thread name.
|
85
|
+
#
|
86
|
+
# @param thread [Thread] The thread to get the name for. Defaults to the current thread.
|
87
|
+
# @return [String] The name of the thread.
|
88
|
+
def thread_name(thread = Thread.current)
|
89
|
+
thread.name ? slugify(thread.name) : thread.object_id.to_s(36)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Force encode a string to UTF-8. Any invalid byte sequences will be
|
93
|
+
# ignored and replaced with an empty string.
|
94
|
+
#
|
95
|
+
# @param str [String] The string to encode.
|
96
|
+
# @return [String] The UTF-8 encoded string.
|
97
|
+
def force_utf8(str)
|
98
|
+
return nil if str.nil?
|
99
|
+
|
100
|
+
str.dup.force_encoding("ASCII-8BIT").encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
101
|
+
end
|
102
|
+
|
103
|
+
# Flatten a tag hash to a single level hash with dot notation for nested keys.
|
104
|
+
#
|
105
|
+
# @param tag_hash [Hash] The hash to flatten.
|
106
|
+
# @return [Hash<String, Object>] The flattened hash.
|
107
|
+
# @example
|
108
|
+
# expand_tags(user: {id: 123, name: "Alice"}, action: "login")})
|
109
|
+
# # => {"user.id" => 123, "user.name" => "Alice", "action" => "login"}
|
110
|
+
def flatten_tags(tag_hash)
|
111
|
+
return {} unless tag_hash.is_a?(Hash)
|
112
|
+
|
113
|
+
flatten_hash_recursive(tag_hash)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Expand a hash of tags that may contain nested hashes or dot notation keys. Dot notation tags
|
117
|
+
# will be expanded into nested hashes.
|
118
|
+
#
|
119
|
+
# @param tags [Hash] The hash of tags to expand.
|
120
|
+
# @return [Hash] The expanded hash with dot notation keys.
|
121
|
+
#
|
122
|
+
# @example
|
123
|
+
# expand_tags({"user.id" => 123, "user.name" => "Alice", "action" => "login"})
|
124
|
+
# # => {"user" => {"id" => 123, "name" => "Alice"}, "action" => "login"}
|
125
|
+
def expand_tags(tags)
|
126
|
+
return {} unless tags.is_a?(Hash)
|
127
|
+
|
128
|
+
expand_dot_notation_hash(tags)
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
def flatten_hash_recursive(hash, prefix = nil)
|
134
|
+
hash.each_with_object({}) do |(key, value), result|
|
135
|
+
full_key = prefix ? "#{prefix}.#{key}" : key.to_s
|
136
|
+
if value.is_a?(Hash)
|
137
|
+
result.merge!(flatten_hash_recursive(value, full_key))
|
138
|
+
else
|
139
|
+
result[full_key] = value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def slugify(str)
|
145
|
+
return nil if str.nil?
|
146
|
+
|
147
|
+
str = str.gsub(NON_SLUGGABLE_PATTERN, "-")
|
148
|
+
str.delete_prefix!("-")
|
149
|
+
str.chomp!("-")
|
150
|
+
str
|
151
|
+
end
|
152
|
+
|
153
|
+
def expand_dot_notation_hash(hash, expanded = {})
|
154
|
+
return hash unless hash.is_a?(Hash)
|
155
|
+
|
156
|
+
hash.each do |key, value|
|
157
|
+
key = key.to_s
|
158
|
+
if key.include?(".")
|
159
|
+
main_key, sub_key = key.split(".", 2)
|
160
|
+
main_key_hash = expanded[main_key]
|
161
|
+
unless main_key_hash.is_a?(Hash)
|
162
|
+
main_key_hash = {}
|
163
|
+
expanded[main_key] = main_key_hash
|
164
|
+
end
|
165
|
+
expand_dot_notation_hash({sub_key => value}, main_key_hash)
|
166
|
+
elsif value.is_a?(Hash)
|
167
|
+
key_hash = expanded[key]
|
168
|
+
unless key_hash.is_a?(Hash)
|
169
|
+
key_hash = {}
|
170
|
+
expanded[key] = key_hash
|
171
|
+
end
|
172
|
+
expand_dot_notation_hash(value, key_hash)
|
173
|
+
else
|
174
|
+
expanded[key] = value
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
expanded
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
data/lib/lumberjack.rb
CHANGED
@@ -17,11 +17,13 @@ module Lumberjack
|
|
17
17
|
require_relative "lumberjack/device"
|
18
18
|
require_relative "lumberjack/logger"
|
19
19
|
require_relative "lumberjack/tags"
|
20
|
+
require_relative "lumberjack/tag_context"
|
20
21
|
require_relative "lumberjack/tag_formatter"
|
21
22
|
require_relative "lumberjack/tagged_logger_support"
|
22
23
|
require_relative "lumberjack/tagged_logging"
|
23
24
|
require_relative "lumberjack/template"
|
24
25
|
require_relative "lumberjack/rack"
|
26
|
+
require_relative "lumberjack/utils"
|
25
27
|
|
26
28
|
class << self
|
27
29
|
# Define a unit of work within a block. Within the block supplied to this
|
@@ -34,24 +36,29 @@ module Lumberjack
|
|
34
36
|
# For the common use case of treating a single web request as a unit of work, see the
|
35
37
|
# Lumberjack::Rack::UnitOfWork class.
|
36
38
|
#
|
37
|
-
# @param [String]
|
39
|
+
# @param id [String] The id for the unit of work.
|
38
40
|
# @return [void]
|
41
|
+
# @deprecated Use tags instead. This will be removed in version 2.0.
|
39
42
|
def unit_of_work(id = nil)
|
40
|
-
|
41
|
-
|
42
|
-
context
|
43
|
-
|
43
|
+
Lumberjack::Utils.deprecated("Lumberjack.unit_of_work", "Lumberjack.unit_of_work will be removed in version 2.0. Use Lumberjack::Logger#tag(unit_of_work: id) instead.") do
|
44
|
+
id ||= SecureRandom.hex(6)
|
45
|
+
context do
|
46
|
+
context[:unit_of_work_id] = id
|
47
|
+
yield
|
48
|
+
end
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
47
52
|
# Get the UniqueIdentifier for the current unit of work.
|
48
53
|
#
|
49
54
|
# @return [String, nil] The id for the current unit of work.
|
55
|
+
# @deprecated Use tags instead. This will be removed in version 2.0.
|
50
56
|
def unit_of_work_id
|
51
57
|
context[:unit_of_work_id]
|
52
58
|
end
|
53
59
|
|
54
60
|
# Contexts can be used to store tags that will be attached to all log entries in the block.
|
61
|
+
# The context will apply to all Lumberjack loggers that are used within the block.
|
55
62
|
#
|
56
63
|
# If this method is called with a block, it will set a logging context for the scope of a block.
|
57
64
|
# If there is already a context in scope, a new one will be created that inherits
|
data/lumberjack.gemspec
CHANGED
@@ -4,10 +4,16 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.authors = ["Brian Durand"]
|
5
5
|
spec.email = ["bbdurand@gmail.com"]
|
6
6
|
|
7
|
-
spec.summary = "A simple, powerful, and
|
7
|
+
spec.summary = "A simple, powerful, and fast logging utility with excellent structured logging support that can be a drop in replacement for the standard library Logger."
|
8
8
|
spec.homepage = "https://github.com/bdurand/lumberjack"
|
9
9
|
spec.license = "MIT"
|
10
10
|
|
11
|
+
spec.metadata = {
|
12
|
+
"homepage_uri" => spec.homepage,
|
13
|
+
"source_code_uri" => spec.homepage,
|
14
|
+
"changelog_uri" => "#{spec.homepage}/blob/main/CHANGELOG.md"
|
15
|
+
}
|
16
|
+
|
11
17
|
# Specify which files should be added to the gem when it is released.
|
12
18
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
13
19
|
ignore_files = %w[
|
@@ -25,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
25
31
|
|
26
32
|
spec.require_paths = ["lib"]
|
27
33
|
|
28
|
-
spec.required_ruby_version = ">= 2.
|
34
|
+
spec.required_ruby_version = ">= 2.5.0"
|
29
35
|
|
30
36
|
spec.add_development_dependency "bundler"
|
31
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lumberjack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -31,6 +31,7 @@ executables: []
|
|
31
31
|
extensions: []
|
32
32
|
extra_rdoc_files: []
|
33
33
|
files:
|
34
|
+
- ARCHITECTURE.md
|
34
35
|
- CHANGELOG.md
|
35
36
|
- MIT_LICENSE.txt
|
36
37
|
- README.md
|
@@ -50,11 +51,15 @@ files:
|
|
50
51
|
- lib/lumberjack/formatter/exception_formatter.rb
|
51
52
|
- lib/lumberjack/formatter/id_formatter.rb
|
52
53
|
- lib/lumberjack/formatter/inspect_formatter.rb
|
54
|
+
- lib/lumberjack/formatter/multiply_formatter.rb
|
53
55
|
- lib/lumberjack/formatter/object_formatter.rb
|
54
56
|
- lib/lumberjack/formatter/pretty_print_formatter.rb
|
57
|
+
- lib/lumberjack/formatter/redact_formatter.rb
|
58
|
+
- lib/lumberjack/formatter/round_formatter.rb
|
55
59
|
- lib/lumberjack/formatter/string_formatter.rb
|
56
60
|
- lib/lumberjack/formatter/strip_formatter.rb
|
57
61
|
- lib/lumberjack/formatter/structured_formatter.rb
|
62
|
+
- lib/lumberjack/formatter/tagged_message.rb
|
58
63
|
- lib/lumberjack/formatter/truncate_formatter.rb
|
59
64
|
- lib/lumberjack/log_entry.rb
|
60
65
|
- lib/lumberjack/logger.rb
|
@@ -63,16 +68,21 @@ files:
|
|
63
68
|
- lib/lumberjack/rack/request_id.rb
|
64
69
|
- lib/lumberjack/rack/unit_of_work.rb
|
65
70
|
- lib/lumberjack/severity.rb
|
71
|
+
- lib/lumberjack/tag_context.rb
|
66
72
|
- lib/lumberjack/tag_formatter.rb
|
67
73
|
- lib/lumberjack/tagged_logger_support.rb
|
68
74
|
- lib/lumberjack/tagged_logging.rb
|
69
75
|
- lib/lumberjack/tags.rb
|
70
76
|
- lib/lumberjack/template.rb
|
77
|
+
- lib/lumberjack/utils.rb
|
71
78
|
- lumberjack.gemspec
|
72
79
|
homepage: https://github.com/bdurand/lumberjack
|
73
80
|
licenses:
|
74
81
|
- MIT
|
75
|
-
metadata:
|
82
|
+
metadata:
|
83
|
+
homepage_uri: https://github.com/bdurand/lumberjack
|
84
|
+
source_code_uri: https://github.com/bdurand/lumberjack
|
85
|
+
changelog_uri: https://github.com/bdurand/lumberjack/blob/main/CHANGELOG.md
|
76
86
|
post_install_message:
|
77
87
|
rdoc_options: []
|
78
88
|
require_paths:
|
@@ -81,16 +91,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
91
|
requirements:
|
82
92
|
- - ">="
|
83
93
|
- !ruby/object:Gem::Version
|
84
|
-
version: 2.
|
94
|
+
version: 2.5.0
|
85
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
96
|
requirements:
|
87
97
|
- - ">="
|
88
98
|
- !ruby/object:Gem::Version
|
89
99
|
version: '0'
|
90
100
|
requirements: []
|
91
|
-
rubygems_version: 3.4.
|
101
|
+
rubygems_version: 3.4.10
|
92
102
|
signing_key:
|
93
103
|
specification_version: 4
|
94
|
-
summary: A simple, powerful, and
|
95
|
-
for
|
104
|
+
summary: A simple, powerful, and fast logging utility with excellent structured logging
|
105
|
+
support that can be a drop in replacement for the standard library Logger.
|
96
106
|
test_files: []
|