lumberjack_json_device 3.0.0 → 3.0.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: 93f11eda1a4055d1cc3b6ee2b9577e28f0a26ae937f88e49bc5c07aa0c1b327d
4
- data.tar.gz: 96d500179158ea397ed2f52a3a096520125350cc673e5de5dbe352203b607d3f
3
+ metadata.gz: 53ef8a0ab4cd39e6debbbffd600a38dfe6749b41031c69c2865454bb918637bd
4
+ data.tar.gz: cb73709975c436608cac23bc612049d152a9b516796cd618178d717640f94e22
5
5
  SHA512:
6
- metadata.gz: 00773c4aa83e49275b69fa0d400d8c17783008aa013a0b84b881acd868ab9e3ce6f39e5fc183b8d1ce2584c7e306363cfb7aa60d9045edacd100c66821601d85
7
- data.tar.gz: 396d28c5697ded1ef621a959287c356b71a2e33942510cc72c88d32bd41e77c548d0d359df852e41a7ebeff1b60b839c092954e654a7dbbd6b2bc322b207eb1b
6
+ metadata.gz: 71b3f23efb68abc0d4b322fe0aa1eea2c7df7d2bc6f68512701354690c9265e2a092ecf8f21e01be190d4afee96c082f055d52af29c5d788604c2ef767c89962
7
+ data.tar.gz: 77a020bb1b4591ffc56493972a0fbc7e55ca97ebca9cd145eded2afc500628eafb61b1d5686eb20a0f8aaf1ec616846c8027d5f0940a16cd636b9b0e702b2baa
@@ -1,4 +1,3 @@
1
- # Dependabot update strategy
2
1
  version: 2
3
2
  updates:
4
3
  - package-ecosystem: bundler
@@ -6,7 +5,10 @@ updates:
6
5
  schedule:
7
6
  interval: weekly
8
7
  allow:
9
- # Automatically keep all runtime dependencies updated
10
8
  - dependency-name: "*"
11
9
  dependency-type: "production"
12
- versioning-strategy: lockfile-only
10
+ versioning-strategy: increase-if-necessary
11
+ - package-ecosystem: github-actions
12
+ directory: "/"
13
+ schedule:
14
+ interval: weekly
@@ -10,12 +10,6 @@ on:
10
10
  - actions-*
11
11
  workflow_dispatch:
12
12
 
13
- env:
14
- BUNDLE_CLEAN: "true"
15
- BUNDLE_PATH: vendor/bundle
16
- BUNDLE_JOBS: 3
17
- BUNDLE_RETRY: 3
18
-
19
13
  jobs:
20
14
  build:
21
15
  name: ${{ matrix.ruby }} build
@@ -29,19 +23,16 @@ jobs:
29
23
  - ruby: "3.0"
30
24
  - ruby: "2.7"
31
25
  steps:
32
- - uses: actions/checkout@v4
33
- - name: Set up Ruby
34
- uses: ruby/setup-ruby@v1
35
- with:
36
- ruby-version: ${{ matrix.ruby}}
37
- - name: Install gems
38
- run: |
39
- bundle install
40
- - name: Run Tests
41
- run: bundle exec rake
42
- - name: standardrb
43
- if: matrix.standardrb
44
- run: bundle exec standardrb
45
- - name: yard
46
- if: matrix.yard
47
- run: bundle exec yard --fail-on-warning
26
+ - name: Checkout
27
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
28
+ with:
29
+ persist-credentials: false
30
+ - name: Ruby CI
31
+ uses: bdurand/github-actions/ruby-ci@v1.0.4
32
+ with:
33
+ ruby: ${{ matrix.ruby }}
34
+ appraisal: ${{ matrix.appraisal }}
35
+ bundler: ${{ matrix.bundler }}
36
+ standardrb: ${{ matrix.standardrb }}
37
+ yard: ${{ matrix.yard }}
38
+ frozen_strings: ${{ matrix.frozen_strings }}
data/.standard.yml CHANGED
@@ -1,8 +1,3 @@
1
1
  ruby_version: 2.7
2
2
 
3
3
  format: progress
