dry-logger 1.2.0 → 1.2.2

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: d5b1c6d122b7cb90cf0e9d2a847056d8a610813e0c5dd6b4496deb1b172781be
4
+ data.tar.gz: 4642ad1fb26e02dd1fb660262819d576ab58c64eb376858ebf3f08fe39248d00
5
5
  SHA512:
6
- metadata.gz: 4ed4f26c990c6e85575fd06f5064fbd68ca73a11ecb4370e749455cc980edf319905e672d7f2bc798ec0f80df235f0c86cf1b50786eb891b71fb142b2a2c4590
7
- data.tar.gz: 527a960b08d0083fbbbc086e5b946d896021ff0d3295916c42eed5f41e5d1131d15633e7d0926cb7dbe528098c0943e965189a5e0c6076845bc567bd04c6d96a
6
+ metadata.gz: 30a77024ebe05dcfc86d6b44e5c3e0262f1a6d27ad8ad4e298e38d763366f8ed3a176014e37b0cc6904dfebee34a18f73a6a13fa61a03d788caf79501a0ddb38
7
+ data.tar.gz: 498b41ab0fd5cd03bf79b8a04ef7a528ba90294777b0f24e427933f77f75880a5297c1a0252a079156fafe274cb05a0528abafe997c08b318b0a2b6d88cd7b53
data/CHANGELOG.md CHANGED
@@ -19,6 +19,28 @@ 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.2...main
23
+
24
+ ## [1.2.2] - 2026-03-13
25
+
26
+ ### Fixed
27
+
28
+ - Exception when message and metadata have different encodings (@katafrakt in #40)
29
+
30
+ [1.2.2]: https://github.com/dry-rb/dry-logger/compare/v1.2.1...v1.2.2
31
+
32
+ ## [1.2.1] - 2025-12-16
33
+
34
+ ### Changed
35
+
36
+ - Support Ruby 4.0 by adding the `"logger"` gem to the list of runtime dependencies. (@timriley in #39)
37
+
38
+ ### Fixed
39
+
40
+ - Ensure changes to `logger.context` and calls to `logger.tagged` are threadsafe. (@timriley in #38)
41
+
42
+ [1.2.1]: https://github.com/dry-rb/dry-logger/compare/v1.2.0...v1.2.1
43
+
22
44
  ## [1.2.0] - 2025-11-05
23
45
 
24
46
  ### Changed
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2025 Hanakai team
3
+ Copyright (c) 2015-2026 Hanakai team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
@@ -18,4 +18,3 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
18
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
19
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
20
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
-
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"
@@ -21,7 +21,7 @@ module Dry
21
21
 
22
22
  # @since 0.1.0
23
23
  # @api private
24
- def initialize( # rubocop:disable Style/ParameterLists
24
+ def initialize(
25
25
  stream:,
26
26
  formatter:,
27
27
  level: DEFAULT_LEVEL,
@@ -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
@@ -64,7 +53,9 @@ module Dry
64
53
  severity: "FATAL",
65
54
  progname: progname,
66
55
  time: Time.now,
67
- log_entry: [message, payload].map(&:to_s).reject(&:empty?).join(SEPARATOR),
56
+ log_entry: [message, payload].map { |s|
57
+ s.to_s.encode("UTF-8", invalid: :replace, undef: :replace, replace: "?")
58
+ }.reject(&:empty?).join(SEPARATOR),
68
59
  exception: exception.class,
69
60
  message: exception.message,
70
61
  backtrace: TAB + exception.backtrace.join(NEW_LINE + TAB)
@@ -86,21 +77,13 @@ module Dry
86
77
 
87
78
  # @since 1.0.0
88
79
  # @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
- )
80
+ def initialize(id, backends: [], tags: [], context: {}, **options)
98
81
  @id = id
99
82
  @backends = backends
100
83
  @options = {**options, progname: id}
101
84
  @mutex = Mutex.new
102
- @context = context
103
- @tags = tags
85
+ @default_tags = tags.freeze
86
+ @default_context = context.freeze
104
87
  @clock = Clock.new(**(options[:clock] || EMPTY_HASH))
105
88
  @on_crash = options[:on_crash] || ON_CRASH
106
89
  end
@@ -226,7 +209,7 @@ module Dry
226
209
  clock: clock,
227
210
  progname: progname,
228
211
  severity: severity,
229
- tags: @tags,
212
+ tags: current_tags,
230
213
  message: message,
231
214
  payload: {**context, **payload}
232
215
  )
@@ -244,7 +227,22 @@ module Dry
244
227
  true
245
228
  end
246
229
 
247
- # (EXPERIMENTAL) Tagged logging withing the provided block
230
+ # Shared payload context
231
+ #
232
+ # @example
233
+ # logger.context[:component] = "test"
234
+ #
235
+ # logger.info "Hello World"
236
+ # # Hello World component=test
237
+ #
238
+ # @since 1.0.0
239
+ # @api public
240
+ def context
241
+ @context_key ||= :"context_#{object_id}"
242
+ ExecutionContext[@context_key] ||= @default_context.dup
243
+ end
244
+
245
+ # Tagged logging withing the provided block
248
246
  #
249
247
  # @example
250
248
  # logger.tagged("red") do
@@ -258,10 +256,10 @@ module Dry
258
256
  # @since 1.0.0
259
257
  # @api public
260
258
  def tagged(*tags)
261
- @tags.concat(tags)
259
+ tags_stack.push(tags)
262
260
  yield
263
261
  ensure
264
- @tags = []
262
+ tags_stack.pop
265
263
  end
266
264
 
267
265
  # Add a new backend to an existing dispatcher
@@ -310,6 +308,17 @@ module Dry
310
308
  each_backend { |backend| backend.public_send(meth, ...) }
311
309
  true
312
310
  end
311
+
312
+ private
313
+
314
+ def tags_stack
315
+ @tags_key ||= :"tags_#{object_id}"
316
+ ExecutionContext[@tags_key] ||= @default_tags.dup
317
+ end
318
+
319
+ def current_tags
320
+ tags_stack.flatten
321
+ end
313
322
  end
314
323
  end
315
324
  end
@@ -44,7 +44,6 @@ module Dry
44
44
 
45
45
  # @since 1.0.0
46
46
  # @api private
47
- # rubocop:disable Metrics/ParameterLists
48
47
  def initialize(clock:, progname:, severity:, tags: EMPTY_ARRAY, message: nil,
49
48
  payload: EMPTY_HASH)
50
49
  @clock = clock
@@ -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
@@ -68,8 +68,19 @@ module Dry
68
68
 
69
69
  # @since 1.0.0
70
70
  # @api private
71
- def %(tokens)
72
- output = value % tokens
71
+ def %(other)
72
+ begin
73
+ output = value % other
74
+ rescue Encoding::CompatibilityError
75
+ sanitized_tokens = other.transform_values { |v|
76
+ if v.respond_to?(:encode)
77
+ v.encode("UTF-8", invalid: :replace, undef: :replace, replace: "?")
78
+ else
79
+ v
80
+ end
81
+ }
82
+ output = value % sanitized_tokens
83
+ end
73
84
  output.strip!
74
85
  output.split(NEW_LINE).map(&:rstrip).join(NEW_LINE)
75
86
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Logger
5
- VERSION = "1.2.0"
5
+ VERSION = "1.2.2"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,15 +1,28 @@
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.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hanakai team
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-11-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: logger
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '0'
13
26
  - !ruby/object:Gem::Dependency
14
27
  name: bundler
15
28
  requirement: !ruby/object:Gem::Requirement
@@ -58,9 +71,9 @@ email:
58
71
  executables: []
59
72
  extensions: []
60
73
  extra_rdoc_files:
61
- - README.md
62
74
  - CHANGELOG.md
63
75
  - LICENSE
76
+ - README.md
64
77
  files:
65
78
  - CHANGELOG.md
66
79
  - LICENSE
@@ -76,6 +89,7 @@ files:
76
89
  - lib/dry/logger/constants.rb
77
90
  - lib/dry/logger/dispatcher.rb
78
91
  - lib/dry/logger/entry.rb
92
+ - lib/dry/logger/execution_context.rb
79
93
  - lib/dry/logger/filter.rb
80
94
  - lib/dry/logger/formatters/colors.rb
81
95
  - lib/dry/logger/formatters/json.rb
@@ -94,7 +108,6 @@ metadata:
94
108
  source_code_uri: https://github.com/dry-rb/dry-logger
95
109
  bug_tracker_uri: https://github.com/dry-rb/dry-logger/issues
96
110
  funding_uri: https://github.com/sponsors/hanami
97
- post_install_message:
98
111
  rdoc_options: []
99
112
  require_paths:
100
113
  - lib
@@ -109,8 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
122
  - !ruby/object:Gem::Version
110
123
  version: '0'
111
124
  requirements: []
112
- rubygems_version: 3.3.27
113
- signing_key:
125
+ rubygems_version: 3.6.9
114
126
  specification_version: 4
115
127
  summary: Lightweight structured logging for Ruby applications
116
128
  test_files: []