lumberjack 1.4.2 → 2.0.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 +524 -176
- data/CHANGELOG.md +89 -0
- data/README.md +604 -211
- data/UPGRADE_GUIDE.md +80 -0
- data/VERSION +1 -1
- data/lib/lumberjack/attribute_formatter.rb +451 -0
- data/lib/lumberjack/attributes_helper.rb +100 -0
- data/lib/lumberjack/context.rb +120 -23
- data/lib/lumberjack/context_logger.rb +620 -0
- data/lib/lumberjack/device/buffer.rb +209 -0
- data/lib/lumberjack/device/date_rolling_log_file.rb +10 -62
- data/lib/lumberjack/device/log_file.rb +76 -29
- data/lib/lumberjack/device/logger_wrapper.rb +137 -0
- data/lib/lumberjack/device/multi.rb +92 -30
- data/lib/lumberjack/device/null.rb +26 -8
- data/lib/lumberjack/device/size_rolling_log_file.rb +13 -54
- data/lib/lumberjack/device/test.rb +337 -0
- data/lib/lumberjack/device/writer.rb +184 -176
- data/lib/lumberjack/device.rb +134 -15
- data/lib/lumberjack/device_registry.rb +90 -0
- data/lib/lumberjack/entry_formatter.rb +357 -0
- data/lib/lumberjack/fiber_locals.rb +55 -0
- data/lib/lumberjack/forked_logger.rb +143 -0
- data/lib/lumberjack/formatter/date_time_formatter.rb +14 -3
- data/lib/lumberjack/formatter/exception_formatter.rb +12 -2
- data/lib/lumberjack/formatter/id_formatter.rb +13 -1
- data/lib/lumberjack/formatter/inspect_formatter.rb +14 -1
- data/lib/lumberjack/formatter/multiply_formatter.rb +10 -0
- data/lib/lumberjack/formatter/object_formatter.rb +13 -1
- data/lib/lumberjack/formatter/pretty_print_formatter.rb +15 -2
- data/lib/lumberjack/formatter/redact_formatter.rb +18 -3
- data/lib/lumberjack/formatter/round_formatter.rb +12 -0
- data/lib/lumberjack/formatter/string_formatter.rb +9 -1
- data/lib/lumberjack/formatter/strip_formatter.rb +13 -1
- data/lib/lumberjack/formatter/structured_formatter.rb +18 -2
- data/lib/lumberjack/formatter/tagged_message.rb +10 -32
- data/lib/lumberjack/formatter/tags_formatter.rb +32 -0
- data/lib/lumberjack/formatter/truncate_formatter.rb +8 -1
- data/lib/lumberjack/formatter.rb +271 -141
- data/lib/lumberjack/formatter_registry.rb +84 -0
- data/lib/lumberjack/io_compatibility.rb +133 -0
- data/lib/lumberjack/local_log_template.rb +209 -0
- data/lib/lumberjack/log_entry.rb +154 -79
- data/lib/lumberjack/log_entry_matcher/score.rb +276 -0
- data/lib/lumberjack/log_entry_matcher.rb +126 -0
- data/lib/lumberjack/logger.rb +328 -556
- data/lib/lumberjack/message_attributes.rb +38 -0
- data/lib/lumberjack/rack/context.rb +66 -15
- data/lib/lumberjack/rack.rb +0 -2
- data/lib/lumberjack/remap_attribute.rb +24 -0
- data/lib/lumberjack/severity.rb +52 -15
- data/lib/lumberjack/tag_context.rb +8 -71
- data/lib/lumberjack/tag_formatter.rb +22 -188
- data/lib/lumberjack/tags.rb +15 -21
- data/lib/lumberjack/template.rb +252 -62
- data/lib/lumberjack/template_registry.rb +60 -0
- data/lib/lumberjack/utils.rb +198 -48
- data/lib/lumberjack.rb +167 -59
- data/lumberjack.gemspec +4 -2
- metadata +41 -15
- data/lib/lumberjack/device/rolling_log_file.rb +0 -145
- data/lib/lumberjack/rack/request_id.rb +0 -31
- data/lib/lumberjack/rack/unit_of_work.rb +0 -21
- data/lib/lumberjack/tagged_logger_support.rb +0 -81
- data/lib/lumberjack/tagged_logging.rb +0 -29
data/lib/lumberjack/utils.rb
CHANGED
@@ -3,6 +3,11 @@
|
|
3
3
|
require "socket"
|
4
4
|
|
5
5
|
module Lumberjack
|
6
|
+
# Error raised when a deprecated method is called and the deprecation mode is set to :raise.
|
7
|
+
class DeprecationError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Utils provides utility methods and helper functions used throughout the Lumberjack logging framework.
|
6
11
|
module Utils
|
7
12
|
UNDEFINED = Object.new.freeze
|
8
13
|
private_constant :UNDEFINED
|
@@ -16,36 +21,73 @@ module Lumberjack
|
|
16
21
|
|
17
22
|
class << self
|
18
23
|
# Print warning when deprecated methods are called the first time. This can be disabled
|
19
|
-
# by setting
|
20
|
-
#
|
21
|
-
#
|
24
|
+
# by setting +Lumberjack.deprecation_mode+ to +:silent+.
|
25
|
+
#
|
26
|
+
# In order to cut down on noise, each deprecated method will only print a warning once per process.
|
27
|
+
# You can change this by setting +Lumberjack.deprecation_mode+ to +:verbose+.
|
28
|
+
#
|
29
|
+
# @param method [String, Symbol] The name of the deprecated method.
|
30
|
+
# @param message [String] The deprecation message explaining what to use instead.
|
31
|
+
# @yield The block containing the deprecated functionality to execute.
|
32
|
+
# @return [Object] The result of the yielded block.
|
22
33
|
#
|
23
|
-
# @
|
24
|
-
#
|
25
|
-
#
|
34
|
+
# @example
|
35
|
+
# def old_method
|
36
|
+
# Utils.deprecated(:old_method, "Use new_method instead.") do
|
37
|
+
# # deprecated implementation
|
38
|
+
# end
|
39
|
+
# end
|
26
40
|
def deprecated(method, message)
|
27
|
-
|
28
|
-
|
41
|
+
if Lumberjack.deprecation_mode != :silent && !@deprecations&.include?(method)
|
42
|
+
@deprecations_lock ||= Mutex.new
|
29
43
|
@deprecations_lock.synchronize do
|
30
44
|
@deprecations ||= {}
|
31
45
|
unless @deprecations.include?(method)
|
32
|
-
trace = caller[3
|
33
|
-
|
34
|
-
|
46
|
+
trace = ($VERBOSE && Lumberjack.deprecation_mode != :raise) ? caller[3..] : caller[3, 1]
|
47
|
+
if trace.first.start_with?(__dir__) && !$VERBOSE
|
48
|
+
non_lumberjack_caller = caller[4..].detect { |line| !line.start_with?(__dir__) }
|
49
|
+
trace = [non_lumberjack_caller] if non_lumberjack_caller
|
50
|
+
end
|
51
|
+
message = "DEPRECATION WARNING: #{message} Called from #{trace.join(Lumberjack::LINE_SEPARATOR)}"
|
52
|
+
|
53
|
+
if Lumberjack.deprecation_mode == :raise
|
54
|
+
raise DeprecationError, message
|
55
|
+
end
|
56
|
+
|
57
|
+
unless Lumberjack.deprecation_mode == :verbose
|
35
58
|
@deprecations[method] = true
|
36
59
|
end
|
37
|
-
|
38
|
-
warn(message)
|
60
|
+
|
61
|
+
warn(message)
|
39
62
|
end
|
40
63
|
end
|
41
64
|
end
|
42
65
|
|
43
|
-
yield
|
66
|
+
yield if block_given?
|
67
|
+
end
|
68
|
+
|
69
|
+
# Helper method for tests to silence deprecation warnings within a block. You should
|
70
|
+
# not use this in production code since it will silence all deprecation warnings
|
71
|
+
# globally across all threads.
|
72
|
+
#
|
73
|
+
# @param mode [Symbol, String] The deprecation mode to set within the block. Valid values are
|
74
|
+
# :normal, :verbose, :silent, and :raise.
|
75
|
+
# @yield The block in which to silence deprecation warnings.
|
76
|
+
# @return [Object] The result of the yielded block.
|
77
|
+
def with_deprecation_mode(mode)
|
78
|
+
save_mode = Lumberjack.deprecation_mode
|
79
|
+
begin
|
80
|
+
Lumberjack.deprecation_mode = mode
|
81
|
+
yield
|
82
|
+
ensure
|
83
|
+
Lumberjack.deprecation_mode = save_mode
|
84
|
+
end
|
44
85
|
end
|
45
86
|
|
46
87
|
# Get the hostname of the machine. The returned value will be in UTF-8 encoding.
|
88
|
+
# The hostname is cached after the first call for performance.
|
47
89
|
#
|
48
|
-
# @return [String] The hostname of the machine.
|
90
|
+
# @return [String] The hostname of the machine in UTF-8 encoding.
|
49
91
|
def hostname
|
50
92
|
if @hostname.equal?(UNDEFINED)
|
51
93
|
@hostname = force_utf8(Socket.gethostname)
|
@@ -53,83 +95,179 @@ module Lumberjack
|
|
53
95
|
@hostname
|
54
96
|
end
|
55
97
|
|
56
|
-
#
|
98
|
+
# Get the current line of code that calls this method. This is useful for debugging
|
99
|
+
# purposes to record the exact location in your code that generated a log entry.
|
100
|
+
#
|
101
|
+
# @param root_path [String, Pathname, nil] An optional root path to strip from the file path.
|
102
|
+
# @return [String] A string representation of the caller location (file:line:method).
|
103
|
+
#
|
104
|
+
# @example Adding source location to log entries
|
105
|
+
# logger.info("Something happened", source: Lumberjack::Utils.current_line)
|
106
|
+
# # Logs: "Something happened" with source: "/path/to/file.rb:123:in `method_name'"
|
107
|
+
def current_line(root_path = nil)
|
108
|
+
location = caller_locations(1, 1)[0]
|
109
|
+
path = location.path
|
110
|
+
if root_path
|
111
|
+
root_path = root_path.to_s
|
112
|
+
root_path = "#{root_path}#{File::SEPARATOR}" unless root_path.end_with?(File::SEPARATOR)
|
113
|
+
path = path.delete_prefix(root_path)
|
114
|
+
end
|
115
|
+
"#{path}:#{location.lineno}:in `#{location.label}'"
|
116
|
+
end
|
117
|
+
|
118
|
+
# Set the hostname to a specific value. This overrides the system hostname.
|
119
|
+
# Useful for testing or when you want to use a specific identifier.
|
57
120
|
#
|
58
|
-
# @param hostname [String]
|
121
|
+
# @param hostname [String] The hostname to use.
|
59
122
|
# @return [void]
|
60
123
|
def hostname=(hostname)
|
61
124
|
@hostname = force_utf8(hostname)
|
62
125
|
end
|
63
126
|
|
64
|
-
# Generate a global process
|
127
|
+
# Generate a global process identifier that includes the hostname and process ID.
|
128
|
+
# This creates a unique identifier that can distinguish processes across different machines.
|
65
129
|
#
|
66
|
-
# @return [String] The global process ID.
|
67
|
-
|
130
|
+
# @return [String] The global process ID in the format "hostname-pid".
|
131
|
+
#
|
132
|
+
# @example
|
133
|
+
# Lumberjack::Utils.global_pid
|
134
|
+
# # => "server1-12345"
|
135
|
+
def global_pid(pid = Process.pid)
|
68
136
|
if hostname
|
69
|
-
"#{hostname}-#{
|
137
|
+
"#{hostname}-#{pid}"
|
70
138
|
else
|
71
|
-
|
139
|
+
pid.to_s
|
72
140
|
end
|
73
141
|
end
|
74
142
|
|
75
|
-
# Generate a global thread
|
143
|
+
# Generate a global thread identifier that includes the global process ID and thread name.
|
144
|
+
# This creates a unique identifier for threads across processes and machines.
|
145
|
+
#
|
146
|
+
# @return [String] The global thread ID in the format "hostname-pid-threadname".
|
76
147
|
#
|
77
|
-
# @
|
148
|
+
# @example
|
149
|
+
# Lumberjack::Utils.global_thread_id
|
150
|
+
# # => "server1-12345-main" or "server1-12345-worker-1"
|
78
151
|
def global_thread_id
|
79
152
|
"#{global_pid}-#{thread_name}"
|
80
153
|
end
|
81
154
|
|
82
|
-
# Get
|
83
|
-
#
|
84
|
-
# characters
|
155
|
+
# Get a safe name for a thread. Uses the thread's assigned name if available,
|
156
|
+
# otherwise generates a unique identifier based on the thread's object ID.
|
157
|
+
# Non-alphanumeric characters (except underscores, dashes, and periods) are replaced
|
158
|
+
# with dashes to create URL-safe identifiers.
|
85
159
|
#
|
86
160
|
# @param thread [Thread] The thread to get the name for. Defaults to the current thread.
|
87
|
-
# @return [String]
|
161
|
+
# @return [String] A safe string identifier for the thread.
|
162
|
+
#
|
163
|
+
# @example
|
164
|
+
# Thread.current.name = "worker-thread"
|
165
|
+
# Lumberjack::Utils.thread_name # => "worker-thread"
|
166
|
+
#
|
167
|
+
# # For unnamed threads
|
168
|
+
# Lumberjack::Utils.thread_name # => "2c001a80c" (based on object_id)
|
88
169
|
def thread_name(thread = Thread.current)
|
89
170
|
thread.name ? slugify(thread.name) : thread.object_id.to_s(36)
|
90
171
|
end
|
91
172
|
|
92
|
-
# Force encode a string to UTF-8
|
93
|
-
#
|
173
|
+
# Force encode a string to UTF-8, handling invalid byte sequences gracefully.
|
174
|
+
# Any invalid or undefined byte sequences will be replaced with an empty string,
|
175
|
+
# ensuring the result is always valid UTF-8.
|
176
|
+
#
|
177
|
+
# @param str [String, nil] The string to encode. Returns nil if input is nil.
|
178
|
+
# @return [String, nil] The UTF-8 encoded string, or nil if input was nil.
|
94
179
|
#
|
95
|
-
# @
|
96
|
-
#
|
180
|
+
# @example
|
181
|
+
# # Handles strings with invalid encoding
|
182
|
+
# bad_string = "Hello\xff\xfeWorld".force_encoding("ASCII-8BIT")
|
183
|
+
# Lumberjack::Utils.force_utf8(bad_string) # => "HelloWorld"
|
97
184
|
def force_utf8(str)
|
98
185
|
return nil if str.nil?
|
99
186
|
|
100
187
|
str.dup.force_encoding("ASCII-8BIT").encode("UTF-8", invalid: :replace, undef: :replace, replace: "")
|
101
188
|
end
|
102
189
|
|
103
|
-
# Flatten a
|
190
|
+
# Flatten a nested attribute hash into a single-level hash using dot notation for nested keys.
|
191
|
+
# This is useful for converting structured data into a flat format suitable for logging systems
|
192
|
+
# that don't support nested structures.
|
193
|
+
#
|
194
|
+
# @param attr_hash [Hash] The hash to flatten. Non-hash values are ignored.
|
195
|
+
# @return [Hash<String, Object>] A flattened hash with dot-notation keys.
|
196
|
+
#
|
197
|
+
# @example Basic flattening
|
198
|
+
# hash = {user: {id: 123, profile: {name: "Alice"}}, action: "login"}
|
199
|
+
# Lumberjack::Utils.flatten_attributes(hash)
|
200
|
+
# # => {"user.id" => 123, "user.profile.name" => "Alice", "action" => "login"}
|
201
|
+
#
|
202
|
+
# @example With mixed types
|
203
|
+
# hash = {config: {db: {host: "localhost", port: 5432}}, debug: true}
|
204
|
+
# Lumberjack::Utils.flatten_attributes(hash)
|
205
|
+
# # => {"config.db.host" => "localhost", "config.db.port" => 5432, "debug" => true}
|
206
|
+
def flatten_attributes(attr_hash)
|
207
|
+
return {} unless attr_hash.is_a?(Hash)
|
208
|
+
|
209
|
+
flatten_hash_recursive(attr_hash)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Alias for {.flatten_attributes} to provide compatibility with the 1.x API.
|
213
|
+
# This method will eventually be removed in a future version.
|
104
214
|
#
|
105
215
|
# @param tag_hash [Hash] The hash to flatten.
|
106
216
|
# @return [Hash<String, Object>] The flattened hash.
|
107
|
-
# @
|
108
|
-
# expand_tags(user: {id: 123, name: "Alice"}, action: "login")})
|
109
|
-
# # => {"user.id" => 123, "user.name" => "Alice", "action" => "login"}
|
217
|
+
# @deprecated Use {.flatten_attributes} instead.
|
110
218
|
def flatten_tags(tag_hash)
|
111
|
-
|
112
|
-
|
113
|
-
|
219
|
+
Utils.deprecated("Lumberjack::Utils.flatten_tags", "Lumberjack::Utils.flatten_tags is deprecated and will be removed in version 2.1; use flatten_attributes instead.") do
|
220
|
+
flatten_attributes(tag_hash)
|
221
|
+
end
|
114
222
|
end
|
115
223
|
|
116
|
-
# Expand a hash
|
117
|
-
#
|
224
|
+
# Expand a hash containing dot notation keys into a nested hash structure.
|
225
|
+
# This is the inverse operation of {.flatten_attributes} and is useful for converting
|
226
|
+
# flat attribute structures back into nested hashes.
|
118
227
|
#
|
119
|
-
# @param
|
120
|
-
# @return [Hash]
|
228
|
+
# @param attributes [Hash] The hash with dot notation keys to expand. Non-hash values are ignored.
|
229
|
+
# @return [Hash] A nested hash with dot notation keys expanded into nested structures.
|
121
230
|
#
|
122
|
-
# @example
|
123
|
-
#
|
231
|
+
# @example Basic expansion
|
232
|
+
# flat = {"user.id" => 123, "user.name" => "Alice", "action" => "login"}
|
233
|
+
# Lumberjack::Utils.expand_attributes(flat)
|
124
234
|
# # => {"user" => {"id" => 123, "name" => "Alice"}, "action" => "login"}
|
125
|
-
|
126
|
-
|
235
|
+
#
|
236
|
+
# @example Deep nesting
|
237
|
+
# flat = {"app.db.host" => "localhost", "app.db.port" => 5432, "app.debug" => true}
|
238
|
+
# Lumberjack::Utils.expand_attributes(flat)
|
239
|
+
# # => {"app" => {"db" => {"host" => "localhost", "port" => 5432}, "debug" => true}}
|
240
|
+
#
|
241
|
+
# @example Mixed with existing nested structures
|
242
|
+
# mixed = {"user.id" => 123, "settings" => {"theme" => "dark"}}
|
243
|
+
# Lumberjack::Utils.expand_attributes(mixed)
|
244
|
+
# # => {"user" => {"id" => 123}, "settings" => {"theme" => "dark"}}
|
245
|
+
def expand_attributes(attributes)
|
246
|
+
return {} unless attributes.is_a?(Hash)
|
127
247
|
|
128
|
-
expand_dot_notation_hash(
|
248
|
+
expand_dot_notation_hash(attributes)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Alias for {.expand_attributes} to provide compatibility with the 1.x API.
|
252
|
+
# This method will eventually be removed in a future version.
|
253
|
+
#
|
254
|
+
# @param tags [Hash] The hash to expand.
|
255
|
+
# @return [Hash] The expanded hash.
|
256
|
+
# @deprecated Use {.expand_attributes} instead.
|
257
|
+
def expand_tags(tags)
|
258
|
+
Utils.deprecated("Lumberjack::Utils.expand_tags", "Lumberjack::Utils.expand_tags is deprecated and will be removed in version 2.1; use expand_attributes instead.") do
|
259
|
+
expand_attributes(tags)
|
260
|
+
end
|
129
261
|
end
|
130
262
|
|
131
263
|
private
|
132
264
|
|
265
|
+
# Recursively flatten a hash, building dot notation keys for nested structures.
|
266
|
+
#
|
267
|
+
# @param hash [Hash] The hash to flatten.
|
268
|
+
# @param prefix [String, nil] The current key prefix for nested structures.
|
269
|
+
# @return [Hash<String, Object>] The flattened hash.
|
270
|
+
# @api private
|
133
271
|
def flatten_hash_recursive(hash, prefix = nil)
|
134
272
|
hash.each_with_object({}) do |(key, value), result|
|
135
273
|
full_key = prefix ? "#{prefix}.#{key}" : key.to_s
|
@@ -141,6 +279,12 @@ module Lumberjack
|
|
141
279
|
end
|
142
280
|
end
|
143
281
|
|
282
|
+
# Convert a string to a URL-safe slug by replacing non-alphanumeric characters
|
283
|
+
# (except underscores, dashes, and periods) with dashes, and removing leading/trailing dashes.
|
284
|
+
#
|
285
|
+
# @param str [String, nil] The string to slugify.
|
286
|
+
# @return [String, nil] The slugified string, or nil if input was nil.
|
287
|
+
# @api private
|
144
288
|
def slugify(str)
|
145
289
|
return nil if str.nil?
|
146
290
|
|
@@ -150,6 +294,12 @@ module Lumberjack
|
|
150
294
|
str
|
151
295
|
end
|
152
296
|
|
297
|
+
# Recursively expand dot notation keys in a hash into nested structures.
|
298
|
+
#
|
299
|
+
# @param hash [Hash] The hash containing dot notation keys to expand.
|
300
|
+
# @param expanded [Hash] The target hash to store expanded results.
|
301
|
+
# @return [Hash] The expanded hash with nested structures.
|
302
|
+
# @api private
|
153
303
|
def expand_dot_notation_hash(hash, expanded = {})
|
154
304
|
return hash unless hash.is_a?(Hash)
|
155
305
|
|
data/lib/lumberjack.rb
CHANGED
@@ -2,117 +2,225 @@
|
|
2
2
|
|
3
3
|
require "rbconfig"
|
4
4
|
require "time"
|
5
|
-
require "securerandom"
|
6
5
|
require "logger"
|
7
6
|
require "fiber"
|
7
|
+
require "pathname"
|
8
8
|
|
9
|
+
# Lumberjack is a flexible logging framework for Ruby that extends the standard
|
10
|
+
# Logger functionality with structured logging, context isolation, and advanced
|
11
|
+
# formatting capabilities.
|
12
|
+
#
|
13
|
+
# The main features include:
|
14
|
+
# - Structured logging with attributes for machine-readable metadata
|
15
|
+
# - Context isolation for scoping logging behavior to specific code blocks
|
16
|
+
# - Flexible formatters for customizing log output
|
17
|
+
# - Multiple output devices and templates
|
18
|
+
# - Built-in testing utilities
|
19
|
+
#
|
20
|
+
# @example Basic usage
|
21
|
+
# logger = Lumberjack::Logger.new(STDOUT)
|
22
|
+
# logger.info("Hello world")
|
23
|
+
#
|
24
|
+
# @example Using contexts
|
25
|
+
# Lumberjack.context do
|
26
|
+
# Lumberjack.tag(user_id: 123)
|
27
|
+
# logger.info("User action") # Will include user_id: 123
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# @see Lumberjack::Logger
|
31
|
+
# @see Lumberjack::ContextLogger
|
9
32
|
module Lumberjack
|
33
|
+
VERSION = File.read(File.join(__dir__, "..", "VERSION")).strip.freeze
|
34
|
+
|
10
35
|
LINE_SEPARATOR = ((RbConfig::CONFIG["host_os"] =~ /mswin/i) ? "\r\n" : "\n")
|
11
36
|
|
12
|
-
require_relative "lumberjack/
|
13
|
-
require_relative "lumberjack/
|
37
|
+
require_relative "lumberjack/device_registry"
|
38
|
+
require_relative "lumberjack/template_registry"
|
39
|
+
require_relative "lumberjack/formatter_registry"
|
14
40
|
|
41
|
+
require_relative "lumberjack/attribute_formatter"
|
42
|
+
require_relative "lumberjack/attributes_helper"
|
15
43
|
require_relative "lumberjack/context"
|
44
|
+
require_relative "lumberjack/context_logger"
|
45
|
+
require_relative "lumberjack/fiber_locals"
|
46
|
+
require_relative "lumberjack/io_compatibility"
|
16
47
|
require_relative "lumberjack/log_entry"
|
48
|
+
require_relative "lumberjack/log_entry_matcher"
|
17
49
|
require_relative "lumberjack/device"
|
50
|
+
require_relative "lumberjack/entry_formatter"
|
51
|
+
require_relative "lumberjack/formatter"
|
52
|
+
require_relative "lumberjack/forked_logger"
|
18
53
|
require_relative "lumberjack/logger"
|
19
|
-
require_relative "lumberjack/
|
20
|
-
require_relative "lumberjack/
|
21
|
-
require_relative "lumberjack/
|
22
|
-
require_relative "lumberjack/tagged_logger_support"
|
23
|
-
require_relative "lumberjack/tagged_logging"
|
24
|
-
require_relative "lumberjack/template"
|
54
|
+
require_relative "lumberjack/local_log_template"
|
55
|
+
require_relative "lumberjack/message_attributes"
|
56
|
+
require_relative "lumberjack/remap_attribute"
|
25
57
|
require_relative "lumberjack/rack"
|
58
|
+
require_relative "lumberjack/severity"
|
59
|
+
require_relative "lumberjack/template"
|
26
60
|
require_relative "lumberjack/utils"
|
27
61
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
#
|
33
|
-
# You can specify the id for the unit of work if desired. If you don't supply
|
34
|
-
# it, a 12 digit hexidecimal number will be automatically generated for you.
|
35
|
-
#
|
36
|
-
# For the common use case of treating a single web request as a unit of work, see the
|
37
|
-
# Lumberjack::Rack::UnitOfWork class.
|
38
|
-
#
|
39
|
-
# @param id [String] The id for the unit of work.
|
40
|
-
# @return [void]
|
41
|
-
# @deprecated Use tags instead. This will be removed in version 2.0.
|
42
|
-
def unit_of_work(id = nil)
|
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
|
49
|
-
end
|
50
|
-
end
|
62
|
+
# Deprecated
|
63
|
+
require_relative "lumberjack/tag_context"
|
64
|
+
require_relative "lumberjack/tag_formatter"
|
65
|
+
require_relative "lumberjack/tags"
|
51
66
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def unit_of_work_id
|
57
|
-
context[:unit_of_work_id]
|
58
|
-
end
|
67
|
+
@global_contexts = {}
|
68
|
+
@global_contexts_mutex = Mutex.new
|
69
|
+
@deprecation_mode = nil
|
70
|
+
@raise_logger_errors = false
|
59
71
|
|
60
|
-
|
72
|
+
class << self
|
73
|
+
# Contexts can be used to store attributes that will be attached to all log entries in the block.
|
61
74
|
# The context will apply to all Lumberjack loggers that are used within the block.
|
62
75
|
#
|
63
76
|
# If this method is called with a block, it will set a logging context for the scope of a block.
|
64
77
|
# If there is already a context in scope, a new one will be created that inherits
|
65
|
-
# all the
|
78
|
+
# all the attributes of the parent context.
|
66
79
|
#
|
67
80
|
# Otherwise, it will return the current context. If one doesn't exist, it will return a new one
|
68
81
|
# but that context will not be in any scope.
|
69
82
|
#
|
70
|
-
# @return [
|
83
|
+
# @return [Object] The result
|
84
|
+
# of the block
|
71
85
|
def context(&block)
|
72
|
-
current_context
|
73
|
-
|
74
|
-
|
86
|
+
use_context(Context.new(current_context), &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Ensure that the block of code is wrapped by a global context. If there is not already
|
90
|
+
# a context in scope, one will be created.
|
91
|
+
#
|
92
|
+
# @return [Object] The result of the block.
|
93
|
+
def ensure_context(&block)
|
94
|
+
if in_context?
|
95
|
+
yield
|
75
96
|
else
|
76
|
-
|
97
|
+
context(&block)
|
77
98
|
end
|
78
99
|
end
|
79
100
|
|
80
101
|
# Set the context to use within a block.
|
81
102
|
#
|
82
|
-
# @param [Lumberjack::Context]
|
103
|
+
# @param context [Lumberjack::Context] The context to use within the block.
|
83
104
|
# @return [Object] The result of the block.
|
105
|
+
# @api private
|
84
106
|
def use_context(context, &block)
|
85
|
-
|
107
|
+
fiber_id = Fiber.current.object_id
|
108
|
+
ctx = @global_contexts[fiber_id]
|
86
109
|
begin
|
87
|
-
|
110
|
+
@global_contexts_mutex.synchronize do
|
111
|
+
@global_contexts[fiber_id] = (context || Context.new)
|
112
|
+
end
|
88
113
|
yield
|
89
114
|
ensure
|
90
|
-
|
115
|
+
@global_contexts_mutex.synchronize do
|
116
|
+
if ctx.nil?
|
117
|
+
@global_contexts.delete(fiber_id)
|
118
|
+
else
|
119
|
+
@global_contexts[fiber_id] = ctx
|
120
|
+
end
|
121
|
+
end
|
91
122
|
end
|
92
123
|
end
|
93
124
|
|
94
125
|
# Return true if inside a context block.
|
95
126
|
#
|
96
127
|
# @return [Boolean]
|
128
|
+
def in_context?
|
129
|
+
!!@global_contexts[Fiber.current.object_id]
|
130
|
+
end
|
131
|
+
|
97
132
|
def context?
|
98
|
-
|
133
|
+
Utils.deprecated("Lumberjack.context?", "Lumberjack.context? is deprecated and will be removed in version 2.1; use in_context? instead.") do
|
134
|
+
in_context?
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Return attributes that will be applied to all Lumberjack loggers.
|
139
|
+
#
|
140
|
+
# @return [Hash, nil]
|
141
|
+
def context_attributes
|
142
|
+
current_context&.attributes
|
99
143
|
end
|
100
144
|
|
101
|
-
#
|
145
|
+
# Alias for context_attributes to provide API compatibility with version 1.x.
|
146
|
+
# This method will eventually be removed.
|
102
147
|
#
|
103
148
|
# @return [Hash, nil]
|
149
|
+
# @deprecated Use {.context_attributes}
|
104
150
|
def context_tags
|
105
|
-
|
106
|
-
|
151
|
+
Utils.deprecated("Lumberjack.context_tags", "Lumberjack.context_tags is deprecated and will be removed in version 2.1; use context_attributes instead.") do
|
152
|
+
context_attributes
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Tag all loggers with attributes on the current context.
|
157
|
+
#
|
158
|
+
# @param attributes [Hash] The attributes to set.
|
159
|
+
# @param block [Proc] optional context block in which to set the attributes.
|
160
|
+
# @return [void]
|
161
|
+
def tag(attributes, &block)
|
162
|
+
if block
|
163
|
+
context do
|
164
|
+
current_context.assign_attributes(attributes)
|
165
|
+
block.call
|
166
|
+
end
|
167
|
+
else
|
168
|
+
current_context&.assign_attributes(attributes)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Helper method to build an entry formatter.
|
173
|
+
#
|
174
|
+
# @param block [Proc] The block to use for building the entry formatter.
|
175
|
+
# @return [Lumberjack::EntryFormatter] The built entry formatter.
|
176
|
+
# @see Lumberjack::EntryFormatter.build
|
177
|
+
def build_formatter(&block)
|
178
|
+
EntryFormatter.build(&block)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Control how use of deprecated methods is handled. The default is to print a warning
|
182
|
+
# the first time a deprecated method is called. Setting this to :verbose will print
|
183
|
+
# a warning every time a deprecated method is called. Setting this to :silent will
|
184
|
+
# suppress all deprecation warnings. Setting this to :raise will raise an exception
|
185
|
+
# when a deprecated method is called.
|
186
|
+
#
|
187
|
+
# The default value can be set with the +LUMBERJACK_DEPRECATION_WARNINGS+ environment variable.
|
188
|
+
#
|
189
|
+
# @param value [Symbol, String, nil] The deprecation mode to set. Valid values are :normal,
|
190
|
+
# :verbose, :silent, and :raise.
|
191
|
+
def deprecation_mode=(value)
|
192
|
+
@deprecation_mode = value&.to_sym
|
107
193
|
end
|
108
194
|
|
109
|
-
#
|
195
|
+
# @return [Symbol] The current deprecation mode.
|
196
|
+
# @api private
|
197
|
+
def deprecation_mode
|
198
|
+
@deprecation_mode ||= ENV.fetch("LUMBERJACK_DEPRECATION_WARNINGS", "normal").to_sym
|
199
|
+
end
|
200
|
+
|
201
|
+
# Set whether errors encountered while logging entries should be raised. The default behavior
|
202
|
+
# is to rescue these errors and print them to standard error. Otherwise there can be no way
|
203
|
+
# to record the error since it cannot be logged.
|
110
204
|
#
|
111
|
-
#
|
205
|
+
# You can set this to true in you test and development environments to catch logging errors
|
206
|
+
# before they make it to production.
|
207
|
+
#
|
208
|
+
# @param value [Boolean] Whether to raise logger errors.
|
112
209
|
# @return [void]
|
113
|
-
def
|
114
|
-
|
115
|
-
|
210
|
+
def raise_logger_errors=(value)
|
211
|
+
@raise_logger_errors = !!value
|
212
|
+
end
|
213
|
+
|
214
|
+
# @return [Boolean] Whether logger errors should be raised.
|
215
|
+
# @api private
|
216
|
+
def raise_logger_errors?
|
217
|
+
@raise_logger_errors
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def current_context
|
223
|
+
@global_contexts[Fiber.current.object_id]
|
116
224
|
end
|
117
225
|
end
|
118
226
|
end
|
data/lumberjack.gemspec
CHANGED
@@ -4,7 +4,7 @@ Gem::Specification.new do |spec|
|
|
4
4
|
spec.authors = ["Brian Durand"]
|
5
5
|
spec.email = ["bbdurand@gmail.com"]
|
6
6
|
|
7
|
-
spec.summary = "
|
7
|
+
spec.summary = "Extension of Ruby’s standard Logger for advanced, structured logging. Includes log entry attributes, context isolation, customizable formatters, flexible output devices, and testing tools."
|
8
8
|
spec.homepage = "https://github.com/bdurand/lumberjack"
|
9
9
|
spec.license = "MIT"
|
10
10
|
|
@@ -31,7 +31,9 @@ Gem::Specification.new do |spec|
|
|
31
31
|
|
32
32
|
spec.require_paths = ["lib"]
|
33
33
|
|
34
|
-
spec.required_ruby_version = ">= 2.
|
34
|
+
spec.required_ruby_version = ">= 2.7"
|
35
|
+
|
36
|
+
spec.add_runtime_dependency "logger"
|
35
37
|
|
36
38
|
spec.add_development_dependency "bundler"
|
37
39
|
end
|