lumberjack 1.3.2 → 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/CHANGELOG.md +32 -0
- data/README.md +24 -8
- data/VERSION +1 -1
- data/lib/lumberjack/context.rb +12 -5
- data/lib/lumberjack/log_entry.rb +18 -1
- data/lib/lumberjack/logger.rb +46 -49
- data/lib/lumberjack/tag_context.rb +78 -0
- data/lib/lumberjack/utils.rb +57 -8
- data/lib/lumberjack.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c72bca9355bd37fb691a06a4cea4a341b6905b7b5c15429d41061b2b0afd3813
|
4
|
+
data.tar.gz: 49a18195fadf1de9b2cf43e3ce95c1f5e49d3d81dd4384a722e8f685187f6bbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d58e6244cad6396bf702759c05a130e279d4def0d7bee491817b373fbee79420fa0df776264485e7387657a7dd28bab7e4690b7b0a677d878b98f611432a7f7
|
7
|
+
data.tar.gz: d2c2c8f1765230b39df298c68c89bad1db520acbaabfee7da7381d75336de91ff9c3f709e501683fb2502f6b5f7b61eef89c8814f13fda6c2235c3ac43ef5959
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,38 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 1.4.0
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
|
11
|
+
- Tags are consistently flattened internally to dot notation keys. This makes tag handling more consistent when using nested hashes as tag values. This changes how nested tags are merged, though. Now when new nested tags are set they will be merged into the existing tags rather than replacing them entirely. So `logger.tag(foo: {bar: "baz"})` will now merge the `foo.bar` tag into the existing tags rather than replacing the entire `foo` tag.
|
12
|
+
- The `Lumberjack::Logger#context` method can now be called without a block. When called with a block it sets up a new tag context for the block. When called without a block, it returns the current tag context in a `Lumberjack::TagContext` object which can be used to add tags to the current context.
|
13
|
+
- Tags in `Lumberjack::LogEntry` are now always stored as a hash of flattened keys. This means that when tags are set on a log entry, they will be automatically flattened to dot notation keys. The `tag` method will return a hash of sub-tags if the tag name is a tag prefix.
|
14
|
+
|
15
|
+
### Added
|
16
|
+
|
17
|
+
- Added `Lumberjack::LogEntry#nested_tags` method to return the tags as a nested hash structure.
|
18
|
+
|
19
|
+
## 1.3.4
|
20
|
+
|
21
|
+
### Added
|
22
|
+
|
23
|
+
- Added `Lumberjack::Logger#with_progname` alias for `set_progname` to match the naming convention used for setting temporary levels.
|
24
|
+
|
25
|
+
### Fixed
|
26
|
+
|
27
|
+
- Ensure that the safety check for circular calls to `Lumberjack::Logger#add_entry` cannot lose state.
|
28
|
+
|
29
|
+
## 1.3.3
|
30
|
+
|
31
|
+
### Added
|
32
|
+
|
33
|
+
- Added `Lumberjack::Utils#expand_tags` method to expand a hash of tags that may contain nested hashes or dot notation keys.
|
34
|
+
|
35
|
+
### Changed
|
36
|
+
|
37
|
+
- Updated `Lumberjack::Utils#flatten_tags` to convert all keys to strings.
|
38
|
+
|
7
39
|
## 1.3.2
|
8
40
|
|
9
41
|
### Fixed
|
data/README.md
CHANGED
@@ -50,7 +50,7 @@ logger.info("request completed", duration: elapsed_time, status: response.status
|
|
50
50
|
You can also specify tags on a logger that will be included with every log message.
|
51
51
|
|
52
52
|
```ruby
|
53
|
-
logger.
|
53
|
+
logger.tag_globally(host: Socket.gethostname.force_encoding("UTF-8"))
|
54
54
|
```
|
55
55
|
|
56
56
|
You can specify tags that will only be applied to the logger in a block as well.
|
@@ -64,22 +64,37 @@ end
|
|
64
64
|
logger.info("there") # Will not include the `thread_id` or `count` tag
|
65
65
|
```
|
66
66
|
|
67
|
+
The block opens up a new tag context. The context applies only within a block and only for the currently executing thread. You can also open up a new context block without specifying any tags and then add tags to the context within the block.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
logger.context do # When a block is given to `context`, it opens a new empty tag context.
|
71
|
+
# `context` can be called without a block, to get an TagContext object for manipulating tags.
|
72
|
+
logger.context.tag(user_id: current_user.id, username: current_user.username)
|
73
|
+
logger.context["user_role"] = current_user.role # You can also use hash syntax to set tags.
|
74
|
+
logger.info("user logged in") # Will include the `user_id`, `username`, and `user_role` tags.
|
75
|
+
end
|
76
|
+
logger.info("no user") # Will not include the tags
|
77
|
+
```
|
78
|
+
|
67
79
|
You can also set tags to `Proc` objects that will be evaluated when creating a log entry.
|
68
80
|
|
69
81
|
```ruby
|
70
|
-
logger.
|
82
|
+
logger.tag_globally(thread_id: lambda { Thread.current.object_id })
|
83
|
+
|
71
84
|
Thread.new do
|
72
85
|
logger.info("inside thread") # Will include the `thread_id` tag with id of the spawned thread
|
73
86
|
end
|
87
|
+
|
74
88
|
logger.info("outside thread") # Will include the `thread_id` tag with id of the main thread
|
75
89
|
```
|
76
90
|
|
77
|
-
Finally, you can specify a logging context
|
91
|
+
Finally, you can specify a global logging context that applies to all loggers.
|
78
92
|
|
79
93
|
```ruby
|
80
94
|
Lumberjack.context do
|
81
|
-
Lumberjack.tag(request_id: SecureRandom.hex)
|
95
|
+
Lumberjack.tag(request_id: SecureRandom.hex) # add a global context tag
|
82
96
|
logger.info("begin request") # Will include the `request_id` tag
|
97
|
+
event_logger.info("http.request") # Will also include the `request_id` tag
|
83
98
|
end
|
84
99
|
logger.info("no requests") # Will not include the `request_id` tag
|
85
100
|
```
|
@@ -134,7 +149,7 @@ When combined with structured output devices (like [`lumberjack_json_device`](ht
|
|
134
149
|
|
135
150
|
#### Compatibility with ActiveSupport::TaggedLogging
|
136
151
|
|
137
|
-
`Lumberjack::Logger`
|
152
|
+
`Lumberjack::Logger` is compatible with `ActiveSupport::TaggedLogging`. This is so that other code that expects to have a logger that responds to the `tagged` method will work. Any tags added with the `tagged` method will be appended to an array in the "tagged" tag.
|
138
153
|
|
139
154
|
```ruby
|
140
155
|
logger.tagged("foo", "bar=1", "other") do
|
@@ -199,6 +214,7 @@ There are several built in classes you can add as formatters. You can use a symb
|
|
199
214
|
- `:pretty_print` - `Lumberjack::Formatter::PrettyPrintFormatter` - returns the pretty print format of the object.
|
200
215
|
- `:id` - `Lumberjack::Formatter::IdFormatter` - returns a hash of the object with keys for the id attribute and class.
|
201
216
|
- `:structured` - `Lumberjack::Formatter::StructuredFormatter` - crawls the object and applies the formatter recursively to Enumerable objects found in it (arrays, hashes, etc.).
|
217
|
+
- `:truncate` - `Lumberjack::Formatter::TruncateFormatter` - truncates long strings to a specified length.
|
202
218
|
|
203
219
|
To define your own formatter, either provide a block or an object that responds to `call` with a single argument.
|
204
220
|
|
@@ -260,7 +276,7 @@ logger.tag_formatter.add("user.username", &:upcase)
|
|
260
276
|
|
261
277
|
#### Templates
|
262
278
|
|
263
|
-
If you use the built-in `Lumberjack::Writer` derived devices, you can also customize the Template used to format the LogEntry.
|
279
|
+
If you use the built-in `Lumberjack::Device::Writer` derived devices, you can also customize the Template used to format the LogEntry.
|
264
280
|
|
265
281
|
See `Lumberjack::Template` for a complete list of macros you can use in the template. You can also use a block that receives a `Lumberjack::LogEntry` as a template.
|
266
282
|
|
@@ -286,7 +302,7 @@ The logger has hooks for devices that support buffering to potentially increase
|
|
286
302
|
|
287
303
|
You can use the `:flush_seconds` option on the logger to periodically flush the log. This is usually a good idea so you can more easily debug hung processes. Without periodic flushing, a process that hangs may never write anything to the log because the messages are sitting in a buffer. By turning on periodic flushing, the logged messages will be written which can greatly aid in debugging the problem.
|
288
304
|
|
289
|
-
The built in stream based logging devices use an internal buffer. The size of the buffer (in bytes) can be set with the `:buffer_size` options when initializing a logger. The default behavior is to not
|
305
|
+
The built in stream based logging devices use an internal buffer. The size of the buffer (in bytes) can be set with the `:buffer_size` options when initializing a logger. The default behavior is to not buffer.
|
290
306
|
|
291
307
|
```ruby
|
292
308
|
# Set buffer to flush after 8K has been written to the log.
|
@@ -361,7 +377,7 @@ To change the log message format to output JSON, you could use this code:
|
|
361
377
|
config.logger = Lumberjack::Logger.new(log_file_path, :template => lambda{|e| JSON.dump(time: e.time, level: e.severity_label, message: e.message)})
|
362
378
|
```
|
363
379
|
|
364
|
-
To send log messages to syslog instead of to a file, you could use this (
|
380
|
+
To send log messages to syslog instead of to a file, you could use this (requires the lumberjack_syslog_device gem):
|
365
381
|
|
366
382
|
```ruby
|
367
383
|
config.logger = Lumberjack::Logger.new(Lumberjack::SyslogDevice.new)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/lib/lumberjack/context.rb
CHANGED
@@ -9,6 +9,7 @@ module Lumberjack
|
|
9
9
|
def initialize(parent_context = nil)
|
10
10
|
@tags = {}
|
11
11
|
@tags.merge!(parent_context.tags) if parent_context
|
12
|
+
@tag_context = TagContext.new(@tags)
|
12
13
|
end
|
13
14
|
|
14
15
|
# Set tags on the context.
|
@@ -16,9 +17,7 @@ module Lumberjack
|
|
16
17
|
# @param tags [Hash] The tags to set.
|
17
18
|
# @return [void]
|
18
19
|
def tag(tags)
|
19
|
-
tags
|
20
|
-
@tags[key.to_s] = value
|
21
|
-
end
|
20
|
+
@tag_context.tag(tags)
|
22
21
|
end
|
23
22
|
|
24
23
|
# Get a context tag.
|
@@ -26,7 +25,7 @@ module Lumberjack
|
|
26
25
|
# @param key [String, Symbol] The tag key.
|
27
26
|
# @return [Object] The tag value.
|
28
27
|
def [](key)
|
29
|
-
@
|
28
|
+
@tag_context[key]
|
30
29
|
end
|
31
30
|
|
32
31
|
# Set a context tag.
|
@@ -35,7 +34,15 @@ module Lumberjack
|
|
35
34
|
# @param value [Object] The tag value.
|
36
35
|
# @return [void]
|
37
36
|
def []=(key, value)
|
38
|
-
@
|
37
|
+
@tag_context[key] = value
|
38
|
+
end
|
39
|
+
|
40
|
+
# Remove tags from the context.
|
41
|
+
#
|
42
|
+
# @param keys [Array<String, Symbol>] The tag keys to remove.
|
43
|
+
# @return [void]
|
44
|
+
def delete(*keys)
|
45
|
+
@tag_context.delete(*keys)
|
39
46
|
end
|
40
47
|
|
41
48
|
# Clear all the context data.
|
data/lib/lumberjack/log_entry.rb
CHANGED
@@ -64,11 +64,28 @@ module Lumberjack
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# Return the tag with the specified name.
|
67
|
+
#
|
68
|
+
# @param name [String, Symbol] The tag name.
|
69
|
+
# @return [Object, nil] The tag value or nil if the tag does not exist.
|
67
70
|
def tag(name)
|
68
|
-
tags[name
|
71
|
+
TagContext.new(tags)[name]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Helper method to expand the tags into a nested structure. Tags with dots in the name
|
75
|
+
# will be expanded into nested hashes.
|
76
|
+
#
|
77
|
+
# @return [Hash] The tags expanded into a nested structure.
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# entry = Lumberjack::LogEntry.new(Time.now, Logger::INFO, "test", "app", 1500, "a.b.c" => 1, "a.b.d" => 2)
|
81
|
+
# entry.nested_tags # => {"a" => {"b" => {"c" => 1, "d" => 2}}}
|
82
|
+
def nested_tags
|
83
|
+
Utils.expand_tags(tags)
|
69
84
|
end
|
70
85
|
|
71
86
|
# Return true if the log entry has no message and no tags.
|
87
|
+
#
|
88
|
+
# @return [Boolean] True if the log entry is empty, false otherwise.
|
72
89
|
def empty?
|
73
90
|
(message.nil? || message == "") && (tags.nil? || tags.empty?)
|
74
91
|
end
|
data/lib/lumberjack/logger.rb
CHANGED
@@ -200,12 +200,12 @@ module Lumberjack
|
|
200
200
|
# logger.add_entry(:warn, "Request took a long time")
|
201
201
|
# logger.add_entry(Logger::DEBUG){"Start processing with options #{options.inspect}"}
|
202
202
|
def add_entry(severity, message, progname = nil, tags = nil)
|
203
|
-
|
204
|
-
|
205
|
-
|
203
|
+
severity = Severity.label_to_level(severity) unless severity.is_a?(Integer)
|
204
|
+
return true unless device && severity && severity >= level
|
205
|
+
return true if Thread.current[:lumberjack_logging]
|
206
206
|
|
207
|
-
|
208
|
-
Thread.current[:lumberjack_logging] = true
|
207
|
+
begin
|
208
|
+
Thread.current[:lumberjack_logging] = true # Prevent circular calls to add_entry
|
209
209
|
|
210
210
|
time = Time.now
|
211
211
|
|
@@ -223,6 +223,7 @@ module Lumberjack
|
|
223
223
|
end
|
224
224
|
|
225
225
|
progname ||= self.progname
|
226
|
+
message_tags = Utils.flatten_tags(message_tags) if message_tags
|
226
227
|
|
227
228
|
current_tags = self.tags
|
228
229
|
tags = nil unless tags.is_a?(Hash)
|
@@ -380,7 +381,7 @@ module Lumberjack
|
|
380
381
|
|
381
382
|
# Return +true+ if +INFO+ messages are being logged.
|
382
383
|
#
|
383
|
-
|
384
|
+
# @return [Boolean]
|
384
385
|
def info?
|
385
386
|
level <= INFO
|
386
387
|
end
|
@@ -465,7 +466,7 @@ module Lumberjack
|
|
465
466
|
# @param [Integer, String, Symbol] level The log level to use inside the block.
|
466
467
|
# @return [Object] The result of the block.
|
467
468
|
def log_at(level, &block)
|
468
|
-
|
469
|
+
with_level(level, &block)
|
469
470
|
end
|
470
471
|
|
471
472
|
# Set the program name that is associated with log messages. If a block
|
@@ -481,6 +482,15 @@ module Lumberjack
|
|
481
482
|
end
|
482
483
|
end
|
483
484
|
|
485
|
+
# Set the logger progname for the duration of the block.
|
486
|
+
#
|
487
|
+
# @yield [Object] The block to execute with the program name set.
|
488
|
+
# @param [String] value The program name to use.
|
489
|
+
# @return [Object] The result of the block.
|
490
|
+
def with_progname(value, &block)
|
491
|
+
set_progname(value, &block)
|
492
|
+
end
|
493
|
+
|
484
494
|
# Get the program name associated with log messages.
|
485
495
|
#
|
486
496
|
# @return [String]
|
@@ -498,16 +508,16 @@ module Lumberjack
|
|
498
508
|
# @param [Hash] tags The tags to set.
|
499
509
|
# @return [void]
|
500
510
|
def tag(tags, &block)
|
501
|
-
tags = Tags.stringify_keys(tags)
|
502
511
|
thread_tags = thread_local_value(:lumberjack_logger_tags)
|
503
512
|
if block
|
504
|
-
merged_tags = (thread_tags ? thread_tags.
|
513
|
+
merged_tags = (thread_tags ? thread_tags.dup : {})
|
514
|
+
TagContext.new(merged_tags).tag(tags)
|
505
515
|
push_thread_local_value(:lumberjack_logger_tags, merged_tags, &block)
|
506
516
|
elsif thread_tags
|
507
|
-
thread_tags.
|
517
|
+
TagContext.new(thread_tags).tag(tags)
|
508
518
|
nil
|
509
519
|
else
|
510
|
-
|
520
|
+
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
|
511
521
|
tag_globally(tags)
|
512
522
|
end
|
513
523
|
end
|
@@ -516,10 +526,21 @@ module Lumberjack
|
|
516
526
|
# Set up a context block for the logger. All tags added within the block will be cleared when
|
517
527
|
# the block exits.
|
518
528
|
#
|
529
|
+
# @param [Proc] block The block to execute with the tag context.
|
530
|
+
# @return [TagContext] If no block is passed, then a Lumberjack::TagContext is returned that can be used
|
531
|
+
# to interact with the tags (add, remove, etc.).
|
532
|
+
# @yield [TagContext] If a block is passed, it will be yielded a TagContext object that can be used to
|
533
|
+
# add or remove tags within the context.
|
519
534
|
def context(&block)
|
520
|
-
|
521
|
-
|
522
|
-
|
535
|
+
if block
|
536
|
+
thread_tags = thread_local_value(:lumberjack_logger_tags)&.dup
|
537
|
+
thread_tags ||= {}
|
538
|
+
push_thread_local_value(:lumberjack_logger_tags, thread_tags) do
|
539
|
+
block.call(TagContext.new(thread_tags))
|
540
|
+
end
|
541
|
+
else
|
542
|
+
TagContext.new(thread_local_value(:lumberjack_logger_tags) || {})
|
543
|
+
end
|
523
544
|
end
|
524
545
|
|
525
546
|
# Add global tags to the logger that will appear on all log entries.
|
@@ -527,24 +548,19 @@ module Lumberjack
|
|
527
548
|
# @param [Hash] tags The tags to set.
|
528
549
|
# @return [void]
|
529
550
|
def tag_globally(tags)
|
530
|
-
tags
|
531
|
-
@tags.merge!(tags)
|
551
|
+
TagContext.new(@tags).tag(tags)
|
532
552
|
nil
|
533
553
|
end
|
534
554
|
|
535
|
-
# Remove a tag from the current tag context. If this is called inside a
|
536
|
-
#
|
537
|
-
#
|
555
|
+
# Remove a tag from the current tag context. If this is called inside a tag context,
|
556
|
+
# the tags will only be removed for the duration of that block. Otherwise they will be removed
|
557
|
+
# from the global tags.
|
538
558
|
#
|
539
559
|
# @param [Array<String, Symbol>] tag_names The tags to remove.
|
540
560
|
# @return [void]
|
541
561
|
def remove_tag(*tag_names)
|
542
|
-
|
543
|
-
|
544
|
-
tag_names.each { |name| thread_tags.delete(name.to_s) }
|
545
|
-
else
|
546
|
-
tag_names.each { |name| @tags.delete(name.to_s) }
|
547
|
-
end
|
562
|
+
tags = thread_local_value(:lumberjack_logger_tags) || @tags
|
563
|
+
TagContext.new(tags).delete(*tag_names)
|
548
564
|
end
|
549
565
|
|
550
566
|
# Return all tags in scope on the logger including global tags set on the Lumberjack
|
@@ -566,24 +582,8 @@ module Lumberjack
|
|
566
582
|
# @param [String, Symbol] name The name of the tag to get.
|
567
583
|
# @return [Object, nil] The value of the tag or nil if the tag does not exist.
|
568
584
|
def tag_value(name)
|
569
|
-
all_tags = tags
|
570
|
-
return nil if tags.empty?
|
571
|
-
|
572
585
|
name = name.join(".") if name.is_a?(Array)
|
573
|
-
name
|
574
|
-
return all_tags[name] if all_tags.include?(name)
|
575
|
-
|
576
|
-
flattened_tags = Lumberjack::Utils.flatten_tags(all_tags)
|
577
|
-
return flattened_tags[name] if flattened_tags.include?(name)
|
578
|
-
|
579
|
-
flattened_tags.keys.select { |key| key.include?(".") }.each do |key|
|
580
|
-
parts = key.split(".")
|
581
|
-
while (subkey = parts.pop)
|
582
|
-
flattened_tags[parts.join(".")] = {subkey => flattened_tags[(parts + [subkey]).join(".")]}
|
583
|
-
end
|
584
|
-
end
|
585
|
-
|
586
|
-
flattened_tags[name]
|
586
|
+
TagContext.new(tags)[name]
|
587
587
|
end
|
588
588
|
|
589
589
|
# Remove all tags on the current logger and logging context within a block.
|
@@ -644,15 +644,12 @@ module Lumberjack
|
|
644
644
|
# Merge a tags hash into an existing tags hash.
|
645
645
|
def merge_tags(current_tags, tags)
|
646
646
|
if current_tags.nil? || current_tags.empty?
|
647
|
-
tags
|
647
|
+
tags
|
648
|
+
elsif tags.nil?
|
649
|
+
current_tags
|
648
650
|
else
|
649
|
-
tags
|
650
|
-
current_tags.dup
|
651
|
-
else
|
652
|
-
current_tags.merge(Tags.stringify_keys(tags))
|
653
|
-
end
|
651
|
+
current_tags.merge(tags)
|
654
652
|
end
|
655
|
-
tags
|
656
653
|
end
|
657
654
|
|
658
655
|
# Set a local value for a thread tied to this object.
|
@@ -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
|
data/lib/lumberjack/utils.rb
CHANGED
@@ -103,23 +103,44 @@ module Lumberjack
|
|
103
103
|
# Flatten a tag hash to a single level hash with dot notation for nested keys.
|
104
104
|
#
|
105
105
|
# @param tag_hash [Hash] The hash to flatten.
|
106
|
-
# @return [Hash] The flattened hash.
|
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"}
|
107
110
|
def flatten_tags(tag_hash)
|
108
111
|
return {} unless tag_hash.is_a?(Hash)
|
109
112
|
|
110
|
-
tag_hash
|
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
|
111
136
|
if value.is_a?(Hash)
|
112
|
-
value
|
113
|
-
result["#{key}.#{sub_key}"] = sub_value
|
114
|
-
end
|
137
|
+
result.merge!(flatten_hash_recursive(value, full_key))
|
115
138
|
else
|
116
|
-
result[
|
139
|
+
result[full_key] = value
|
117
140
|
end
|
118
141
|
end
|
119
142
|
end
|
120
143
|
|
121
|
-
private
|
122
|
-
|
123
144
|
def slugify(str)
|
124
145
|
return nil if str.nil?
|
125
146
|
|
@@ -128,6 +149,34 @@ module Lumberjack
|
|
128
149
|
str.chomp!("-")
|
129
150
|
str
|
130
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
|
131
180
|
end
|
132
181
|
end
|
133
182
|
end
|
data/lib/lumberjack.rb
CHANGED
@@ -17,6 +17,7 @@ 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"
|
@@ -57,6 +58,7 @@ module Lumberjack
|
|
57
58
|
end
|
58
59
|
|
59
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.
|
60
62
|
#
|
61
63
|
# If this method is called with a block, it will set a logging context for the scope of a block.
|
62
64
|
# If there is already a context in scope, a new one will be created that inherits
|
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: 2025-
|
11
|
+
date: 2025-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- lib/lumberjack/rack/request_id.rb
|
69
69
|
- lib/lumberjack/rack/unit_of_work.rb
|
70
70
|
- lib/lumberjack/severity.rb
|
71
|
+
- lib/lumberjack/tag_context.rb
|
71
72
|
- lib/lumberjack/tag_formatter.rb
|
72
73
|
- lib/lumberjack/tagged_logger_support.rb
|
73
74
|
- lib/lumberjack/tagged_logging.rb
|