4
-
5
- ignore:
6
- - 'spec/**/*':
7
- - Lint/UselessAssignment
8
- - Lint/Void
data/CHANGE_LOG.md CHANGED
@@ -4,6 +4,16 @@ 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
+ ## 3.0.1
8
+
9
+ ### Fixed
10
+
11
+ - Objects that appear more than once in a log entry (shared references that are not circular) are now serialized in full instead of being replaced with `null`. Only true circular references are replaced with `null`.
12
+ - Log entries are now written to the output stream inside a mutex so that entries written from multiple threads cannot be interleaved, which could produce unparseable JSON lines.
13
+ - Changing the mapping at runtime is now atomic with respect to entries being written on other threads. Previously a concurrent mapping change could produce an entry with a mix of the old and new mappings.
14
+ - Fixed an `IndexError` when a mapping nests a field under a key that another field maps to as a scalar value (e.g. `{progname: "process", pid: "process.pid"}`). The nested structure now replaces the scalar value instead of raising an error.
15
+ - Added an explicit `require "set"` rather than relying on it being transitively loaded.
16
+
7
17
  ## 3.0.0
8
18
 
9
19
  ### Added
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.0.0
1
+ 3.0.1
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "lumberjack"
4
4
  require "json"
5
+ require "set"
5
6
  require "time"
6
7
 
7
8
  # Lumberjack is a simple, powerful, and fast logging library for Ruby that
@@ -70,6 +71,12 @@ module Lumberjack
70
71
  JSON_OPTIONS = [:output, :mapping, :formatter, :datetime_format, :post_processor, :pretty, :utc].freeze
71
72
  private_constant :JSON_OPTIONS
72
73
 
74
+ # Immutable snapshot of a parsed mapping. The mapping is published as a single frozen
75
+ # object so that entries being written concurrently with a mapping change always see
76
+ # a consistent view of the mapping.
77
+ MappedKeys = Struct.new(:time, :severity, :message, :progname, :pid, :attributes, :custom)
78
+ private_constant :MappedKeys
79
+
73
80
  # Register the JsonDevice with the device registry for easier instantiation.
74
81
  DeviceRegistry.add(:json, self)
75
82
 
@@ -152,7 +159,7 @@ module Lumberjack
152
159
 
153
160
  data = entry_as_json(entry)
154
161
  json = @pretty ? JSON.pretty_generate(data) : JSON.generate(data)
155
- @output.write("#{json}\n")
162
+ @output.write("#{json}\n") # thread safety is handled by the underlying output stream
156
163
  end
157
164
 
158
165
  # Get the underlying device from the output stream.
@@ -200,26 +207,33 @@ module Lumberjack
200
207
  # If the value is `false`, the field will not be included in the JSON output.
201
208
  # @return [void]
202
209
  def mapping=(mapping)
203
- @mutex.synchronize do
204
- keys = {}
205
- mapping.each do |key, value|
206
- if value == true
207
- value = key.to_s.split(".")
208
- value = value.first if value.size == 1
209
- end
210
- keys[key.to_sym] = value if value
210
+ keys = {}
211
+ mapping.each do |key, value|
212
+ if value == true
213
+ value = key.to_s.split(".")
214
+ value = value.first if value.size == 1
211
215
  end
216
+ keys[key.to_sym] = value if value
217
+ end
218
+
219
+ custom_keys = keys.each_with_object({}) do |(name, key), hash|
220
+ next if DEFAULT_MAPPING.include?(name)
212
221
 
213
- @time_key = keys.delete(:time)
214
- @severity_key = keys.delete(:severity)
215
- @message_key = keys.delete(:message)
216
- @progname_key = keys.delete(:progname)
217
- @pid_key = keys.delete(:pid)
218
- @attributes_key = keys.delete(:attributes)
219
- @custom_keys = keys.map do |name, key|
220
- [name.to_s.split("."), key]
221
- end.to_h
222
+ hash[name.to_s.split(".")] = key
223
+ end
222
224
 
