activesupport-json_logging 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 +4 -4
- data/CHANGELOG.md +28 -0
- data/README.md +26 -31
- data/lib/json_logging/formatter.rb +13 -9
- data/lib/json_logging/formatter_with_tags.rb +38 -20
- data/lib/json_logging/helpers.rb +26 -1
- data/lib/json_logging/json_logger_extension.rb +47 -69
- data/lib/json_logging/line_encoder.rb +245 -0
- data/lib/json_logging/payload_builder.rb +57 -21
- data/lib/json_logging/sanitizer.rb +111 -10
- data/lib/json_logging/severity.rb +18 -0
- data/lib/json_logging/structured_hash_json_encoder.rb +111 -0
- data/lib/json_logging/structured_hash_sanitizer.rb +206 -0
- data/lib/json_logging/version.rb +1 -1
- data/lib/json_logging.rb +84 -11
- data/sig/json_logging.rbs +3 -0
- metadata +146 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 71ac52d26c4cca14a0eaed618927f9432880865ad9b24e43232b5801ce10a055
|
|
4
|
+
data.tar.gz: 81ef2c90e5d44fc7910f319acdbbd4bb9b56572075c6a28050fd05759349e91b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0f8ebdfeb94e456cdffd8e8d176c9dde7dff4187f2547b721dd4ec33e229c290663386a1f1c091ee54e95821be3bc11eb8f02fbf645f3a9bd8a54ab1e79596b9
|
|
7
|
+
data.tar.gz: cbfdad0f75642ec096bf18ca154a9aef9ce3364d92a43c263ceea81f877f018db3459b1a3fc239b2025aa6d96815db8f37063675f33a29d24fd24de4eaeb2299
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 1.2.3 (2026-07-13)
|
|
4
|
+
|
|
5
|
+
- Reduce per-line work for plain string, hash, tagged, and context-scoped log messages on common shapes
|
|
6
|
+
- Sanitize flat and nested structured hash payloads without deep-copying the source when values are logging-safe primitives
|
|
7
|
+
- Reuse ISO8601 microsecond UTC timestamps when callers already supply them
|
|
8
|
+
- Skip context merging when tags and additional context are both empty
|
|
9
|
+
- Cache empty thread context as a frozen hash on the hot path
|
|
10
|
+
- Expand hot-path contract specs for fast-path logging and sanitization
|
|
11
|
+
- Encode large nested structured hash log lines in one pass with copy-on-write sanitization and JSON.generate instead of building a full sanitized tree first
|
|
12
|
+
|
|
13
|
+
## 1.2.2 (2026-07-08)
|
|
14
|
+
|
|
15
|
+
- Isolate log context per execution via `ActiveSupport::IsolatedExecutionState` when available
|
|
16
|
+
- Sanitize fallback formatter output when JSON encoding fails
|
|
17
|
+
- Refactor emit path into `LineEncoder`, `PayloadBuilder`, and `Severity` modules
|
|
18
|
+
- Cache sanitized `additional_context` per `with_context` scope on the hot path
|
|
19
|
+
- Memoize `ActiveSupport::ParameterFilter` when `filter_parameters` is unchanged
|
|
20
|
+
- Fast-path `sanitize_string` for clean ASCII text within length limits
|
|
21
|
+
- Sanitize tags at push time instead of on every log line
|
|
22
|
+
- Skip `deep_stringify_keys` when payload structure already uses string keys
|
|
23
|
+
- Add hot-path optimization specs
|
|
24
|
+
|
|
25
|
+
## 1.2.1 (2026-01-18)
|
|
26
|
+
|
|
27
|
+
- Refactor tag stack handling in JsonLogging formatter for improved maintainability
|
|
28
|
+
- Refactor timestamp handling in JsonLogging helpers to support Time.zone
|
|
29
|
+
- Add Ruby 4.0 support in gemspec and Appraisal configurations
|
|
30
|
+
|
|
3
31
|
## 1.2.0 (2025-11-07)
|
|
4
32
|
|
|
5
33
|
- 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
|
-
[](https://badge.fury.io/rb/activesupport-json_logging) [](https://github.com/amkisko/activesupport-json_logging.rb/actions/workflows/test.yml) [](https://codecov.io/gh/amkisko/activesupport-json_logging.rb)
|
|
3
|
+
[](https://badge.fury.io/rb/activesupport-json_logging) [](https://github.com/amkisko/activesupport-json_logging.rb/actions/workflows/test.yml) [](https://codecov.io/gh/amkisko/activesupport-json_logging.rb) [](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
|
-
#
|
|
299
|
-
config.
|
|
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
|
-
|
|
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
|
-
|
|
606
|
-
bin/
|
|
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
|
|
@@ -2,17 +2,21 @@ module JsonLogging
|
|
|
2
2
|
class Formatter < ::Logger::Formatter
|
|
3
3
|
def initialize(tags: [])
|
|
4
4
|
super()
|
|
5
|
-
@tags =
|
|
5
|
+
@tags = Sanitizer.prepare_tags(tags)
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
attr_reader :tags
|
|
9
9
|
|
|
10
10
|
def call(severity, timestamp, progname, msg)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
LineEncoder.build_line(
|
|
12
|
+
msg: msg,
|
|
13
|
+
severity: severity,
|
|
14
|
+
timestamp: Helpers.normalize_timestamp(timestamp),
|
|
15
|
+
tags: @tags,
|
|
16
|
+
additional_context: JsonLogging.additional_context_for_payload,
|
|
17
|
+
additional_context_sanitized: true,
|
|
18
|
+
sanitize_tags: false
|
|
19
|
+
)
|
|
16
20
|
rescue => e
|
|
17
21
|
build_fallback_output(severity, timestamp, msg, e)
|
|
18
22
|
end
|
|
@@ -23,14 +27,14 @@ module JsonLogging
|
|
|
23
27
|
timestamp_str = Helpers.normalize_timestamp(timestamp)
|
|
24
28
|
fallback_payload = {
|
|
25
29
|
timestamp: timestamp_str,
|
|
26
|
-
severity: severity,
|
|
27
|
-
message: Helpers.safe_string(msg),
|
|
30
|
+
severity: Severity.name_for(severity),
|
|
31
|
+
message: Sanitizer.sanitize_string(Helpers.safe_string(msg)),
|
|
28
32
|
formatter_error: {
|
|
29
33
|
class: Sanitizer.sanitize_string(error.class.name),
|
|
30
34
|
message: Sanitizer.sanitize_string(Helpers.safe_string(error.message))
|
|
31
35
|
}
|
|
32
36
|
}
|
|
33
|
-
|
|
37
|
+
LineEncoder.to_json_line(fallback_payload)
|
|
34
38
|
end
|
|
35
39
|
end
|
|
36
40
|
end
|
|
@@ -10,28 +10,31 @@ 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
|
|
14
|
-
|
|
13
|
+
if (stack = current_tag_stack)
|
|
14
|
+
stack.tags
|
|
15
15
|
else
|
|
16
16
|
@logger.send(:current_tags)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def call(severity, timestamp, progname, msg)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
LineEncoder.build_line(
|
|
22
|
+
msg: msg,
|
|
23
|
+
severity: severity,
|
|
24
|
+
timestamp: Helpers.normalize_timestamp(timestamp),
|
|
25
|
+
tags: current_tags,
|
|
26
|
+
additional_context: JsonLogging.additional_context_for_payload,
|
|
27
|
+
additional_context_sanitized: true,
|
|
28
|
+
sanitize_tags: false
|
|
29
|
+
)
|
|
27
30
|
rescue => e
|
|
28
31
|
build_fallback_output(severity, timestamp, msg, e)
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
def push_tags(*tags)
|
|
32
35
|
# If LocalTagStorage is present, use it; otherwise use logger's thread-local storage
|
|
33
|
-
if
|
|
34
|
-
|
|
36
|
+
if (stack = current_tag_stack)
|
|
37
|
+
stack.push_tags(tags)
|
|
35
38
|
else
|
|
36
39
|
@logger.send(:push_tags, tags)
|
|
37
40
|
end
|
|
@@ -40,14 +43,12 @@ module JsonLogging
|
|
|
40
43
|
# Support tagged blocks for formatter
|
|
41
44
|
def tagged(*tags)
|
|
42
45
|
if block_given?
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
previous_count = tag_stack.tags.size
|
|
46
|
-
tag_stack.push_tags(tags)
|
|
46
|
+
if (stack = current_tag_stack)
|
|
47
|
+
pushed_count = stack.push_tags(tags).size
|
|
47
48
|
begin
|
|
48
49
|
yield @logger
|
|
49
50
|
ensure
|
|
50
|
-
|
|
51
|
+
stack.pop_tags(pushed_count)
|
|
51
52
|
end
|
|
52
53
|
else
|
|
53
54
|
previous = @logger.send(:current_tags).dup
|
|
@@ -59,8 +60,8 @@ module JsonLogging
|
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
62
|
else
|
|
62
|
-
if
|
|
63
|
-
|
|
63
|
+
if (stack = current_tag_stack)
|
|
64
|
+
stack.push_tags(tags)
|
|
64
65
|
else
|
|
65
66
|
@logger.send(:push_tags, tags)
|
|
66
67
|
end
|
|
@@ -70,18 +71,35 @@ module JsonLogging
|
|
|
70
71
|
|
|
71
72
|
private
|
|
72
73
|
|
|
74
|
+
# Returns the current tag_stack to use, checking in order:
|
|
75
|
+
# 1. This formatter's tag_stack (if LocalTagStorage is extended)
|
|
76
|
+
# 2. Logger's formatter's tag_stack (if it has LocalTagStorage)
|
|
77
|
+
# 3. nil (fall back to thread-local storage)
|
|
78
|
+
def current_tag_stack
|
|
79
|
+
if respond_to?(:tag_stack, true) && instance_variable_defined?(:@tag_stack)
|
|
80
|
+
tag_stack
|
|
81
|
+
elsif logger_formatter_has_tag_stack?
|
|
82
|
+
@logger.formatter.tag_stack
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def logger_formatter_has_tag_stack?
|
|
87
|
+
@logger.formatter.respond_to?(:tag_stack, true) &&
|
|
88
|
+
@logger.formatter.instance_variable_defined?(:@tag_stack)
|
|
89
|
+
end
|
|
90
|
+
|
|
73
91
|
def build_fallback_output(severity, timestamp, msg, error)
|
|
74
92
|
timestamp_str = Helpers.normalize_timestamp(timestamp)
|
|
75
93
|
fallback_payload = {
|
|
76
94
|
timestamp: timestamp_str,
|
|
77
|
-
severity: severity,
|
|
78
|
-
message: Helpers.safe_string(msg),
|
|
95
|
+
severity: Severity.name_for(severity),
|
|
96
|
+
message: Sanitizer.sanitize_string(Helpers.safe_string(msg)),
|
|
79
97
|
formatter_error: {
|
|
80
98
|
class: Sanitizer.sanitize_string(error.class.name),
|
|
81
99
|
message: Sanitizer.sanitize_string(Helpers.safe_string(error.message))
|
|
82
100
|
}
|
|
83
101
|
}
|
|
84
|
-
|
|
102
|
+
LineEncoder.to_json_line(fallback_payload)
|
|
85
103
|
end
|
|
86
104
|
end
|
|
87
105
|
end
|
data/lib/json_logging/helpers.rb
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
1
|
module JsonLogging
|
|
2
2
|
module Helpers
|
|
3
|
+
ISO8601_MICROSECOND_UTC_PATTERN = /\A\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z\z/
|
|
4
|
+
|
|
3
5
|
module_function
|
|
4
6
|
|
|
5
7
|
# Normalize timestamp to ISO8601 with microseconds
|
|
6
8
|
def normalize_timestamp(timestamp)
|
|
7
|
-
|
|
9
|
+
return timestamp if iso8601_microsecond_utc?(timestamp)
|
|
10
|
+
|
|
11
|
+
format_timestamp(timestamp || current_time)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def current_timestamp
|
|
15
|
+
format_timestamp(current_time)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def format_timestamp(time)
|
|
19
|
+
time.utc.iso8601(6)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def iso8601_microsecond_utc?(timestamp)
|
|
23
|
+
timestamp.is_a?(String) && timestamp.match?(ISO8601_MICROSECOND_UTC_PATTERN)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Get current time, using Time.zone if available, otherwise Time.now
|
|
27
|
+
def current_time
|
|
28
|
+
if defined?(Time.zone) && Time.zone
|
|
29
|
+
Time.zone.now
|
|
30
|
+
else
|
|
31
|
+
Time.now
|
|
32
|
+
end
|
|
8
33
|
end
|
|
9
34
|
|
|
10
35
|
# Safely convert object to string, never raises
|
|
@@ -2,15 +2,6 @@ module JsonLogging
|
|
|
2
2
|
# Module that extends any Logger with JSON formatting capabilities
|
|
3
3
|
# This is used by JsonLogging.new to wrap standard loggers
|
|
4
4
|
module JsonLoggerExtension
|
|
5
|
-
SEVERITY_NAMES = {
|
|
6
|
-
::Logger::DEBUG => "DEBUG",
|
|
7
|
-
::Logger::INFO => "INFO",
|
|
8
|
-
::Logger::WARN => "WARN",
|
|
9
|
-
::Logger::ERROR => "ERROR",
|
|
10
|
-
::Logger::FATAL => "FATAL",
|
|
11
|
-
::Logger::UNKNOWN => "UNKNOWN"
|
|
12
|
-
}.freeze
|
|
13
|
-
|
|
14
5
|
def formatter
|
|
15
6
|
@formatter_with_tags ||= begin
|
|
16
7
|
formatter_with_tags = FormatterWithTags.new(self)
|
|
@@ -19,46 +10,31 @@ module JsonLogging
|
|
|
19
10
|
end
|
|
20
11
|
end
|
|
21
12
|
|
|
22
|
-
def formatter=(
|
|
23
|
-
#
|
|
13
|
+
def formatter=(_ignored)
|
|
14
|
+
# Custom formatters are ignored; JSON output requires FormatterWithTags.
|
|
24
15
|
formatter_with_tags = @formatter_with_tags || FormatterWithTags.new(self)
|
|
25
16
|
instance_variable_set(:@formatter, formatter_with_tags)
|
|
26
17
|
@formatter_with_tags = formatter_with_tags
|
|
27
18
|
end
|
|
28
19
|
|
|
29
|
-
def add(severity, message = nil, progname = nil)
|
|
20
|
+
def add(severity, message = nil, progname = nil, &block)
|
|
30
21
|
return true if severity < level
|
|
31
22
|
|
|
32
|
-
msg =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
stringified = stringify_keys(payload)
|
|
45
|
-
@logdev&.write("#{stringified.to_json}\n")
|
|
23
|
+
msg = nil
|
|
24
|
+
msg = extract_log_message(message, progname, &block)
|
|
25
|
+
line = LineEncoder.build_line(
|
|
26
|
+
msg: msg,
|
|
27
|
+
severity: severity,
|
|
28
|
+
timestamp: Helpers.current_timestamp,
|
|
29
|
+
tags: formatter.current_tags,
|
|
30
|
+
additional_context: JsonLogging.additional_context_for_payload,
|
|
31
|
+
additional_context_sanitized: true,
|
|
32
|
+
sanitize_tags: false
|
|
33
|
+
)
|
|
34
|
+
@logdev&.write(line)
|
|
46
35
|
true
|
|
47
36
|
rescue => e
|
|
48
|
-
|
|
49
|
-
# Initialize msg if it wasn't set due to error
|
|
50
|
-
msg ||= "<uninitialized>"
|
|
51
|
-
|
|
52
|
-
fallback = {
|
|
53
|
-
timestamp: Helpers.normalize_timestamp(Time.now),
|
|
54
|
-
severity: severity_name(severity),
|
|
55
|
-
message: Sanitizer.sanitize_string(Helpers.safe_string(msg)),
|
|
56
|
-
logger_error: {
|
|
57
|
-
class: Sanitizer.sanitize_string(e.class.name),
|
|
58
|
-
message: Sanitizer.sanitize_string(Helpers.safe_string(e.message))
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
@logdev&.write("#{fallback.compact.to_json}\n")
|
|
37
|
+
write_add_fallback(severity, msg, e)
|
|
62
38
|
true
|
|
63
39
|
end
|
|
64
40
|
|
|
@@ -91,6 +67,28 @@ module JsonLogging
|
|
|
91
67
|
|
|
92
68
|
private
|
|
93
69
|
|
|
70
|
+
def extract_log_message(message, progname, &block)
|
|
71
|
+
if message.nil?
|
|
72
|
+
block ? block.call : progname
|
|
73
|
+
else
|
|
74
|
+
message
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def write_add_fallback(severity, msg, error)
|
|
79
|
+
msg ||= "<uninitialized>"
|
|
80
|
+
fallback = {
|
|
81
|
+
timestamp: Helpers.current_timestamp,
|
|
82
|
+
severity: Severity.name_for(severity),
|
|
83
|
+
message: Sanitizer.sanitize_string(Helpers.safe_string(msg)),
|
|
84
|
+
logger_error: {
|
|
85
|
+
class: Sanitizer.sanitize_string(error.class.name),
|
|
86
|
+
message: Sanitizer.sanitize_string(Helpers.safe_string(error.message))
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
@logdev&.write(LineEncoder.to_json_line(fallback))
|
|
90
|
+
end
|
|
91
|
+
|
|
94
92
|
def tags_key
|
|
95
93
|
@tags_key ||= :"json_logging_tags_#{object_id}"
|
|
96
94
|
end
|
|
@@ -116,8 +114,9 @@ module JsonLogging
|
|
|
116
114
|
end
|
|
117
115
|
|
|
118
116
|
def push_tags(tags)
|
|
119
|
-
flat =
|
|
117
|
+
flat = Sanitizer.prepare_tags(tags)
|
|
120
118
|
return if flat.empty?
|
|
119
|
+
|
|
121
120
|
set_tags(current_tags + flat)
|
|
122
121
|
end
|
|
123
122
|
|
|
@@ -125,36 +124,12 @@ module JsonLogging
|
|
|
125
124
|
set_tags([])
|
|
126
125
|
end
|
|
127
126
|
|
|
128
|
-
def build_payload(severity, _progname, msg)
|
|
129
|
-
payload = PayloadBuilder.build_base_payload(
|
|
130
|
-
msg,
|
|
131
|
-
severity: severity_name(severity),
|
|
132
|
-
timestamp: Helpers.normalize_timestamp(Time.now)
|
|
133
|
-
)
|
|
134
|
-
payload = PayloadBuilder.merge_context(
|
|
135
|
-
payload,
|
|
136
|
-
additional_context: JsonLogging.additional_context.compact,
|
|
137
|
-
tags: formatter.current_tags
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
payload.compact
|
|
141
|
-
end
|
|
142
|
-
|
|
143
127
|
def severity_name(severity)
|
|
144
|
-
|
|
128
|
+
Severity.name_for(severity)
|
|
145
129
|
end
|
|
146
130
|
|
|
147
|
-
def stringify_keys(
|
|
148
|
-
|
|
149
|
-
when Hash
|
|
150
|
-
hash.each_with_object({}) do |(k, v), result|
|
|
151
|
-
result[k.to_s] = stringify_keys(v)
|
|
152
|
-
end
|
|
153
|
-
when Array
|
|
154
|
-
hash.map { |v| stringify_keys(v) }
|
|
155
|
-
else
|
|
156
|
-
hash
|
|
157
|
-
end
|
|
131
|
+
def stringify_keys(obj)
|
|
132
|
+
LineEncoder.deep_stringify_structure(obj)
|
|
158
133
|
end
|
|
159
134
|
end
|
|
160
135
|
|
|
@@ -179,13 +154,16 @@ module JsonLogging
|
|
|
179
154
|
end
|
|
180
155
|
|
|
181
156
|
def push_tags(tags)
|
|
182
|
-
flat =
|
|
157
|
+
flat = Sanitizer.prepare_tags(tags)
|
|
183
158
|
return [] if flat.empty?
|
|
159
|
+
|
|
184
160
|
@tags.concat(flat)
|
|
185
161
|
flat
|
|
186
162
|
end
|
|
187
163
|
|
|
188
164
|
def pop_tags(count = 1)
|
|
165
|
+
return [] if count <= 0
|
|
166
|
+
|
|
189
167
|
@tags.pop(count)
|
|
190
168
|
end
|
|
191
169
|
|