dry-logger 1.2.0 → 1.2.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64477022ad878f3e1a98d7fb8b82bb9117b8d09c662ecf12b89fda0bca0bc8dd
4
- data.tar.gz: f69f6a4d5a1daf532f4a569789fa9e087b44889cdb6f47b048e5d3961a93a893
3
+ metadata.gz: 8d27303efa558c60b1f0f9710b1c9419223d7b421c61b7f6efbea241b54ca486
4
+ data.tar.gz: ada0ee3f313045a3cfbcd26e15da7642741d6217efe3e834542935b5efbaa0b9
5
5
  SHA512:
6
- metadata.gz: 4ed4f26c990c6e85575fd06f5064fbd68ca73a11ecb4370e749455cc980edf319905e672d7f2bc798ec0f80df235f0c86cf1b50786eb891b71fb142b2a2c4590
7
- data.tar.gz: 527a960b08d0083fbbbc086e5b946d896021ff0d3295916c42eed5f41e5d1131d15633e7d0926cb7dbe528098c0943e965189a5e0c6076845bc567bd04c6d96a
6
+ metadata.gz: 5c42481abe364e3550091fe8d1d8fcfbd3e2b23fa00943ca22e8a13f9d6c20cf7bf7846390498c5fb098c7cb45ff9cef461f9bddde50f4382a719e288af9731d
7
+ data.tar.gz: c91f8c1e74e4b1dc7fdeaa62870453e303018e7f5e4b0f25152a805cc20c15c04fea719caef6a6feb756f41291f319dd9ebca3b2275dbedc470e4ff22d5ed3fd
data/CHANGELOG.md CHANGED
@@ -19,6 +19,20 @@ and this project adheres to [Break Versioning](https://www.taoensso.com/break-ve
19
19
 
20
20
  ### Security
21
21
 
22
+ [Unreleased]: https://github.com/dry-rb/dry-logger/compare/v1.2.1...main
23
+
24
+ ## [1.2.1] - 2025-12-16
25
+
26
+ ### Changed
27
+
28
+ - Support Ruby 4.0 by adding the `"logger"` gem to the list of runtime dependencies. (@timriley in #39)
29
+
30
+ ### Fixed
31
+
32
+ - Ensure changes to `logger.context` and calls to `logger.tagged` are threadsafe. (@timriley in #38)
33
+
34
+ [1.2.1]: https://github.com/dry-rb/dry-logger/compare/v1.2.0...v1.2.1
35
+
22
36
  ## [1.2.0] - 2025-11-05
23
37
 
24
38
  ### Changed
data/dry-logger.gemspec CHANGED
@@ -31,6 +31,8 @@ Gem::Specification.new do |spec|
31
31
 
32
32
  spec.required_ruby_version = ">= 3.2"
33
33
 
34
+ spec.add_runtime_dependency "logger"
35
+
34
36
  spec.add_development_dependency "bundler"
35
37
  spec.add_development_dependency "rake"
36
38
  spec.add_development_dependency "rspec"
@@ -6,6 +6,7 @@ require "pathname"
6
6
  require "dry/logger/constants"
7
7
  require "dry/logger/backends/proxy"
8
8
  require "dry/logger/entry"
9
+ require "dry/logger/execution_context"
9
10
 
10
11
  module Dry
11
12
  module Logger
@@ -18,18 +19,6 @@ module Dry
18
19
  # @api private
19
20
  attr_reader :id
20
21
 
21
- # (EXPERIMENTAL) Shared payload context
22
- #
23
- # @example
24
- # logger.context[:component] = "test"
25
- #
26
- # logger.info "Hello World"
27
- # # Hello World component=test
28
- #
29
- # @since 1.0.0
30
- # @api public
31
- attr_reader :context
32
-
33
22
  # @since 1.0.0
34
23
  # @api private
35
24
  attr_reader :backends
@@ -86,21 +75,13 @@ module Dry
86
75
 
87
76
  # @since 1.0.0
88
77
  # @api private
89
- def self.default_context
90
- Thread.current[:__dry_logger__] ||= {}
91
- end
92
-
93
- # @since 1.0.0
94
- # @api private
95
- def initialize(
96
- id, backends: [], tags: [], context: self.class.default_context, **options
97
- )
78
+ def initialize(id, backends: [], tags: [], context: {}, **options)
98
79
  @id = id
99
80
  @backends = backends
100
81
  @options = {**options, progname: id}
101
82
  @mutex = Mutex.new
102
- @context = context
103
- @tags = tags
83
+ @default_tags = tags.freeze
84
+ @default_context = context.freeze
104
85
  @clock = Clock.new(**(options[:clock] || EMPTY_HASH))
105
86
  @on_crash = options[:on_crash] || ON_CRASH
106
87
  end
@@ -226,7 +207,7 @@ module Dry
226
207
  clock: clock,
227
208
  progname: progname,
228
209
  severity: severity,
229
- tags: @tags,
210
+ tags: current_tags,
230
211
  message: message,
231
212
  payload: {**context, **payload}
232
213
  )
@@ -244,7 +225,22 @@ module Dry
244
225
  true
245
226
  end
246
227
 
247
- # (EXPERIMENTAL) Tagged logging withing the provided block
228
+ # Shared payload context
229
+ #
230
+ # @example
231
+ # logger.context[:component] = "test"
232
+ #
233
+ # logger.info "Hello World"
234
+ # # Hello World component=test
235
+ #
236
+ # @since 1.0.0
237
+ # @api public
238
+ def context
239
+ @context_key ||= :"context_#{object_id}"
240
+ ExecutionContext[@context_key] ||= @default_context.dup
241
+ end
242
+
243
+ # Tagged logging withing the provided block
248
244
  #
249
245
  # @example
250
246
  # logger.tagged("red") do
@@ -258,10 +254,10 @@ module Dry
258
254
  # @since 1.0.0
259
255
  # @api public
260
256
  def tagged(*tags)
261
- @tags.concat(tags)
257
+ tags_stack.push(tags)
262
258
  yield
263
259
  ensure
264
- @tags = []
260
+ tags_stack.pop
265
261
  end
266
262
 
267
263
  # Add a new backend to an existing dispatcher
@@ -310,6 +306,17 @@ module Dry
310
306
  each_backend { |backend| backend.public_send(meth, ...) }
311
307
  true
312
308
  end
309
+
310
+ private
311
+
312
+ def tags_stack
313
+ @tags_key ||= :"tags_#{object_id}"
314
+ ExecutionContext[@tags_key] ||= @default_tags.dup
315
+ end
316
+
317
+ def current_tags
318
+ tags_stack.flatten
319
+ end
313
320
  end
314
321
  end
315
322
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Logger
5
+ # Provides isolated thread-local storage for logger values.
6
+ #
7
+ # @api private
8
+ module ExecutionContext
9
+ CONTEXT_KEY = :__dry_logger__
10
+
11
+ class << self
12
+ # Returns a value from the current execution context.
13
+ #
14
+ # @param key [Symbol] the key to retrieve
15
+ #
16
+ # @return [Object, nil] the stored value, or nil if no value has been stored
17
+ def [](key)
18
+ context[key]
19
+ end
20
+
21
+ # Sets a value in the current execution context.
22
+ #
23
+ # @param key [Symbol] the key to store
24
+ # @param value [Object] the value to store
25
+ #
26
+ # @return [Object] the stored value
27
+ def []=(key, value)
28
+ context[key] = value
29
+ end
30
+
31
+ # Clears all values from the current execution context.
32
+ #
33
+ # @return [self]
34
+ def clear
35
+ current_store[CONTEXT_KEY] = {}
36
+ self
37
+ end
38
+
39
+ private
40
+
41
+ def context
42
+ current_store[CONTEXT_KEY] ||= {}
43
+ end
44
+
45
+ def current_store
46
+ Thread.current
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Logger
5
- VERSION = "1.2.0"
5
+ VERSION = "1.2.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-logger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hanakai team
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-05 00:00:00.000000000 Z
11
+ date: 2025-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logger
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -76,6 +90,7 @@ files:
76
90
  - lib/dry/logger/constants.rb
77
91
  - lib/dry/logger/dispatcher.rb
78
92
  - lib/dry/logger/entry.rb
93
+ - lib/dry/logger/execution_context.rb
79
94
  - lib/dry/logger/filter.rb
80
95
  - lib/dry/logger/formatters/colors.rb
81
96
  - lib/dry/logger/formatters/json.rb