fluentd-json-size-limit 0.1.4 → 0.2.0
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 +24 -0
- data/LICENSE +16 -202
- data/NOTICE.md +3 -0
- data/README.md +61 -26
- data/fluentd-json-size-limit.gemspec +37 -20
- data/lib/fluent/plugin/filter_jsonsizelimit.rb +4 -67
- data/lib/fluent/plugin/json_size_limit/errors.rb +53 -0
- data/lib/fluent/plugin/json_size_limit/filter.rb +154 -0
- data/lib/fluent/plugin/json_size_limit/filter_configuration.rb +48 -0
- data/lib/fluent/plugin/json_size_limit/json_string.rb +169 -0
- data/lib/fluent/plugin/json_size_limit/processing_guard.rb +77 -0
- data/lib/fluent/plugin/json_size_limit/rate_limited_logger.rb +76 -0
- data/lib/fluent/plugin/json_size_limit/record_measurer.rb +133 -0
- data/lib/fluent/plugin/json_size_limit/record_processor.rb +52 -0
- data/lib/fluent/plugin/json_size_limit/record_reducer.rb +258 -0
- data/lib/fluent/plugin/json_size_limit/string_encoding.rb +25 -0
- data/lib/fluent/plugin/json_size_limit/telemetry.rb +60 -0
- data/lib/fluent/plugin/json_size_limit/version.rb +9 -0
- data/lib/fluent/plugin/json_size_limit.rb +15 -0
- metadata +143 -38
- data/.gitignore +0 -2
- data/.gitlab-ci.yml +0 -171
- data/Gemfile +0 -3
- data/Gemfile.lock +0 -51
- data/Rakefile +0 -13
- data/test/helper.rb +0 -7
- data/test/plugin/test_fluentd-json-size-limit.rb +0 -43
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fluent/plugin/json_size_limit/processing_guard"
|
|
4
|
+
require "fluent/plugin/json_size_limit/record_measurer"
|
|
5
|
+
require "fluent/plugin/json_size_limit/record_reducer"
|
|
6
|
+
|
|
7
|
+
module Fluent
|
|
8
|
+
module Plugin
|
|
9
|
+
module JsonSizeLimit
|
|
10
|
+
class RecordProcessor
|
|
11
|
+
Result = Struct.new(:status, :original_json_bytes, :json_bytes)
|
|
12
|
+
|
|
13
|
+
def initialize(max_json_bytes:, safety_options:, clock: ProcessingGuard::MONOTONIC_TIME)
|
|
14
|
+
@max_json_bytes = max_json_bytes
|
|
15
|
+
@safety_options = safety_options
|
|
16
|
+
@clock = clock
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(record)
|
|
20
|
+
guard = ProcessingGuard.new(**@safety_options, clock: @clock)
|
|
21
|
+
original_json_bytes = RecordMeasurer.new(guard).measure(record)
|
|
22
|
+
|
|
23
|
+
if original_json_bytes <= @max_json_bytes
|
|
24
|
+
return Result.new(
|
|
25
|
+
status: :within_limit,
|
|
26
|
+
original_json_bytes: original_json_bytes,
|
|
27
|
+
json_bytes: original_json_bytes
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Node and input counters are phase-local, while the absolute
|
|
32
|
+
# deadline remains shared by measurement and reduction.
|
|
33
|
+
guard.reset_phase!(track_input: false)
|
|
34
|
+
reduced_json_bytes = RecordReducer.new(
|
|
35
|
+
record,
|
|
36
|
+
original_json_bytes: original_json_bytes,
|
|
37
|
+
max_json_bytes: @max_json_bytes,
|
|
38
|
+
guard: guard,
|
|
39
|
+
validated_record: true
|
|
40
|
+
).reduce_to_limit
|
|
41
|
+
guard.checkpoint!
|
|
42
|
+
|
|
43
|
+
Result.new(
|
|
44
|
+
status: (reduced_json_bytes <= @max_json_bytes) ? :reduced : :overflow,
|
|
45
|
+
original_json_bytes: original_json_bytes,
|
|
46
|
+
json_bytes: reduced_json_bytes
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fluent/plugin/json_size_limit/json_string"
|
|
4
|
+
require "fluent/plugin/json_size_limit/processing_guard"
|
|
5
|
+
|
|
6
|
+
module Fluent
|
|
7
|
+
module Plugin
|
|
8
|
+
module JsonSizeLimit
|
|
9
|
+
# Reduces string values proportionally while preserving record shape,
|
|
10
|
+
# aliases, key names, encodings, and non-string values.
|
|
11
|
+
class RecordReducer
|
|
12
|
+
HASH_EACH_PAIR = Hash.instance_method(:each_pair)
|
|
13
|
+
ARRAY_EACH_WITH_INDEX = Array.instance_method(:each_with_index)
|
|
14
|
+
HASH_SET = Hash.instance_method(:[]=)
|
|
15
|
+
ARRAY_SET = Array.instance_method(:[]=)
|
|
16
|
+
|
|
17
|
+
class StringLocation < JsonString
|
|
18
|
+
attr_reader :container, :key, :original_value
|
|
19
|
+
attr_accessor :occurrences, :replacement_value, :replacement_content_bytes
|
|
20
|
+
|
|
21
|
+
def initialize(container, key, value, encoding_validated: false)
|
|
22
|
+
super(value, validate_encoding: !encoding_validated)
|
|
23
|
+
@container = container
|
|
24
|
+
@key = key
|
|
25
|
+
@original_value = value
|
|
26
|
+
@occurrences = 1
|
|
27
|
+
@replacement_value = value
|
|
28
|
+
@replacement_content_bytes = content_bytes
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def truncate_to(content_budget)
|
|
32
|
+
@replacement_value = truncate(content_budget)
|
|
33
|
+
@replacement_content_bytes = truncated_content_bytes
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def initialize(record, original_json_bytes:, max_json_bytes:, guard: nil, validated_record: false)
|
|
38
|
+
@record = record
|
|
39
|
+
@original_json_bytes = original_json_bytes
|
|
40
|
+
@max_json_bytes = max_json_bytes
|
|
41
|
+
@guard = guard || ProcessingGuard.new(
|
|
42
|
+
timeout: 5,
|
|
43
|
+
max_nodes: 1_000_000,
|
|
44
|
+
max_input_bytes: Float::INFINITY,
|
|
45
|
+
max_nesting: 100
|
|
46
|
+
)
|
|
47
|
+
@validated_record = validated_record
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def reduce_to_limit
|
|
51
|
+
locations, original_content_bytes = collect_string_locations
|
|
52
|
+
return @original_json_bytes if locations.empty?
|
|
53
|
+
|
|
54
|
+
immutable_json_bytes = @original_json_bytes - original_content_bytes
|
|
55
|
+
content_budget = @max_json_bytes - immutable_json_bytes
|
|
56
|
+
@guard.reset_phase!(track_input: false)
|
|
57
|
+
replacements, current_content_bytes = build_replacements(locations, content_budget, original_content_bytes)
|
|
58
|
+
|
|
59
|
+
@guard.reset_phase!(track_input: false)
|
|
60
|
+
apply_replacements(replacements)
|
|
61
|
+
immutable_json_bytes + current_content_bytes
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# JSON serializes aliases once per occurrence. The common tree path
|
|
67
|
+
# avoids a per-field index; alias accounting is activated only when a
|
|
68
|
+
# shared Hash or Array identity is observed.
|
|
69
|
+
def collect_string_locations
|
|
70
|
+
collect_tree_string_locations || begin
|
|
71
|
+
@guard.reset_phase!(track_input: false)
|
|
72
|
+
collect_aliased_string_locations
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def collect_tree_string_locations
|
|
77
|
+
locations = []
|
|
78
|
+
seen_containers = {}.compare_by_identity
|
|
79
|
+
total_content_bytes = 0
|
|
80
|
+
containers_to_scan = [[@record, 0]]
|
|
81
|
+
@scan_operations = 0
|
|
82
|
+
|
|
83
|
+
until containers_to_scan.empty?
|
|
84
|
+
container, depth = containers_to_scan.pop
|
|
85
|
+
scan_visit!(depth)
|
|
86
|
+
return nil if seen_containers.key?(container)
|
|
87
|
+
|
|
88
|
+
seen_containers[container] = true
|
|
89
|
+
|
|
90
|
+
each_container_value(container) do |key, value|
|
|
91
|
+
if value.instance_of?(String) && !value.empty?
|
|
92
|
+
location = StringLocation.new(container, key, value, encoding_validated: @validated_record)
|
|
93
|
+
locations << location
|
|
94
|
+
total_content_bytes += location.content_bytes
|
|
95
|
+
scan_visit!(depth + 1)
|
|
96
|
+
elsif value.instance_of?(Hash) || value.instance_of?(Array)
|
|
97
|
+
containers_to_scan << [value, depth + 1]
|
|
98
|
+
else
|
|
99
|
+
scan_visit!(depth + 1)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
[locations, total_content_bytes]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def collect_aliased_string_locations
|
|
108
|
+
locations = []
|
|
109
|
+
locations_by_container = {}.compare_by_identity
|
|
110
|
+
total_content_bytes = 0
|
|
111
|
+
containers_to_scan = [[@record, 0]]
|
|
112
|
+
@scan_operations = 0
|
|
113
|
+
|
|
114
|
+
until containers_to_scan.empty?
|
|
115
|
+
container, depth = containers_to_scan.pop
|
|
116
|
+
scan_visit!(depth)
|
|
117
|
+
location_indexes = locations_by_container[container] ||= {}
|
|
118
|
+
|
|
119
|
+
each_container_value(container) do |key, value|
|
|
120
|
+
if value.instance_of?(String) && !value.empty?
|
|
121
|
+
location = location_indexes[key]
|
|
122
|
+
|
|
123
|
+
if location
|
|
124
|
+
location.occurrences += 1
|
|
125
|
+
else
|
|
126
|
+
location = StringLocation.new(container, key, value, encoding_validated: @validated_record)
|
|
127
|
+
location_indexes[key] = location
|
|
128
|
+
locations << location
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
total_content_bytes += location.content_bytes
|
|
132
|
+
scan_visit!(depth + 1)
|
|
133
|
+
elsif value.instance_of?(Hash) || value.instance_of?(Array)
|
|
134
|
+
containers_to_scan << [value, depth + 1]
|
|
135
|
+
else
|
|
136
|
+
scan_visit!(depth + 1)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
[locations, total_content_bytes]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def each_container_value(container, &block)
|
|
145
|
+
if container.instance_of?(Hash)
|
|
146
|
+
HASH_EACH_PAIR.bind_call(container, &block)
|
|
147
|
+
else
|
|
148
|
+
ARRAY_EACH_WITH_INDEX.bind_call(container) { |value, index| block.call(index, value) }
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def scan_visit!(depth)
|
|
153
|
+
unless @validated_record
|
|
154
|
+
@guard.visit!(depth)
|
|
155
|
+
return
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
@scan_operations += 1
|
|
159
|
+
@guard.checkpoint! if (@scan_operations & 255).zero?
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def build_replacements(locations, content_budget, original_content_bytes)
|
|
163
|
+
remaining_budget = [content_budget, 0].max
|
|
164
|
+
remaining_original = original_content_bytes
|
|
165
|
+
current_content_bytes = 0
|
|
166
|
+
|
|
167
|
+
locations.each_with_index do |location, index|
|
|
168
|
+
@guard.checkpoint! if (index & 255).zero?
|
|
169
|
+
weighted_original = location.content_bytes * location.occurrences
|
|
170
|
+
weighted_target = remaining_budget.positive? ? remaining_budget * weighted_original / remaining_original : 0
|
|
171
|
+
target_per_occurrence = weighted_target / location.occurrences
|
|
172
|
+
|
|
173
|
+
location.truncate_to(target_per_occurrence)
|
|
174
|
+
@guard.checkpoint! if location.content_bytes >= 64 * 1024
|
|
175
|
+
weighted_replacement = location.replacement_content_bytes * location.occurrences
|
|
176
|
+
|
|
177
|
+
current_content_bytes += weighted_replacement
|
|
178
|
+
remaining_budget -= weighted_replacement
|
|
179
|
+
remaining_original -= weighted_original
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
@guard.reset_phase!(track_input: false)
|
|
183
|
+
current_content_bytes += distribute_remaining_budget(locations, remaining_budget)
|
|
184
|
+
@guard.reset_phase!(track_input: false)
|
|
185
|
+
replacements = build_replacement_list(locations)
|
|
186
|
+
|
|
187
|
+
[replacements, current_content_bytes]
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def distribute_remaining_budget(locations, remaining_budget)
|
|
191
|
+
added_content_bytes = 0
|
|
192
|
+
|
|
193
|
+
locations.each_with_index do |location, index|
|
|
194
|
+
@guard.checkpoint! if (index & 255).zero?
|
|
195
|
+
break unless remaining_budget.positive?
|
|
196
|
+
next if location.replacement_content_bytes >= location.content_bytes
|
|
197
|
+
|
|
198
|
+
additional_per_occurrence = remaining_budget / location.occurrences
|
|
199
|
+
next unless additional_per_occurrence.positive?
|
|
200
|
+
|
|
201
|
+
previous_replacement_bytes = location.replacement_content_bytes
|
|
202
|
+
location.truncate_to(previous_replacement_bytes + additional_per_occurrence)
|
|
203
|
+
@guard.checkpoint! if location.content_bytes >= 64 * 1024
|
|
204
|
+
replacement_bytes = location.replacement_content_bytes
|
|
205
|
+
weighted_addition = (replacement_bytes - previous_replacement_bytes) * location.occurrences
|
|
206
|
+
remaining_budget -= weighted_addition
|
|
207
|
+
added_content_bytes += weighted_addition
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
added_content_bytes
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def build_replacement_list(locations)
|
|
214
|
+
# A flat tuple buffer avoids allocating one small Array per changed
|
|
215
|
+
# field on records with many strings.
|
|
216
|
+
replacements = []
|
|
217
|
+
index = 0
|
|
218
|
+
|
|
219
|
+
locations.each do |location|
|
|
220
|
+
@guard.checkpoint! if (index & 255).zero?
|
|
221
|
+
unless location.replacement_value.equal?(location.original_value)
|
|
222
|
+
replacements << location.container << location.key << location.original_value << location.replacement_value
|
|
223
|
+
end
|
|
224
|
+
index += 1
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
replacements
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def apply_replacements(replacements)
|
|
231
|
+
applied = 0
|
|
232
|
+
|
|
233
|
+
while applied < replacements.length
|
|
234
|
+
@guard.checkpoint! if (applied & 1023).zero?
|
|
235
|
+
set_container_value(replacements[applied], replacements[applied + 1], replacements[applied + 3])
|
|
236
|
+
applied += 4
|
|
237
|
+
end
|
|
238
|
+
rescue
|
|
239
|
+
rollback_replacements(replacements, applied)
|
|
240
|
+
raise
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def rollback_replacements(replacements, applied)
|
|
244
|
+
index = 0
|
|
245
|
+
while index < applied
|
|
246
|
+
set_container_value(replacements[index], replacements[index + 1], replacements[index + 2])
|
|
247
|
+
index += 4
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def set_container_value(container, key, value)
|
|
252
|
+
method = container.instance_of?(Hash) ? HASH_SET : ARRAY_SET
|
|
253
|
+
method.bind_call(container, key, value)
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fluent/plugin/json_size_limit/errors"
|
|
4
|
+
|
|
5
|
+
module Fluent
|
|
6
|
+
module Plugin
|
|
7
|
+
module JsonSizeLimit
|
|
8
|
+
module StringEncoding
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def validate!(value)
|
|
12
|
+
unless value.valid_encoding?
|
|
13
|
+
raise InvalidStringEncodingError, value.encoding.name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Binary bytes have no character boundaries, so truncating them could
|
|
17
|
+
# silently change payload semantics. ASCII-only binary strings are safe.
|
|
18
|
+
if value.encoding == Encoding::ASCII_8BIT && !value.ascii_only?
|
|
19
|
+
raise InvalidStringEncodingError, value.encoding.name
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fluent/plugin/json_size_limit/errors"
|
|
4
|
+
|
|
5
|
+
module Fluent
|
|
6
|
+
module Plugin
|
|
7
|
+
module JsonSizeLimit
|
|
8
|
+
class Telemetry
|
|
9
|
+
DEFINITIONS = {
|
|
10
|
+
oversized_records: "Number of records exceeding max_size",
|
|
11
|
+
reduced_records: "Number of oversized records reduced to max_size",
|
|
12
|
+
unreducible_records: "Number of records whose immutable JSON exceeds max_size",
|
|
13
|
+
error_records: "Number of records that failed measurement or reduction",
|
|
14
|
+
dropped_records: "Number of records dropped by configured actions",
|
|
15
|
+
processing_limit_records: "Number of records stopped by automatic safety limits",
|
|
16
|
+
unsupported_records: "Number of records containing unsupported Ruby value classes",
|
|
17
|
+
removed_bytes: "Total JSON bytes removed from oversized records"
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
20
|
+
def initialize(&metric_factory)
|
|
21
|
+
raise ArgumentError, "metric factory block is required" unless metric_factory
|
|
22
|
+
|
|
23
|
+
@metrics = DEFINITIONS.to_h do |name, help_text|
|
|
24
|
+
metric = metric_factory.call(name.to_s, help_text)
|
|
25
|
+
validate_metric!(name, metric)
|
|
26
|
+
[name, metric]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def increment(name, amount = 1)
|
|
31
|
+
unless amount.is_a?(Integer) && amount.positive?
|
|
32
|
+
raise ArgumentError, "metric increment must be a positive integer"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
metric = @metrics.fetch(name)
|
|
36
|
+
(amount == 1) ? metric.inc : metric.add(amount)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def record_error(error)
|
|
40
|
+
increment(:error_records)
|
|
41
|
+
increment(:processing_limit_records) if error.is_a?(ProcessingLimitError) || error.is_a?(CyclicRecordError)
|
|
42
|
+
increment(:unsupported_records) if error.is_a?(UnsupportedRecordError)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def statistics
|
|
46
|
+
@metrics.transform_keys(&:to_s).transform_values(&:get)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def validate_metric!(name, metric)
|
|
52
|
+
missing_methods = %i[inc add get].reject { |method_name| metric.respond_to?(method_name) }
|
|
53
|
+
return if missing_methods.empty?
|
|
54
|
+
|
|
55
|
+
raise ArgumentError, "metric #{name} must respond to #{missing_methods.map { |name| "##{name}" }.join(", ")}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Internal component bundle. Fluentd registration remains in the stable
|
|
4
|
+
# filter_jsonsizelimit discovery entry point to avoid a circular require.
|
|
5
|
+
require "fluent/plugin/json_size_limit/version"
|
|
6
|
+
require "fluent/plugin/json_size_limit/errors"
|
|
7
|
+
require "fluent/plugin/json_size_limit/string_encoding"
|
|
8
|
+
require "fluent/plugin/json_size_limit/json_string"
|
|
9
|
+
require "fluent/plugin/json_size_limit/rate_limited_logger"
|
|
10
|
+
require "fluent/plugin/json_size_limit/processing_guard"
|
|
11
|
+
require "fluent/plugin/json_size_limit/record_measurer"
|
|
12
|
+
require "fluent/plugin/json_size_limit/record_reducer"
|
|
13
|
+
require "fluent/plugin/json_size_limit/record_processor"
|
|
14
|
+
require "fluent/plugin/json_size_limit/filter_configuration"
|
|
15
|
+
require "fluent/plugin/json_size_limit/telemetry"
|
metadata
CHANGED
|
@@ -1,64 +1,141 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fluentd-json-size-limit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- CreatorIQ
|
|
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: bundler
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '2.6'
|
|
19
|
+
- - "<"
|
|
18
20
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
21
|
+
version: '5'
|
|
20
22
|
type: :development
|
|
21
23
|
prerelease: false
|
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
25
|
requirements:
|
|
24
|
-
- - "
|
|
26
|
+
- - ">="
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '2.6'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '5'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: benchmark
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0.4'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '1'
|
|
42
|
+
type: :development
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0.4'
|
|
49
|
+
- - "<"
|
|
25
50
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
51
|
+
version: '1'
|
|
27
52
|
- !ruby/object:Gem::Dependency
|
|
28
53
|
name: rake
|
|
29
54
|
requirement: !ruby/object:Gem::Requirement
|
|
30
55
|
requirements:
|
|
31
|
-
- - "
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '13.2'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '14'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '13.2'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '14'
|
|
72
|
+
- !ruby/object:Gem::Dependency
|
|
73
|
+
name: simplecov
|
|
74
|
+
requirement: !ruby/object:Gem::Requirement
|
|
75
|
+
requirements:
|
|
76
|
+
- - ">="
|
|
77
|
+
- !ruby/object:Gem::Version
|
|
78
|
+
version: '1.0'
|
|
79
|
+
- - "<"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '2'
|
|
82
|
+
type: :development
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '1.0'
|
|
89
|
+
- - "<"
|
|
90
|
+
- !ruby/object:Gem::Version
|
|
91
|
+
version: '2'
|
|
92
|
+
- !ruby/object:Gem::Dependency
|
|
93
|
+
name: standard
|
|
94
|
+
requirement: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '1.56'
|
|
99
|
+
- - "<"
|
|
32
100
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
101
|
+
version: '2'
|
|
34
102
|
type: :development
|
|
35
103
|
prerelease: false
|
|
36
104
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
105
|
requirements:
|
|
38
|
-
- - "
|
|
106
|
+
- - ">="
|
|
39
107
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
108
|
+
version: '1.56'
|
|
109
|
+
- - "<"
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '2'
|
|
41
112
|
- !ruby/object:Gem::Dependency
|
|
42
113
|
name: test-unit
|
|
43
114
|
requirement: !ruby/object:Gem::Requirement
|
|
44
115
|
requirements:
|
|
45
|
-
- - "
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: '3.6'
|
|
119
|
+
- - "<"
|
|
46
120
|
- !ruby/object:Gem::Version
|
|
47
|
-
version:
|
|
121
|
+
version: '4'
|
|
48
122
|
type: :development
|
|
49
123
|
prerelease: false
|
|
50
124
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
125
|
requirements:
|
|
52
|
-
- - "
|
|
126
|
+
- - ">="
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '3.6'
|
|
129
|
+
- - "<"
|
|
53
130
|
- !ruby/object:Gem::Version
|
|
54
|
-
version:
|
|
131
|
+
version: '4'
|
|
55
132
|
- !ruby/object:Gem::Dependency
|
|
56
133
|
name: fluentd
|
|
57
134
|
requirement: !ruby/object:Gem::Requirement
|
|
58
135
|
requirements:
|
|
59
136
|
- - ">="
|
|
60
137
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
138
|
+
version: 1.16.11
|
|
62
139
|
- - "<"
|
|
63
140
|
- !ruby/object:Gem::Version
|
|
64
141
|
version: '2'
|
|
@@ -68,35 +145,63 @@ dependencies:
|
|
|
68
145
|
requirements:
|
|
69
146
|
- - ">="
|
|
70
147
|
- !ruby/object:Gem::Version
|
|
71
|
-
version:
|
|
148
|
+
version: 1.16.11
|
|
72
149
|
- - "<"
|
|
73
150
|
- !ruby/object:Gem::Version
|
|
74
151
|
version: '2'
|
|
75
|
-
|
|
76
|
-
|
|
152
|
+
- !ruby/object:Gem::Dependency
|
|
153
|
+
name: json
|
|
154
|
+
requirement: !ruby/object:Gem::Requirement
|
|
155
|
+
requirements:
|
|
156
|
+
- - ">="
|
|
157
|
+
- !ruby/object:Gem::Version
|
|
158
|
+
version: 2.19.2
|
|
159
|
+
- - "<"
|
|
160
|
+
- !ruby/object:Gem::Version
|
|
161
|
+
version: '3'
|
|
162
|
+
type: :runtime
|
|
163
|
+
prerelease: false
|
|
164
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
165
|
+
requirements:
|
|
166
|
+
- - ">="
|
|
167
|
+
- !ruby/object:Gem::Version
|
|
168
|
+
version: 2.19.2
|
|
169
|
+
- - "<"
|
|
170
|
+
- !ruby/object:Gem::Version
|
|
171
|
+
version: '3'
|
|
172
|
+
description: Reduces oversized Fluentd JSON records by safely and proportionally truncating
|
|
173
|
+
nested string values.
|
|
77
174
|
email:
|
|
78
|
-
-
|
|
175
|
+
- subscription-rubygems@creatoriq.com
|
|
79
176
|
executables: []
|
|
80
177
|
extensions: []
|
|
81
178
|
extra_rdoc_files: []
|
|
82
179
|
files:
|
|
83
|
-
-
|
|
84
|
-
- ".gitlab-ci.yml"
|
|
85
|
-
- Gemfile
|
|
86
|
-
- Gemfile.lock
|
|
180
|
+
- CHANGELOG.md
|
|
87
181
|
- LICENSE
|
|
182
|
+
- NOTICE.md
|
|
88
183
|
- README.md
|
|
89
|
-
- Rakefile
|
|
90
184
|
- fluentd-json-size-limit.gemspec
|
|
91
185
|
- lib/fluent/plugin/filter_jsonsizelimit.rb
|
|
92
|
-
-
|
|
93
|
-
-
|
|
94
|
-
|
|
186
|
+
- lib/fluent/plugin/json_size_limit.rb
|
|
187
|
+
- lib/fluent/plugin/json_size_limit/errors.rb
|
|
188
|
+
- lib/fluent/plugin/json_size_limit/filter.rb
|
|
189
|
+
- lib/fluent/plugin/json_size_limit/filter_configuration.rb
|
|
190
|
+
- lib/fluent/plugin/json_size_limit/json_string.rb
|
|
191
|
+
- lib/fluent/plugin/json_size_limit/processing_guard.rb
|
|
192
|
+
- lib/fluent/plugin/json_size_limit/rate_limited_logger.rb
|
|
193
|
+
- lib/fluent/plugin/json_size_limit/record_measurer.rb
|
|
194
|
+
- lib/fluent/plugin/json_size_limit/record_processor.rb
|
|
195
|
+
- lib/fluent/plugin/json_size_limit/record_reducer.rb
|
|
196
|
+
- lib/fluent/plugin/json_size_limit/string_encoding.rb
|
|
197
|
+
- lib/fluent/plugin/json_size_limit/telemetry.rb
|
|
198
|
+
- lib/fluent/plugin/json_size_limit/version.rb
|
|
199
|
+
homepage: https://creatoriq.com
|
|
95
200
|
licenses:
|
|
96
|
-
- Copyright 2017 -
|
|
201
|
+
- Copyright 2017 - 2026 SocialEdge, Inc., dba CreatorIQ.
|
|
97
202
|
- Nonstandard
|
|
98
|
-
metadata:
|
|
99
|
-
|
|
203
|
+
metadata:
|
|
204
|
+
allowed_push_host: https://rubygems.org
|
|
100
205
|
rdoc_options: []
|
|
101
206
|
require_paths:
|
|
102
207
|
- lib
|
|
@@ -104,17 +209,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
104
209
|
requirements:
|
|
105
210
|
- - ">="
|
|
106
211
|
- !ruby/object:Gem::Version
|
|
107
|
-
version: '
|
|
212
|
+
version: '3.3'
|
|
213
|
+
- - "<"
|
|
214
|
+
- !ruby/object:Gem::Version
|
|
215
|
+
version: '5'
|
|
108
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
217
|
requirements:
|
|
110
218
|
- - ">="
|
|
111
219
|
- !ruby/object:Gem::Version
|
|
112
220
|
version: '0'
|
|
113
221
|
requirements: []
|
|
114
|
-
rubygems_version:
|
|
115
|
-
signing_key:
|
|
222
|
+
rubygems_version: 4.0.16
|
|
116
223
|
specification_version: 4
|
|
117
|
-
summary: Fluentd
|
|
118
|
-
test_files:
|
|
119
|
-
- test/helper.rb
|
|
120
|
-
- test/plugin/test_fluentd-json-size-limit.rb
|
|
224
|
+
summary: Fluentd filter that enforces a maximum JSON record size
|
|
225
|
+
test_files: []
|
data/.gitignore
DELETED