activesupport-json_logging 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: c99bef73cc6bf2627075656ee38a3e3b756ac61ef54f2edcc628814b317ac7bf
4
- data.tar.gz: c4a0e1ecfd0ae8862db0167cc5507b8da4572e6a58ed4035ec7aa606c3154442
3
+ metadata.gz: 879dfb3d0d8142a294407c70771d234e55d410032dbc50f035bf85f3bd33b79a
4
+ data.tar.gz: bfa9d0637d5e84f58acdf407ce782feda91b584c5c63700b93ec2aa4e6e59dd4
5
5
  SHA512:
6
- metadata.gz: 3abb724226828b28519f25dc8edb138c3b4d7dc1a07bf2946b952e46bee4bef5d71149a44df4a52cb12e41f892ca4d2f7147bfdeb9dbd7ad0ca3c4ee3873dddc
7
- data.tar.gz: 25b2c9f5ae0c8107e4f5c7385ff96fbb379cbfba851234be9800909978b14d1d81b5fab961a5d72bd1d4ede78c5d1d16eb5ab1534e6ed54d2074e1c21456395c
6
+ metadata.gz: e4ed4ef5739e411af61e6186581ec30aa3f0653c557d7f2bc088abf264a3e8608c483b0790b892a7e1c10674d55811f95a5a3e4c33d073cd59949469e732e875
7
+ data.tar.gz: ec86db106814dee2731695159275fb7c56700d36564571edd72e54013d076dd1a3328a050eae06429d16eaaf1c0538404ae8345605d5a2ec63684ca1f71f40b7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.2.1 (2026-01-18)
4
+
5
+ - Refactor tag stack handling in JsonLogging formatter for improved maintainability
6
+ - Refactor timestamp handling in JsonLogging helpers to support Time.zone
7
+ - Add Ruby 4.0 support in gemspec and Appraisal configurations
8
+
3
9
  ## 1.2.0 (2025-11-07)
4
10
 