225
+ mapped_keys = MappedKeys.new(
226
+ keys[:time],
227
+ keys[:severity],
228
+ keys[:message],
229
+ keys[:progname],
230
+ keys[:pid],
231
+ keys[:attributes],
232
+ custom_keys.freeze
233
+ ).freeze
234
+
235
+ @mutex.synchronize do
236
+ @keys = mapped_keys
223
237
  @mapping = mapping
224
238
  end
225
239
  end
@@ -242,17 +256,18 @@ module Lumberjack
242
256
  # @param entry [Lumberjack::LogEntry] The log entry to convert.
243
257
  # @return [Hash] A hash representing the log entry in JSON format.
244
258
  def entry_as_json(entry)
259
+ keys = @keys
245
260
  data = {}
246
- set_attribute(data, @time_key, entry.time) if @time_key
247
- set_attribute(data, @severity_key, entry.severity_label) if @severity_key
248
- set_attribute(data, @message_key, json_safe(entry.message)) if @message_key
249
- set_attribute(data, @progname_key, json_safe(entry.progname)) if @progname_key && entry.progname
250
- set_attribute(data, @pid_key, entry.pid) if @pid_key
261
+ set_attribute(data, keys.time, entry.time) if keys.time
262
+ set_attribute(data, keys.severity, entry.severity_label) if keys.severity
263
+ set_attribute(data, keys.message, json_safe(entry.message)) if keys.message
264
+ set_attribute(data, keys.progname, json_safe(entry.progname)) if keys.progname && entry.progname
265
+ set_attribute(data, keys.pid, entry.pid) if keys.pid
251
266
 
252
267
  attributes = entry.attributes.transform_values { |value| json_safe(value) } if entry.attributes
253
268
 
254
- if @custom_keys.size > 0 && attributes && !attributes&.empty?
255
- @custom_keys.each do |name, key|
269
+ if keys.custom.size > 0 && attributes && !attributes&.empty?
270
+ keys.custom.each do |name, key|
256
271
  name = name.is_a?(Array) ? name.join(".") : name.to_s
257
272
  value = attributes.delete(name)
258
273
  next if value.nil?
@@ -262,12 +277,12 @@ module Lumberjack
262
277
  end
263
278
  end
264
279
 
265
- if @attributes_key && !attributes&.empty?
280
+ if keys.attributes && !attributes&.empty?
266
281
  attributes = Lumberjack::Utils.expand_attributes(attributes)
267
- if @attributes_key == "*"
282
+ if keys.attributes == "*"
268
283
  attributes.each { |k, v| data[k] = v unless data.include?(k) }
269
284
  else
270
- set_attribute(data, @attributes_key, attributes)
285
+ set_attribute(data, keys.attributes, attributes)
271
286
  end
272
287
  end
273
288
 
@@ -325,7 +340,7 @@ module Lumberjack
325
340
  if key.size == 1
326
341
  data[key.first] = value
327
342
  else
328
- data[key.first] ||= {}
343
+ data[key.first] = {} unless data[key.first].is_a?(Hash)
329
344
  set_attribute(data[key.first], key[1, key.size], value)
330
345
  end
331
346
  end
@@ -366,10 +381,16 @@ module Lumberjack
366
381
  else
367
382
  seen ||= Set.new
368
383
  seen << value.object_id
369
- if value.is_a?(Hash)
370
- value.transform_values { |v| json_safe(v, seen) }
371
- else
372
- value.collect { |v| json_safe(v, seen) }
384
+ begin
385
+ if value.is_a?(Hash)
386
+ value.transform_values { |v| json_safe(v, seen) }
387
+ else
388
+ value.collect { |v| json_safe(v, seen) }
389
+ end
390
+ ensure
391
+ # Only track objects on the current traversal path so that shared references
392
+ # that are not circular are serialized in full.
393
+ seen.delete(value.object_id)
373
394
  end
374
395
  end
375
396
  rescue SystemStackError, StandardError => e
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lumberjack_json_device
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Durand
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-10-20 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: lumberjack
@@ -60,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  requirements: []
63
- rubygems_version: 3.6.2
63
+ rubygems_version: 4.0.3
64
64
  specification_version: 4
65
65
  summary: A logging device for the lumberjack gem that writes log entries as JSON documents
66
66
  for use with structured logging.