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
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
module JsonLogging
|
|
2
|
+
module Sanitizer
|
|
3
|
+
module StructuredHash
|
|
4
|
+
JsonableResult = Struct.new(:tree, :owned, :leaf_count, keyword_init: true)
|
|
5
|
+
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def structured_log_hash?(hash, seen = nil)
|
|
9
|
+
seen ||= Set.new.compare_by_identity
|
|
10
|
+
return false unless seen.add?(hash)
|
|
11
|
+
|
|
12
|
+
result = hash.all? { |_key, value| structured_log_value?(value, seen) }
|
|
13
|
+
seen.delete(hash)
|
|
14
|
+
result
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def structured_log_value?(value, seen = nil)
|
|
18
|
+
case value
|
|
19
|
+
when String, Numeric, TrueClass, FalseClass, NilClass
|
|
20
|
+
Sanitizer.primitive_log_value?(value)
|
|
21
|
+
when Hash
|
|
22
|
+
structured_log_hash?(value, seen)
|
|
23
|
+
when Array
|
|
24
|
+
structured_log_array?(value, seen)
|
|
25
|
+
else
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def structured_log_array?(array, seen = nil)
|
|
31
|
+
array.all? { |value| structured_log_value?(value, seen) }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def sanitize(hash, depth: 0)
|
|
35
|
+
return {"error" => "max_depth_exceeded"} if depth > Sanitizer::MAX_DEPTH
|
|
36
|
+
|
|
37
|
+
filter = Sanitizer.rails_parameter_filter
|
|
38
|
+
if filter
|
|
39
|
+
filter.filter(stringify(hash))
|
|
40
|
+
else
|
|
41
|
+
sanitize_without_filter(hash, depth: depth)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def sanitize_without_filter(hash, depth: 0)
|
|
46
|
+
jsonable = jsonable_tree(hash, depth: depth)
|
|
47
|
+
if jsonable.owned
|
|
48
|
+
stringify(jsonable.tree)
|
|
49
|
+
else
|
|
50
|
+
jsonable.tree.dup
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def jsonable_tree(hash, depth: 0, seen: nil, parent_key: nil, omit_keys: nil, count_leaves: false, leaf_counter: nil)
|
|
55
|
+
seen ||= Set.new.compare_by_identity
|
|
56
|
+
leaf_counter = [0] if count_leaves && leaf_counter.nil?
|
|
57
|
+
if depth > Sanitizer::MAX_DEPTH
|
|
58
|
+
return JsonableResult.new(tree: {"error" => "max_depth_exceeded"}, owned: true, leaf_count: leaf_counter&.[](0))
|
|
59
|
+
end
|
|
60
|
+
unless seen.add?(hash)
|
|
61
|
+
return JsonableResult.new(tree: {"error" => "cyclic_reference"}, owned: true, leaf_count: leaf_counter&.[](0))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
entries = []
|
|
65
|
+
owned = false
|
|
66
|
+
|
|
67
|
+
hash.each do |key, value|
|
|
68
|
+
entry = process_jsonable_entry(
|
|
69
|
+
key,
|
|
70
|
+
value,
|
|
71
|
+
depth: depth,
|
|
72
|
+
seen: seen,
|
|
73
|
+
parent_key: parent_key,
|
|
74
|
+
omit_keys: omit_keys,
|
|
75
|
+
leaf_counter: leaf_counter
|
|
76
|
+
)
|
|
77
|
+
next unless entry
|
|
78
|
+
|
|
79
|
+
key_string, encoded_value, pair_owned = entry
|
|
80
|
+
owned ||= pair_owned
|
|
81
|
+
entries << [key_string, encoded_value, pair_owned]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
seen.delete(hash)
|
|
85
|
+
leaf_count = leaf_counter&.[](0)
|
|
86
|
+
unless owned
|
|
87
|
+
tree = omit_root_keys(hash, omit_keys, depth: depth)
|
|
88
|
+
return JsonableResult.new(tree: tree, owned: false, leaf_count: leaf_count)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
result = entries.each_with_object({}) do |(key_string, encoded_value, _pair_owned), object|
|
|
92
|
+
object[key_string] = encoded_value
|
|
93
|
+
end
|
|
94
|
+
JsonableResult.new(tree: result, owned: true, leaf_count: leaf_count)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def jsonable_value(value, depth:, seen:, parent_key:, leaf_counter: nil)
|
|
98
|
+
case value
|
|
99
|
+
when String
|
|
100
|
+
leaf_counter[0] += 1 if leaf_counter
|
|
101
|
+
sanitized = Sanitizer.sanitize_string(value)
|
|
102
|
+
JsonableResult.new(tree: sanitized, owned: sanitized != value)
|
|
103
|
+
when Hash
|
|
104
|
+
jsonable_tree(value, depth: depth + 1, seen: seen, parent_key: parent_key, leaf_counter: leaf_counter)
|
|
105
|
+
when Array
|
|
106
|
+
jsonable_array(value, depth: depth, seen: seen, parent_key: parent_key, leaf_counter: leaf_counter)
|
|
107
|
+
else
|
|
108
|
+
leaf_counter[0] += 1 if leaf_counter
|
|
109
|
+
JsonableResult.new(tree: value, owned: false)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def jsonable_array(array, depth:, seen:, parent_key:, leaf_counter: nil)
|
|
114
|
+
owned = false
|
|
115
|
+
result = nil
|
|
116
|
+
|
|
117
|
+
array.each_with_index do |entry, index|
|
|
118
|
+
child = jsonable_value(entry, depth: depth, seen: seen, parent_key: parent_key, leaf_counter: leaf_counter)
|
|
119
|
+
next unless child.owned
|
|
120
|
+
|
|
121
|
+
owned = true
|
|
122
|
+
result ||= array.dup
|
|
123
|
+
result[index] = child.tree
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
JsonableResult.new(tree: owned ? result : array, owned: owned)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def process_jsonable_entry(key, value, depth:, seen:, parent_key:, omit_keys:, leaf_counter:)
|
|
130
|
+
key_string = key.to_s
|
|
131
|
+
if root_key_omitted?(depth, key_string, omit_keys)
|
|
132
|
+
count_leaves_in_value(value, leaf_counter, depth: depth, seen: seen) if leaf_counter
|
|
133
|
+
return
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
if Sanitizer::SENSITIVE_KEY_PATTERNS.match?(key_string)
|
|
137
|
+
return [Sanitizer.sensitive_filtered_key_name(key_string), "[FILTERED]", true]
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
nested_parent = parent_key ? "#{parent_key}.#{key_string}" : key_string
|
|
141
|
+
child = jsonable_value(
|
|
142
|
+
value,
|
|
143
|
+
depth: depth,
|
|
144
|
+
seen: seen,
|
|
145
|
+
parent_key: nested_parent,
|
|
146
|
+
leaf_counter: leaf_counter
|
|
147
|
+
)
|
|
148
|
+
encoded_value = child.owned ? child.tree : value
|
|
149
|
+
[key_string, encoded_value, child.owned]
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def root_key_omitted?(depth, key_string, omit_keys)
|
|
153
|
+
depth.zero? && omit_keys&.include?(key_string)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def omit_root_keys(hash, omit_keys, depth:)
|
|
157
|
+
return hash unless depth.zero? && omit_keys&.any?
|
|
158
|
+
|
|
159
|
+
hash.each_with_object({}) do |(key, value), object|
|
|
160
|
+
object[key] = value unless omit_keys.include?(key.to_s)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def count_leaves_in_value(value, leaf_counter, depth:, seen:)
|
|
165
|
+
case value
|
|
166
|
+
when Hash
|
|
167
|
+
return unless seen.add?(value)
|
|
168
|
+
|
|
169
|
+
value.each_value do |entry|
|
|
170
|
+
count_leaves_in_value(entry, leaf_counter, depth: depth + 1, seen: seen)
|
|
171
|
+
end
|
|
172
|
+
seen.delete(value)
|
|
173
|
+
when Array
|
|
174
|
+
value.each { |entry| count_leaves_in_value(entry, leaf_counter, depth: depth, seen: seen) }
|
|
175
|
+
else
|
|
176
|
+
leaf_counter[0] += 1
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def stringify(hash)
|
|
181
|
+
hash.each_with_object({}) do |(key, value), result|
|
|
182
|
+
result[key.to_s] = stringify_value(value)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def stringify_value(value)
|
|
187
|
+
case value
|
|
188
|
+
when Hash
|
|
189
|
+
stringify(value)
|
|
190
|
+
when Array
|
|
191
|
+
value.map { |entry| stringify_value(entry) }
|
|
192
|
+
when String
|
|
193
|
+
Sanitizer.sanitize_string(value)
|
|
194
|
+
else
|
|
195
|
+
value
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def stringify_keys_copy(hash)
|
|
200
|
+
return hash if hash.keys.all? { |key| key.is_a?(String) }
|
|
201
|
+
|
|
202
|
+
hash.transform_keys(&:to_s)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
data/lib/json_logging/version.rb
CHANGED
data/lib/json_logging.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative "json_logging/helpers"
|
|
|
7
7
|
require_relative "json_logging/sanitizer"
|
|
8
8
|
require_relative "json_logging/message_parser"
|
|
9
9
|
require_relative "json_logging/payload_builder"
|
|
10
|
+
require_relative "json_logging/line_encoder"
|
|
10
11
|
require_relative "json_logging/formatter"
|
|
11
12
|
require_relative "json_logging/formatter_with_tags"
|
|
12
13
|
require_relative "json_logging/json_logger_extension"
|
|
@@ -14,13 +15,28 @@ require_relative "json_logging/json_logger"
|
|
|
14
15
|
|
|
15
16
|
module JsonLogging
|
|
16
17
|
THREAD_CONTEXT_KEY = :__json_logging_context
|
|
18
|
+
SANITIZED_CONTEXT_CACHE_KEY = :__json_logging_sanitized_context
|
|
19
|
+
@additional_context_warned = Set.new
|
|
20
|
+
@additional_context_transformer = nil
|
|
21
|
+
|
|
22
|
+
def self.context_storage
|
|
23
|
+
if defined?(ActiveSupport::IsolatedExecutionState)
|
|
24
|
+
ActiveSupport::IsolatedExecutionState
|
|
25
|
+
else
|
|
26
|
+
Thread.current
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
private_class_method :context_storage
|
|
17
30
|
|
|
18
31
|
def self.with_context(extra_context)
|
|
19
|
-
|
|
20
|
-
|
|
32
|
+
storage = context_storage
|
|
33
|
+
original = storage[THREAD_CONTEXT_KEY]
|
|
34
|
+
storage[THREAD_CONTEXT_KEY] = (original || {}).merge(safe_hash(extra_context))
|
|
35
|
+
invalidate_sanitized_context_cache(storage)
|
|
21
36
|
yield
|
|
22
37
|
ensure
|
|
23
|
-
|
|
38
|
+
storage[THREAD_CONTEXT_KEY] = original
|
|
39
|
+
invalidate_sanitized_context_cache(storage)
|
|
24
40
|
end
|
|
25
41
|
|
|
26
42
|
# Returns the current thread-local context when called without arguments,
|
|
@@ -42,8 +58,9 @@ module JsonLogging
|
|
|
42
58
|
end
|
|
43
59
|
|
|
44
60
|
begin
|
|
45
|
-
base_context = (
|
|
46
|
-
rescue
|
|
61
|
+
base_context = (context_storage[THREAD_CONTEXT_KEY] || {}).dup
|
|
62
|
+
rescue => e
|
|
63
|
+
warn_additional_context_once(:dup, "thread context dup failed", e)
|
|
47
64
|
base_context = {}
|
|
48
65
|
end
|
|
49
66
|
|
|
@@ -51,7 +68,8 @@ module JsonLogging
|
|
|
51
68
|
if transformer.is_a?(Proc)
|
|
52
69
|
begin
|
|
53
70
|
transformer.call(base_context)
|
|
54
|
-
rescue
|
|
71
|
+
rescue => e
|
|
72
|
+
warn_additional_context_once(:transformer, "additional_context transformer failed", e)
|
|
55
73
|
base_context
|
|
56
74
|
end
|
|
57
75
|
else
|
|
@@ -61,6 +79,26 @@ module JsonLogging
|
|
|
61
79
|
|
|
62
80
|
def self.additional_context=(proc_or_block)
|
|
63
81
|
@additional_context_transformer = proc_or_block
|
|
82
|
+
invalidate_sanitized_context_cache(context_storage)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def self.additional_context_for_payload
|
|
86
|
+
if @additional_context_transformer.is_a?(Proc)
|
|
87
|
+
return sanitized_context_from(compact_context(additional_context))
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
storage = context_storage
|
|
91
|
+
cached = storage[SANITIZED_CONTEXT_CACHE_KEY]
|
|
92
|
+
return cached if cached
|
|
93
|
+
|
|
94
|
+
raw_context = storage[THREAD_CONTEXT_KEY]
|
|
95
|
+
if raw_context.nil? || (raw_context.is_a?(Hash) && raw_context.empty?)
|
|
96
|
+
return storage[SANITIZED_CONTEXT_CACHE_KEY] = {}.freeze
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
sanitized = sanitized_context_from(compact_context(raw_context))
|
|
100
|
+
storage[SANITIZED_CONTEXT_CACHE_KEY] = sanitized.freeze
|
|
101
|
+
sanitized
|
|
64
102
|
end
|
|
65
103
|
|
|
66
104
|
def self.safe_hash(obj)
|
|
@@ -69,6 +107,34 @@ module JsonLogging
|
|
|
69
107
|
{}
|
|
70
108
|
end
|
|
71
109
|
|
|
110
|
+
def self.warn_additional_context_once(key, message, error)
|
|
111
|
+
return if @additional_context_warned.include?(key)
|
|
112
|
+
|
|
113
|
+
@additional_context_warned.add(key)
|
|
114
|
+
warn "[activesupport-json_logging] #{message} (#{error.class}: #{error.message})"
|
|
115
|
+
end
|
|
116
|
+
private_class_method :warn_additional_context_once
|
|
117
|
+
|
|
118
|
+
def self.compact_context(context)
|
|
119
|
+
return {} unless context.is_a?(Hash)
|
|
120
|
+
return {} if context.empty?
|
|
121
|
+
|
|
122
|
+
context.compact
|
|
123
|
+
end
|
|
124
|
+
private_class_method :compact_context
|
|
125
|
+
|
|
126
|
+
def self.sanitized_context_from(compacted_context)
|
|
127
|
+
return {} if compacted_context.empty?
|
|
128
|
+
|
|
129
|
+
Sanitizer.sanitize_hash(compacted_context)
|
|
130
|
+
end
|
|
131
|
+
private_class_method :sanitized_context_from
|
|
132
|
+
|
|
133
|
+
def self.invalidate_sanitized_context_cache(storage)
|
|
134
|
+
storage[SANITIZED_CONTEXT_CACHE_KEY] = nil
|
|
135
|
+
end
|
|
136
|
+
private_class_method :invalidate_sanitized_context_cache
|
|
137
|
+
|
|
72
138
|
# Returns an `ActiveSupport::Logger` that has already been wrapped with JSON logging concern.
|
|
73
139
|
#
|
|
74
140
|
# @param *args Arguments passed to ActiveSupport::Logger.new
|
|
@@ -97,6 +163,17 @@ module JsonLogging
|
|
|
97
163
|
# logger.tagged("BCX") { logger.info("Stuff") } # Logs with tags
|
|
98
164
|
# logger.tagged("BCX").info("Stuff") # Logs with tags (non-block form)
|
|
99
165
|
def self.new(logger)
|
|
166
|
+
logger = prepare_logger_clone(logger)
|
|
167
|
+
logger.extend(JsonLoggerExtension)
|
|
168
|
+
formatter_with_tags = FormatterWithTags.new(logger)
|
|
169
|
+
logger.instance_variable_set(:@formatter_with_tags, formatter_with_tags)
|
|
170
|
+
# Custom formatters are not supported: JSON output requires FormatterWithTags.
|
|
171
|
+
logger.formatter = formatter_with_tags
|
|
172
|
+
|
|
173
|
+
logger
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def self.prepare_logger_clone(logger)
|
|
100
177
|
logger = logger.clone
|
|
101
178
|
if logger.formatter
|
|
102
179
|
logger.formatter = logger.formatter.clone
|
|
@@ -114,11 +191,7 @@ module JsonLogging
|
|
|
114
191
|
end
|
|
115
192
|
end
|
|
116
193
|
|
|
117
|
-
logger.extend(JsonLoggerExtension)
|
|
118
|
-
formatter_with_tags = FormatterWithTags.new(logger)
|
|
119
|
-
logger.instance_variable_set(:@formatter_with_tags, formatter_with_tags)
|
|
120
|
-
logger.formatter = formatter_with_tags
|
|
121
|
-
|
|
122
194
|
logger
|
|
123
195
|
end
|
|
196
|
+
private_class_method :prepare_logger_clone
|
|
124
197
|
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.
|
|
4
|
+
version: 1.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrei Makarov
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: activesupport
|
|
@@ -64,6 +63,20 @@ dependencies:
|
|
|
64
63
|
- - "~>"
|
|
65
64
|
- !ruby/object:Gem::Version
|
|
66
65
|
version: '3'
|
|
66
|
+
- !ruby/object:Gem::Dependency
|
|
67
|
+
name: polyrun
|
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: 2.2.0
|
|
73
|
+
type: :development
|
|
74
|
+
prerelease: false
|
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
76
|
+
requirements:
|
|
77
|
+
- - ">="
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: 2.2.0
|
|
67
80
|
- !ruby/object:Gem::Dependency
|
|
68
81
|
name: webmock
|
|
69
82
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -93,61 +106,131 @@ dependencies:
|
|
|
93
106
|
- !ruby/object:Gem::Version
|
|
94
107
|
version: '13'
|
|
95
108
|
- !ruby/object:Gem::Dependency
|
|
96
|
-
name:
|
|
109
|
+
name: rspec_junit_formatter
|
|
97
110
|
requirement: !ruby/object:Gem::Requirement
|
|
98
111
|
requirements:
|
|
99
112
|
- - "~>"
|
|
100
113
|
- !ruby/object:Gem::Version
|
|
101
|
-
version: '0.
|
|
114
|
+
version: '0.6'
|
|
102
115
|
type: :development
|
|
103
116
|
prerelease: false
|
|
104
117
|
version_requirements: !ruby/object:Gem::Requirement
|
|
105
118
|
requirements:
|
|
106
119
|
- - "~>"
|
|
107
120
|
- !ruby/object:Gem::Version
|
|
108
|
-
version: '0.
|
|
121
|
+
version: '0.6'
|
|
109
122
|
- !ruby/object:Gem::Dependency
|
|
110
|
-
name:
|
|
123
|
+
name: standard
|
|
111
124
|
requirement: !ruby/object:Gem::Requirement
|
|
112
125
|
requirements:
|
|
113
126
|
- - "~>"
|
|
114
127
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: '
|
|
128
|
+
version: '1.52'
|
|
116
129
|
type: :development
|
|
117
130
|
prerelease: false
|
|
118
131
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
132
|
requirements:
|
|
120
133
|
- - "~>"
|
|
121
134
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: '
|
|
135
|
+
version: '1.52'
|
|
123
136
|
- !ruby/object:Gem::Dependency
|
|
124
|
-
name:
|
|
137
|
+
name: standard-custom
|
|
125
138
|
requirement: !ruby/object:Gem::Requirement
|
|
126
139
|
requirements:
|
|
127
140
|
- - "~>"
|
|
128
141
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: '
|
|
142
|
+
version: '1.0'
|
|
130
143
|
type: :development
|
|
131
144
|
prerelease: false
|
|
132
145
|
version_requirements: !ruby/object:Gem::Requirement
|
|
133
146
|
requirements:
|
|
134
147
|
- - "~>"
|
|
135
148
|
- !ruby/object:Gem::Version
|
|
136
|
-
version: '
|
|
149
|
+
version: '1.0'
|
|
137
150
|
- !ruby/object:Gem::Dependency
|
|
138
|
-
name: standard
|
|
151
|
+
name: standard-performance
|
|
139
152
|
requirement: !ruby/object:Gem::Requirement
|
|
140
153
|
requirements:
|
|
141
154
|
- - "~>"
|
|
142
155
|
- !ruby/object:Gem::Version
|
|
143
|
-
version: '1'
|
|
156
|
+
version: '1.8'
|
|
144
157
|
type: :development
|
|
145
158
|
prerelease: false
|
|
146
159
|
version_requirements: !ruby/object:Gem::Requirement
|
|
147
160
|
requirements:
|
|
148
161
|
- - "~>"
|
|
149
162
|
- !ruby/object:Gem::Version
|
|
150
|
-
version: '1'
|
|
163
|
+
version: '1.8'
|
|
164
|
+
- !ruby/object:Gem::Dependency
|
|
165
|
+
name: standard-rails
|
|
166
|
+
requirement: !ruby/object:Gem::Requirement
|
|
167
|
+
requirements:
|
|
168
|
+
- - "~>"
|
|
169
|
+
- !ruby/object:Gem::Version
|
|
170
|
+
version: '1.5'
|
|
171
|
+
type: :development
|
|
172
|
+
prerelease: false
|
|
173
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
174
|
+
requirements:
|
|
175
|
+
- - "~>"
|
|
176
|
+
- !ruby/object:Gem::Version
|
|
177
|
+
version: '1.5'
|
|
178
|
+
- !ruby/object:Gem::Dependency
|
|
179
|
+
name: standard-rspec
|
|
180
|
+
requirement: !ruby/object:Gem::Requirement
|
|
181
|
+
requirements:
|
|
182
|
+
- - "~>"
|
|
183
|
+
- !ruby/object:Gem::Version
|
|
184
|
+
version: '0.3'
|
|
185
|
+
type: :development
|
|
186
|
+
prerelease: false
|
|
187
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
188
|
+
requirements:
|
|
189
|
+
- - "~>"
|
|
190
|
+
- !ruby/object:Gem::Version
|
|
191
|
+
version: '0.3'
|
|
192
|
+
- !ruby/object:Gem::Dependency
|
|
193
|
+
name: rubocop-rails
|
|
194
|
+
requirement: !ruby/object:Gem::Requirement
|
|
195
|
+
requirements:
|
|
196
|
+
- - "~>"
|
|
197
|
+
- !ruby/object:Gem::Version
|
|
198
|
+
version: '2.33'
|
|
199
|
+
type: :development
|
|
200
|
+
prerelease: false
|
|
201
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
202
|
+
requirements:
|
|
203
|
+
- - "~>"
|
|
204
|
+
- !ruby/object:Gem::Version
|
|
205
|
+
version: '2.33'
|
|
206
|
+
- !ruby/object:Gem::Dependency
|
|
207
|
+
name: rubocop-rspec
|
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
|
209
|
+
requirements:
|
|
210
|
+
- - "~>"
|
|
211
|
+
- !ruby/object:Gem::Version
|
|
212
|
+
version: '3.8'
|
|
213
|
+
type: :development
|
|
214
|
+
prerelease: false
|
|
215
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
216
|
+
requirements:
|
|
217
|
+
- - "~>"
|
|
218
|
+
- !ruby/object:Gem::Version
|
|
219
|
+
version: '3.8'
|
|
220
|
+
- !ruby/object:Gem::Dependency
|
|
221
|
+
name: rubocop-thread_safety
|
|
222
|
+
requirement: !ruby/object:Gem::Requirement
|
|
223
|
+
requirements:
|
|
224
|
+
- - "~>"
|
|
225
|
+
- !ruby/object:Gem::Version
|
|
226
|
+
version: '0.7'
|
|
227
|
+
type: :development
|
|
228
|
+
prerelease: false
|
|
229
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
230
|
+
requirements:
|
|
231
|
+
- - "~>"
|
|
232
|
+
- !ruby/object:Gem::Version
|
|
233
|
+
version: '0.7'
|
|
151
234
|
- !ruby/object:Gem::Dependency
|
|
152
235
|
name: appraisal
|
|
153
236
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -190,6 +273,48 @@ dependencies:
|
|
|
190
273
|
- - "~>"
|
|
191
274
|
- !ruby/object:Gem::Version
|
|
192
275
|
version: '3'
|
|
276
|
+
- !ruby/object:Gem::Dependency
|
|
277
|
+
name: benchmark
|
|
278
|
+
requirement: !ruby/object:Gem::Requirement
|
|
279
|
+
requirements:
|
|
280
|
+
- - "~>"
|
|
281
|
+
- !ruby/object:Gem::Version
|
|
282
|
+
version: '0.5'
|
|
283
|
+
type: :development
|
|
284
|
+
prerelease: false
|
|
285
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
286
|
+
requirements:
|
|
287
|
+
- - "~>"
|
|
288
|
+
- !ruby/object:Gem::Version
|
|
289
|
+
version: '0.5'
|
|
290
|
+
- !ruby/object:Gem::Dependency
|
|
291
|
+
name: benchmark-ips
|
|
292
|
+
requirement: !ruby/object:Gem::Requirement
|
|
293
|
+
requirements:
|
|
294
|
+
- - "~>"
|
|
295
|
+
- !ruby/object:Gem::Version
|
|
296
|
+
version: '2'
|
|
297
|
+
type: :development
|
|
298
|
+
prerelease: false
|
|
299
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
300
|
+
requirements:
|
|
301
|
+
- - "~>"
|
|
302
|
+
- !ruby/object:Gem::Version
|
|
303
|
+
version: '2'
|
|
304
|
+
- !ruby/object:Gem::Dependency
|
|
305
|
+
name: stackprof
|
|
306
|
+
requirement: !ruby/object:Gem::Requirement
|
|
307
|
+
requirements:
|
|
308
|
+
- - "~>"
|
|
309
|
+
- !ruby/object:Gem::Version
|
|
310
|
+
version: '0.2'
|
|
311
|
+
type: :development
|
|
312
|
+
prerelease: false
|
|
313
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
314
|
+
requirements:
|
|
315
|
+
- - "~>"
|
|
316
|
+
- !ruby/object:Gem::Version
|
|
317
|
+
version: '0.2'
|
|
193
318
|
description: Lightweight JSON logger and formatter integrating with Rails/ActiveSupport.
|
|
194
319
|
No extra deps beyond Rails/Activesupport. Compatible with Rails 6–8.
|
|
195
320
|
email:
|
|
@@ -209,10 +334,15 @@ files:
|
|
|
209
334
|
- lib/json_logging/helpers.rb
|
|
210
335
|
- lib/json_logging/json_logger.rb
|
|
211
336
|
- lib/json_logging/json_logger_extension.rb
|
|
337
|
+
- lib/json_logging/line_encoder.rb
|
|
212
338
|
- lib/json_logging/message_parser.rb
|
|
213
339
|
- lib/json_logging/payload_builder.rb
|
|
214
340
|
- lib/json_logging/sanitizer.rb
|
|
341
|
+
- lib/json_logging/severity.rb
|
|
342
|
+
- lib/json_logging/structured_hash_json_encoder.rb
|
|
343
|
+
- lib/json_logging/structured_hash_sanitizer.rb
|
|
215
344
|
- lib/json_logging/version.rb
|
|
345
|
+
- sig/json_logging.rbs
|
|
216
346
|
homepage: https://github.com/amkisko/activesupport-json_logging.rb
|
|
217
347
|
licenses:
|
|
218
348
|
- MIT
|
|
@@ -220,7 +350,6 @@ metadata:
|
|
|
220
350
|
source_code_uri: https://github.com/amkisko/activesupport-json_logging.rb
|
|
221
351
|
changelog_uri: https://github.com/amkisko/activesupport-json_logging.rb/blob/main/CHANGELOG.md
|
|
222
352
|
bug_tracker_uri: https://github.com/amkisko/activesupport-json_logging.rb/issues
|
|
223
|
-
post_install_message:
|
|
224
353
|
rdoc_options: []
|
|
225
354
|
require_paths:
|
|
226
355
|
- lib
|
|
@@ -235,8 +364,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
235
364
|
- !ruby/object:Gem::Version
|
|
236
365
|
version: '0'
|
|
237
366
|
requirements: []
|
|
238
|
-
rubygems_version:
|
|
239
|
-
signing_key:
|
|
367
|
+
rubygems_version: 4.0.3
|
|
240
368
|
specification_version: 4
|
|
241
369
|
summary: Structured JSON logging for Rails/ActiveSupport with safe, single-line entries.
|
|
242
370
|
test_files: []
|