5
11
  - Add support for service-specific tagged loggers: create loggers with permanent tags using `logger.tagged("service")` without a block
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # activesupport-json_logging
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/activesupport-json_logging.svg)](https://badge.fury.io/rb/activesupport-json_logging) [![Test Status](https://github.com/amkisko/activesupport-json_logging.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/activesupport-json_logging.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/activesupport-json_logging.rb/graph/badge.svg?token=UX80FTO0Y0)](https://codecov.io/gh/amkisko/activesupport-json_logging.rb)
3
+ [![Gem Version](https://badge.fury.io/rb/activesupport-json_logging.svg)](https://badge.fury.io/rb/activesupport-json_logging) [![Test Status](https://github.com/amkisko/activesupport-json_logging.rb/actions/workflows/test.yml/badge.svg)](https://github.com/amkisko/activesupport-json_logging.rb/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/amkisko/activesupport-json_logging.rb/graph/badge.svg?token=UX80FTO0Y0)](https://codecov.io/gh/amkisko/activesupport-json_logging.rb) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=amkisko_activesupport-json_logging.rb&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=amkisko_activesupport-json_logging.rb)
4
4
 
5
5
  Structured JSON logging for Rails and ActiveSupport with a safe, single-line formatter.
6
6
  No dependencies beyond Rails and Activesupport.
@@ -283,6 +283,8 @@ end
283
283
 
284
284
  If you use Lograge, configure it to feed raw hashes and let this gem handle JSON formatting. This example shows a complete setup including all Rails component loggers and common third-party libraries:
285
285
 
286
+ **Important:** When using Lograge, `config.log_tags` does not work for adding fields to Lograge output. Instead, use `config.lograge.custom_options` to add custom fields to your request logs.
287
+
286
288
  ```ruby
287
289
  # config/initializers/lograge.rb
288
290
  # Note: require is optional in Rails apps (auto-loaded via Railtie)
@@ -295,8 +297,26 @@ Rails.application.configure do
295
297
  config.lograge.formatter = Lograge::Formatters::Raw.new
296
298
  config.lograge.keep_original_rails_log = ENV["DEBUG"] ? true : false
297
299
 
298
- # Merge additional context into Lograge output
299
- config.lograge.custom_options = ->(_event) { JsonLogging.additional_context }
300
+ # Add custom fields to Lograge output
301
+ # Note: config.log_tags does NOT work with Lograge - use custom_options instead
302
+ config.lograge.custom_options = ->(event) {
303
+ {
304
+ remote_ip: Current.remote_addr,
305
+ request_id: Current.request_id,
306
+ user_agent: Current.user_agent,
307
+ user_id: Current.user&.id
308
+ }
309
+ }
310
+
311
+ # Optionally merge additional context from JsonLogging.with_context
312
+ # config.lograge.custom_options = ->(event) {
313
+ # {
314
+ # remote_ip: Current.remote_addr,
315
+ # request_id: Current.request_id,
316
+ # user_agent: Current.user_agent,
317
+ # user_id: Current.user&.id
318
+ # }.merge(JsonLogging.additional_context)
319
+ # }
300
320
 
301
321
  # Build unified JSON logger
302
322
  logdev = Rails.env.production? ? Rails.root.join("log", "#{Rails.env}.log") : $stdout
@@ -306,7 +326,6 @@ Rails.application.configure do
306
326
 
307
327
  # Set the main Rails logger
308
328
  config.logger = json_logger
309
- config.log_tags = [:request_id, :remote_ip]
310
329
 
311
330
  # Override Rails.logger to ensure it uses our formatter
312
331
  Rails.logger = json_logger
@@ -327,13 +346,6 @@ Rails.application.configure do
327
346
 
328
347
  # Disable verbose enqueue logs to reduce noise
329
348
  config.active_job.verbose_enqueue_logs = false
330
-
331
- # Optional: Customize log tags based on request
332
- # config.log_tags = [
333
- # :request_id,
334
- # ->(request) { request.remote_ip },
335
- # ->(request) { request.subdomain }
336
- # ]
337
349
  end
338
350
  ```
339
351
 
@@ -594,27 +606,10 @@ The gem will automatically filter these from all log entries, including context
594
606
 
595
607
  ## Development
596
608
 
597
- ```bash
598
- # Install dependencies
599
- bundle install
600
- bundle exec appraisal generate
601
-
602
- # Run tests for current Rails version
603
- bundle exec rspec
609
+ Run release.rb script to prepare code for publishing, it has all the required checks and tests.
604
610
 
605
- # Run tests for all Rails versions (6.0, 6.1, 7.0, 7.1, 7.2, 8.0)
606
- bin/appraisals
607
-
608
- # Run tests for specific Rails version
609
- bin/appraisals rails-7.0
610
-
611
- # Run tests for multiple versions
612
- bin/appraisals rails-7.0 rails-8.0
613
-
614
- # Or use appraisal directly
615
- bundle exec appraisal rails-7.0 rspec
616
-
617
- bundle exec standardrb --fix
611
+ ```bash
612
+ usr/bin/release.rb
618
613
  ```
619
614
 
620
615
  ### Development: Using from Local Repository
@@ -10,8 +10,8 @@ module JsonLogging
10
10
  def current_tags
11
11
  # If LocalTagStorage is extended on this formatter, use its tag_stack
12
12
  # This matches Rails' TaggedLogging behavior where tag_stack attribute shadows the method
13
- if respond_to?(:tag_stack, true) && instance_variable_defined?(:@tag_stack)
14
- tag_stack.tags
13
+ if (stack = current_tag_stack)
14
+ stack.tags
15
15
  else
16
16
  @logger.send(:current_tags)
17
17
  end
@@ -30,8 +30,8 @@ module JsonLogging
30
30
 
31
31
  def push_tags(*tags)
32
32
  # If LocalTagStorage is present, use it; otherwise use logger's thread-local storage
33
- if respond_to?(:tag_stack, true) && instance_variable_defined?(:@tag_stack)
34
- tag_stack.push_tags(tags)
33
+ if (stack = current_tag_stack)
34
+ stack.push_tags(tags)
35
35
  else
36
36
  @logger.send(:push_tags, tags)
37
37
  end
@@ -40,14 +40,12 @@ module JsonLogging
40
40
  # Support tagged blocks for formatter
41
41
  def tagged(*tags)
42
42
  if block_given?
43
- # If LocalTagStorage is present, use it; otherwise use logger's thread-local storage
44
- if respond_to?(:tag_stack, true) && instance_variable_defined?(:@tag_stack)
45
- previous_count = tag_stack.tags.size
46
- tag_stack.push_tags(tags)
43
+ if (stack = current_tag_stack)
44
+ pushed_count = stack.push_tags(tags).size
47
45
  begin
48
46
  yield @logger
49
47
  ensure
50
- tag_stack.pop_tags(tag_stack.tags.size - previous_count)
48
+ stack.pop_tags(pushed_count)
51
49
  end
52
50
  else
53
51
  previous = @logger.send(:current_tags).dup
@@ -59,8 +57,8 @@ module JsonLogging
59
57
  end
60
58
  end
61
59
  else
62
- if respond_to?(:tag_stack, true) && instance_variable_defined?(:@tag_stack)
63
- tag_stack.push_tags(tags)
60
+ if (stack = current_tag_stack)
61
+ stack.push_tags(tags)
64
62
  else
65
63
  @logger.send(:push_tags, tags)
66
64
  end
@@ -70,6 +68,23 @@ module JsonLogging
70
68
 
71
69
  private
72
70
 
71
+ # Returns the current tag_stack to use, checking in order:
72
+ # 1. This formatter's tag_stack (if LocalTagStorage is extended)
73
+ # 2. Logger's formatter's tag_stack (if it has LocalTagStorage)
74
+ # 3. nil (fall back to thread-local storage)
75
+ def current_tag_stack
76
+ if respond_to?(:tag_stack, true) && instance_variable_defined?(:@tag_stack)
77
+ tag_stack
78
+ elsif logger_formatter_has_tag_stack?
79
+ @logger.formatter.tag_stack
80
+ end
81
+ end
82
+
83
+ def logger_formatter_has_tag_stack?
84
+ @logger.formatter.respond_to?(:tag_stack, true) &&
85
+ @logger.formatter.instance_variable_defined?(:@tag_stack)
86
+ end
87
+
73
88
  def build_fallback_output(severity, timestamp, msg, error)
74
89
  timestamp_str = Helpers.normalize_timestamp(timestamp)
75
90
  fallback_payload = {
@@ -4,7 +4,17 @@ module JsonLogging
4
4
 
5
5
  # Normalize timestamp to ISO8601 with microseconds
6
6
  def normalize_timestamp(timestamp)
7
- (timestamp || Time.now).utc.iso8601(6)
7
+ time = timestamp || current_time
8
+ time.utc.iso8601(6)
9
+ end
10
+
11
+ # Get current time, using Time.zone if available, otherwise Time.now
12
+ def current_time
13
+ if defined?(Time.zone) && Time.zone
14
+ Time.zone.now
15
+ else
16
+ Time.now
17
+ end
8
18
  end
9
19
 
10
20
  # Safely convert object to string, never raises
@@ -50,7 +50,7 @@ module JsonLogging
50
50
  msg ||= "<uninitialized>"
51
51
 
52
52
  fallback = {
53
- timestamp: Helpers.normalize_timestamp(Time.now),
53
+ timestamp: Helpers.normalize_timestamp(Helpers.current_time),
54
54
  severity: severity_name(severity),
55
55
  message: Sanitizer.sanitize_string(Helpers.safe_string(msg)),
56
56
  logger_error: {
@@ -129,7 +129,7 @@ module JsonLogging
129
129
  payload = PayloadBuilder.build_base_payload(
130
130
  msg,
131
131
  severity: severity_name(severity),
132
- timestamp: Helpers.normalize_timestamp(Time.now)
132
+ timestamp: Helpers.normalize_timestamp(Helpers.current_time)
133
133
  )
134
134
  payload = PayloadBuilder.merge_context(
135
135
  payload,
@@ -186,6 +186,8 @@ module JsonLogging
186
186
  end
187
187
 
188
188
  def pop_tags(count = 1)
189
+ return [] if count <= 0
190
+
189
191
  @tags.pop(count)
190
192
  end
191
193
 
@@ -1,3 +1,3 @@
1
1
  module JsonLogging
2
- VERSION = "1.2.0"
2
+ VERSION = "1.2.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activesupport-json_logging
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
  - Andrei Makarov
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2025-11-10 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: activesupport
@@ -140,14 +139,112 @@ dependencies:
140
139
  requirements:
141
140
  - - "~>"
142
141
  - !ruby/object:Gem::Version
143
- version: '1'
142
+ version: '1.52'
144
143
  type: :development
145
144
  prerelease: false
146
145
  version_requirements: !ruby/object:Gem::Requirement
147
146
  requirements:
148
147
  - - "~>"
149
148
  - !ruby/object:Gem::Version
150
- version: '1'
149
+ version: '1.52'
150
+ - !ruby/object:Gem::Dependency
151
+ name: standard-custom
152
+ requirement: !ruby/object:Gem::Requirement
153
+ requirements:
154
+ - - "~>"
155
+ - !ruby/object:Gem::Version
156
+ version: '1.0'
157
+ type: :development
158
+ prerelease: false
159
+ version_requirements: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: '1.0'
164
+ - !ruby/object:Gem::Dependency
165
+ name: standard-performance
166
+ requirement: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: '1.8'
171
+ type: :development
172
+ prerelease: false
173
+ version_requirements: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - "~>"
176
+ - !ruby/object:Gem::Version
177
+ version: '1.8'
178
+ - !ruby/object:Gem::Dependency
179
+ name: standard-rails
180
+ requirement: !ruby/object:Gem::Requirement
181
+ requirements:
182
+ - - "~>"
183
+ - !ruby/object:Gem::Version
184
+ version: '1.5'
185
+ type: :development
186
+ prerelease: false
187
+ version_requirements: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - "~>"
190
+ - !ruby/object:Gem::Version
191
+ version: '1.5'
192
+ - !ruby/object:Gem::Dependency
193
+ name: standard-rspec
194
+ requirement: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: '0.3'
199
+ type: :development
200
+ prerelease: false
201
+ version_requirements: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - "~>"
204
+ - !ruby/object:Gem::Version
205
+ version: '0.3'
206
+ - !ruby/object:Gem::Dependency
207
+ name: rubocop-rails
208
+ requirement: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - "~>"
211
+ - !ruby/object:Gem::Version
212
+ version: '2.33'
213
+ type: :development
214
+ prerelease: false
215
+ version_requirements: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - "~>"
218
+ - !ruby/object:Gem::Version
219
+ version: '2.33'
220
+ - !ruby/object:Gem::Dependency
221
+ name: rubocop-rspec
222
+ requirement: !ruby/object:Gem::Requirement
223
+ requirements:
224
+ - - "~>"
225
+ - !ruby/object:Gem::Version
226
+ version: '3.8'
227
+ type: :development
228
+ prerelease: false
229
+ version_requirements: !ruby/object:Gem::Requirement
230
+ requirements:
231
+ - - "~>"
232
+ - !ruby/object:Gem::Version
233
+ version: '3.8'
234
+ - !ruby/object:Gem::Dependency
235
+ name: rubocop-thread_safety
236
+ requirement: !ruby/object:Gem::Requirement
237
+ requirements:
238
+ - - "~>"
239
+ - !ruby/object:Gem::Version
240
+ version: '0.7'
241
+ type: :development
242
+ prerelease: false
243
+ version_requirements: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - "~>"
246
+ - !ruby/object:Gem::Version
247
+ version: '0.7'
151
248
  - !ruby/object:Gem::Dependency
152
249
  name: appraisal
153
250
  requirement: !ruby/object:Gem::Requirement
@@ -190,6 +287,20 @@ dependencies:
190
287
  - - "~>"
191
288
  - !ruby/object:Gem::Version
192
289
  version: '3'
290
+ - !ruby/object:Gem::Dependency
291
+ name: benchmark
292
+ requirement: !ruby/object:Gem::Requirement
293
+ requirements:
294
+ - - "~>"
295
+ - !ruby/object:Gem::Version
296
+ version: '0.5'
297
+ type: :development
298
+ prerelease: false
299
+ version_requirements: !ruby/object:Gem::Requirement
300
+ requirements:
301
+ - - "~>"
302
+ - !ruby/object:Gem::Version
303
+ version: '0.5'
193
304
  description: Lightweight JSON logger and formatter integrating with Rails/ActiveSupport.
194
305
  No extra deps beyond Rails/Activesupport. Compatible with Rails 6–8.
195
306
  email:
@@ -220,7 +331,6 @@ metadata:
220
331
  source_code_uri: https://github.com/amkisko/activesupport-json_logging.rb
221
332
  changelog_uri: https://github.com/amkisko/activesupport-json_logging.rb/blob/main/CHANGELOG.md
222
333
  bug_tracker_uri: https://github.com/amkisko/activesupport-json_logging.rb/issues
223
- post_install_message:
224
334
  rdoc_options: []
225
335
  require_paths:
226
336
  - lib
@@ -235,8 +345,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
345
  - !ruby/object:Gem::Version
236
346
  version: '0'
237
347
  requirements: []
238
- rubygems_version: 3.5.9
239
- signing_key:
348
+ rubygems_version: 4.0.3
240
349
  specification_version: 4
241
350
  summary: Structured JSON logging for Rails/ActiveSupport with safe, single-line entries.
242
351
  test_files: []