fluentd 1.19.1 → 1.19.3
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 +60 -0
- data/Rakefile +7 -0
- data/lib/fluent/command/fluentd.rb +1 -0
- data/lib/fluent/config/v1_parser.rb +13 -5
- data/lib/fluent/config/yaml_parser/loader.rb +7 -2
- data/lib/fluent/config/yaml_parser.rb +2 -2
- data/lib/fluent/config.rb +5 -5
- data/lib/fluent/engine.rb +1 -1
- data/lib/fluent/event.rb +2 -1
- data/lib/fluent/plugin/buf_file.rb +3 -3
- data/lib/fluent/plugin/buf_file_single.rb +2 -2
- data/lib/fluent/plugin/buf_memory.rb +1 -1
- data/lib/fluent/plugin/buffer/chunk.rb +2 -1
- data/lib/fluent/plugin/buffer/file_chunk.rb +2 -2
- data/lib/fluent/plugin/buffer/file_single_chunk.rb +2 -2
- data/lib/fluent/plugin/buffer/memory_chunk.rb +1 -1
- data/lib/fluent/plugin/buffer.rb +3 -0
- data/lib/fluent/plugin/compressable.rb +7 -62
- data/lib/fluent/plugin/extractor.rb +121 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +1 -1
- data/lib/fluent/plugin/in_debug_agent.rb +1 -1
- data/lib/fluent/plugin/in_forward.rb +3 -1
- data/lib/fluent/plugin/in_http.rb +8 -4
- data/lib/fluent/plugin/in_monitor_agent.rb +19 -22
- data/lib/fluent/plugin/in_tail.rb +1 -1
- data/lib/fluent/plugin/out_file.rb +10 -0
- data/lib/fluent/plugin/out_forward/socket_cache.rb +45 -10
- data/lib/fluent/plugin/out_forward.rb +10 -0
- data/lib/fluent/plugin/out_http.rb +31 -1
- data/lib/fluent/plugin/output.rb +45 -1
- data/lib/fluent/plugin/parser_csv.rb +5 -0
- data/lib/fluent/plugin/storage_local.rb +2 -2
- data/lib/fluent/plugin_helper/http_server/app.rb +2 -0
- data/lib/fluent/supervisor.rb +30 -4
- data/lib/fluent/test/base.rb +5 -0
- data/lib/fluent/version.rb +1 -1
- metadata +34 -9
- data/.deepsource.toml +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9613f1dacdb60cfccb245e988e67cec002daee2f81cbe38c2b80c30d525ad7b8
|
|
4
|
+
data.tar.gz: 4a85aa6c3bdaebd9cd069d508ac969d8792586247bef1d73d25cc906f6cd7c87
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c2d63e0bd8cf51a61d254cfda559f38ed1bcc79ceb1bf1f0d0c80b21b922e67091d2ee8c291a0dc0fcac0110873d0045874df297e0795c0cd604af64f431f845
|
|
7
|
+
data.tar.gz: 5fe9e2450048bacc978389621b0e3f2c8aed0e9136ffe11192945a754173c1ce13ff50c310cfcdf1633d7dc784e14e9a4fc5a6de519da3bc81decb12f6d5b28d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,65 @@
|
|
|
1
1
|
# v1.19
|
|
2
2
|
|
|
3
|
+
## Release v1.19.3 - 2026/06/25
|
|
4
|
+
|
|
5
|
+
### Bug Fix
|
|
6
|
+
|
|
7
|
+
* out_http: add strict host validation for dynamic endpoints https://github.com/fluent/fluentd/pull/5394
|
|
8
|
+
* buffer, in_http: enforce size limits on decompressed payloads https://github.com/fluent/fluentd/pull/5393
|
|
9
|
+
* in_monitor_agent: change default visibility of config, retry, and debug info https://github.com/fluent/fluentd/pull/5392
|
|
10
|
+
* output: enforce strict path boundary validation for tag https://github.com/fluent/fluentd/pull/5391
|
|
11
|
+
* engine: remove duplicated word in unreloadable plugin error message https://github.com/fluent/fluentd/pull/5389
|
|
12
|
+
* storage_local: fix encoding error when reading non-ASCII characters https://github.com/fluent/fluentd/pull/5382
|
|
13
|
+
* parser_csv: skip empty or unparseable lines https://github.com/fluent/fluentd/pull/5359
|
|
14
|
+
* out_forward: avoid reusing closed keepalive sockets after remote disconnects https://github.com/fluent/fluentd/pull/5343
|
|
15
|
+
* buffer: resume buffer correctly even though path contains [] https://github.com/fluent/fluentd/pull/5305
|
|
16
|
+
* in_debug_agent: accept only from local machine by default https://github.com/fluent/fluentd/pull/5279
|
|
17
|
+
|
|
18
|
+
### Misc
|
|
19
|
+
|
|
20
|
+
* gem: add win32-registry as runtime dependency for Ruby 4.1 https://github.com/fluent/fluentd/pull/5317
|
|
21
|
+
* output windows: check shorter service timeout on shutdown https://github.com/fluent/fluentd/pull/5306
|
|
22
|
+
* buffer: warn if default timekey (1d) will be used https://github.com/fluent/fluentd/pull/5291
|
|
23
|
+
* warn recommended exclusion path for antivirus https://github.com/fluent/fluentd/pull/5280
|
|
24
|
+
* CI fixes
|
|
25
|
+
* https://github.com/fluent/fluentd/pull/5387
|
|
26
|
+
* https://github.com/fluent/fluentd/pull/5386
|
|
27
|
+
* https://github.com/fluent/fluentd/pull/5366
|
|
28
|
+
* https://github.com/fluent/fluentd/pull/5342
|
|
29
|
+
* https://github.com/fluent/fluentd/pull/5341
|
|
30
|
+
* https://github.com/fluent/fluentd/pull/5340
|
|
31
|
+
* https://github.com/fluent/fluentd/pull/5339
|
|
32
|
+
* https://github.com/fluent/fluentd/pull/5338
|
|
33
|
+
* https://github.com/fluent/fluentd/pull/5337
|
|
34
|
+
* https://github.com/fluent/fluentd/pull/5336
|
|
35
|
+
* https://github.com/fluent/fluentd/pull/5335
|
|
36
|
+
* https://github.com/fluent/fluentd/pull/5334
|
|
37
|
+
* https://github.com/fluent/fluentd/pull/5333
|
|
38
|
+
|
|
39
|
+
## Release v1.19.2 - 2026/02/13
|
|
40
|
+
|
|
41
|
+
### Bug Fix
|
|
42
|
+
|
|
43
|
+
* out_forward: add timeout to establish_connection to prevent infinite loop https://github.com/fluent/fluentd/pull/5138
|
|
44
|
+
* gem: use latest net-http to solve IPv6 addr error https://github.com/fluent/fluentd/pull/5192
|
|
45
|
+
* in_tail: fix error when files without read permission are included in glob patterns https://github.com/fluent/fluentd/pull/5222
|
|
46
|
+
* command/fluentd: load win32/registry when edit registry for Ruby 4.0 https://github.com/fluent/fluentd/pull/5221
|
|
47
|
+
* plugin_helper/http_server: Ensure request body is closed to prevent socket leaks in POST requests https://github.com/fluent/fluentd/pull/5234
|
|
48
|
+
* config: fix duplicate config file loading in config_include_dir https://github.com/fluent/fluentd/pull/5235
|
|
49
|
+
* gem: add ostruct gem as dependency for Ruby 4.0 https://github.com/fluent/fluentd/pull/5251
|
|
50
|
+
|
|
51
|
+
### Misc
|
|
52
|
+
|
|
53
|
+
* config: warn when backed-up config file will be included https://github.com/fluent/fluentd/pull/5252
|
|
54
|
+
* filter_record_transformer: use cgi/escape to avoid Ruby 4.0 deprecation https://github.com/fluent/fluentd/pull/5256
|
|
55
|
+
* CI fixes
|
|
56
|
+
* https://github.com/fluent/fluentd/pull/5257
|
|
57
|
+
* https://github.com/fluent/fluentd/pull/5229
|
|
58
|
+
* https://github.com/fluent/fluentd/pull/5225
|
|
59
|
+
* https://github.com/fluent/fluentd/pull/5186
|
|
60
|
+
* https://github.com/fluent/fluentd/pull/5184
|
|
61
|
+
* https://github.com/fluent/fluentd/pull/5176
|
|
62
|
+
|
|
3
63
|
## Release v1.19.1 - 2025/11/06
|
|
4
64
|
|
|
5
65
|
### Bug Fix
|
data/Rakefile
CHANGED
|
@@ -78,4 +78,11 @@ task :coverity do
|
|
|
78
78
|
FileUtils.rm_rf(['./cov-int', 'cov-fluentd.tar.gz'])
|
|
79
79
|
end
|
|
80
80
|
|
|
81
|
+
task :check_env do
|
|
82
|
+
unless ENV['GEM_HOST_API_KEY']
|
|
83
|
+
abort "Missing required environment variable: GEM_HOST_API_KEY\nSee https://guides.rubygems.org/api-key-scopes/"
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
Rake::Task["release:rubygem_push"].enhance(["check_env"])
|
|
87
|
+
|
|
81
88
|
task default: [:test, :build]
|
|
@@ -344,6 +344,7 @@ if winsvcinstmode = opts[:regwinsvc]
|
|
|
344
344
|
end
|
|
345
345
|
|
|
346
346
|
if fluentdopt = opts[:fluentdopt]
|
|
347
|
+
require "win32/registry"
|
|
347
348
|
Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Services\\#{opts[:winsvc_name]}", Win32::Registry::KEY_ALL_ACCESS) do |reg|
|
|
348
349
|
reg['fluentdopt', Win32::Registry::REG_SZ] = fluentdopt
|
|
349
350
|
end
|
|
@@ -27,17 +27,18 @@ module Fluent
|
|
|
27
27
|
class V1Parser < LiteralParser
|
|
28
28
|
ELEMENT_NAME = /[a-zA-Z0-9_]+/
|
|
29
29
|
|
|
30
|
-
def self.parse(data, fname, basepath = Dir.pwd, eval_context = nil)
|
|
30
|
+
def self.parse(data, fname, basepath = Dir.pwd, eval_context = nil, on_file_parsed: nil)
|
|
31
31
|
ss = StringScanner.new(data)
|
|
32
|
-
ps = V1Parser.new(ss, basepath, fname, eval_context)
|
|
32
|
+
ps = V1Parser.new(ss, basepath, fname, eval_context, on_file_parsed: on_file_parsed)
|
|
33
33
|
ps.parse!
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
def initialize(strscan, include_basepath, fname, eval_context)
|
|
36
|
+
def initialize(strscan, include_basepath, fname, eval_context, on_file_parsed: nil)
|
|
37
37
|
super(strscan, eval_context)
|
|
38
38
|
@include_basepath = include_basepath
|
|
39
39
|
@fname = fname
|
|
40
40
|
@logger = defined?($log) ? $log : nil
|
|
41
|
+
@on_file_parsed = on_file_parsed
|
|
41
42
|
end
|
|
42
43
|
|
|
43
44
|
def parse!
|
|
@@ -138,6 +139,8 @@ module Fluent
|
|
|
138
139
|
end
|
|
139
140
|
end
|
|
140
141
|
|
|
142
|
+
@on_file_parsed&.call(File.expand_path(File.join(@include_basepath, @fname))) if root_element
|
|
143
|
+
|
|
141
144
|
return attrs, elems
|
|
142
145
|
end
|
|
143
146
|
|
|
@@ -163,10 +166,15 @@ module Fluent
|
|
|
163
166
|
Dir.glob(pattern).sort.each { |entry|
|
|
164
167
|
basepath = File.dirname(entry)
|
|
165
168
|
fname = File.basename(entry)
|
|
169
|
+
suspicious_backup_extensions = %w(bak old backup orig prev conf tmp temp debug wip)
|
|
170
|
+
if path.end_with?('*.conf') and
|
|
171
|
+
suspicious_backup_extensions.any? { |ext| fname.end_with?(".#{ext}.conf", "_#{ext}.conf") }
|
|
172
|
+
@logger.warn "There is a possibility that '@include #{uri}' includes duplicated backed-up config file such as <#{fname}>" if @logger
|
|
173
|
+
end
|
|
166
174
|
data = File.read(entry)
|
|
167
175
|
data.force_encoding('UTF-8')
|
|
168
176
|
ss = StringScanner.new(data)
|
|
169
|
-
V1Parser.new(ss, basepath, fname, @eval_context).parse_element(true, nil, attrs, elems)
|
|
177
|
+
V1Parser.new(ss, basepath, fname, @eval_context, on_file_parsed: @on_file_parsed).parse_element(true, nil, attrs, elems)
|
|
170
178
|
}
|
|
171
179
|
else
|
|
172
180
|
require 'open-uri'
|
|
@@ -175,7 +183,7 @@ module Fluent
|
|
|
175
183
|
data = u.open { |f| f.read }
|
|
176
184
|
data.force_encoding('UTF-8')
|
|
177
185
|
ss = StringScanner.new(data)
|
|
178
|
-
V1Parser.new(ss, basepath, fname, @eval_context).parse_element(true, nil, attrs, elems)
|
|
186
|
+
V1Parser.new(ss, basepath, fname, @eval_context, on_file_parsed: @on_file_parsed).parse_element(true, nil, attrs, elems)
|
|
179
187
|
end
|
|
180
188
|
rescue SystemCallError => e
|
|
181
189
|
cpe = ConfigParseError.new("include error #{uri} - #{e}")
|
|
@@ -30,9 +30,10 @@ module Fluent
|
|
|
30
30
|
FLUENT_STR_TAG = 'tag:fluent/s'.freeze
|
|
31
31
|
SHOVEL = '<<'.freeze
|
|
32
32
|
|
|
33
|
-
def initialize(context = Kernel.binding)
|
|
33
|
+
def initialize(context = Kernel.binding, on_file_parsed: nil)
|
|
34
34
|
@context = context
|
|
35
35
|
@current_path = nil
|
|
36
|
+
@on_file_parsed = on_file_parsed
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
# @param [String] path
|
|
@@ -55,9 +56,13 @@ module Fluent
|
|
|
55
56
|
Fluent::Config::YamlParser::FluentValue::StringValue.new(val, @context)
|
|
56
57
|
end
|
|
57
58
|
|
|
58
|
-
path.open do |f|
|
|
59
|
+
config = path.open do |f|
|
|
59
60
|
visitor.accept(Psych.parse(f))
|
|
60
61
|
end
|
|
62
|
+
|
|
63
|
+
@on_file_parsed&.call(File.expand_path(path.to_s))
|
|
64
|
+
|
|
65
|
+
config
|
|
61
66
|
end
|
|
62
67
|
|
|
63
68
|
def eval_include(path, parent)
|
|
@@ -21,7 +21,7 @@ require 'pathname'
|
|
|
21
21
|
module Fluent
|
|
22
22
|
module Config
|
|
23
23
|
module YamlParser
|
|
24
|
-
def self.parse(path)
|
|
24
|
+
def self.parse(path, on_file_parsed: nil)
|
|
25
25
|
context = Kernel.binding
|
|
26
26
|
|
|
27
27
|
unless context.respond_to?(:use_nil)
|
|
@@ -48,7 +48,7 @@ module Fluent
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
s = Fluent::Config::YamlParser::Loader.new(context).load(Pathname.new(path))
|
|
51
|
+
s = Fluent::Config::YamlParser::Loader.new(context, on_file_parsed: on_file_parsed).load(Pathname.new(path))
|
|
52
52
|
Fluent::Config::YamlParser::Parser.new(s).build.to_element
|
|
53
53
|
end
|
|
54
54
|
end
|
data/lib/fluent/config.rb
CHANGED
|
@@ -26,7 +26,7 @@ module Fluent
|
|
|
26
26
|
# @param additional_config [String] config which is added to last of config body
|
|
27
27
|
# @param use_v1_config [Bool] config is formatted with v1 or not
|
|
28
28
|
# @return [Fluent::Config]
|
|
29
|
-
def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil)
|
|
29
|
+
def self.build(config_path:, encoding: 'utf-8', additional_config: nil, use_v1_config: true, type: nil, on_file_parsed: nil)
|
|
30
30
|
if type == :guess
|
|
31
31
|
config_file_ext = File.extname(config_path)
|
|
32
32
|
if config_file_ext == '.yaml' || config_file_ext == '.yml'
|
|
@@ -35,7 +35,7 @@ module Fluent
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
if type == :yaml || type == :yml
|
|
38
|
-
return Fluent::Config::YamlParser.parse(config_path)
|
|
38
|
+
return Fluent::Config::YamlParser.parse(config_path, on_file_parsed: on_file_parsed)
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
config_fname = File.basename(config_path)
|
|
@@ -49,10 +49,10 @@ module Fluent
|
|
|
49
49
|
s
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
Fluent::Config.parse(config_data, config_fname, config_basedir, use_v1_config)
|
|
52
|
+
Fluent::Config.parse(config_data, config_fname, config_basedir, use_v1_config, on_file_parsed: on_file_parsed)
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
def self.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1)
|
|
55
|
+
def self.parse(str, fname, basepath = Dir.pwd, v1_config = nil, syntax: :v1, on_file_parsed: nil)
|
|
56
56
|
parser = if fname =~ /\.rb$/ || syntax == :ruby
|
|
57
57
|
:ruby
|
|
58
58
|
elsif v1_config.nil?
|
|
@@ -68,7 +68,7 @@ module Fluent
|
|
|
68
68
|
case parser
|
|
69
69
|
when :v1
|
|
70
70
|
require 'fluent/config/v1_parser'
|
|
71
|
-
V1Parser.parse(str, fname, basepath, Kernel.binding)
|
|
71
|
+
V1Parser.parse(str, fname, basepath, Kernel.binding, on_file_parsed: on_file_parsed)
|
|
72
72
|
when :v0
|
|
73
73
|
# TODO: show deprecated message in v1
|
|
74
74
|
require 'fluent/config/parser'
|
data/lib/fluent/engine.rb
CHANGED
|
@@ -186,7 +186,7 @@ module Fluent
|
|
|
186
186
|
|
|
187
187
|
ret.all_plugins.each do |plugin|
|
|
188
188
|
if plugin.respond_to?(:reloadable_plugin?) && !plugin.reloadable_plugin?
|
|
189
|
-
raise Fluent::ConfigError, "Unreloadable plugin
|
|
189
|
+
raise Fluent::ConfigError, "Unreloadable plugin: #{Fluent::Plugin.lookup_type_from_class(plugin.class)}, plugin_id: #{plugin.plugin_id}, class_name: #{plugin.class})"
|
|
190
190
|
end
|
|
191
191
|
end
|
|
192
192
|
|
data/lib/fluent/event.rb
CHANGED
|
@@ -268,11 +268,12 @@ module Fluent
|
|
|
268
268
|
end
|
|
269
269
|
|
|
270
270
|
class CompressedMessagePackEventStream < MessagePackEventStream
|
|
271
|
-
def initialize(data, cached_unpacker = nil, size = 0, unpacked_times: nil, unpacked_records: nil, compress: :gzip)
|
|
271
|
+
def initialize(data, cached_unpacker = nil, size = 0, unpacked_times: nil, unpacked_records: nil, compress: :gzip, decompression_size_limit: Fluent::Plugin::Compressable::DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
272
272
|
super(data, cached_unpacker, size, unpacked_times: unpacked_times, unpacked_records: unpacked_records)
|
|
273
273
|
@decompressed_data = nil
|
|
274
274
|
@compressed_data = data
|
|
275
275
|
@type = compress
|
|
276
|
+
@decompression_size_limit = decompression_size_limit
|
|
276
277
|
end
|
|
277
278
|
|
|
278
279
|
def empty?
|
|
@@ -205,7 +205,7 @@ module Fluent
|
|
|
205
205
|
def generate_chunk(metadata)
|
|
206
206
|
# FileChunk generates real path with unique_id
|
|
207
207
|
perm = @file_permission || system_config.file_permission
|
|
208
|
-
chunk = Fluent::Plugin::Buffer::FileChunk.new(metadata, @path, :create, perm: perm, compress: @compress)
|
|
208
|
+
chunk = Fluent::Plugin::Buffer::FileChunk.new(metadata, @path, :create, perm: perm, compress: @compress, decompression_size_limit: @decompression_size_limit)
|
|
209
209
|
log.debug "Created new chunk", chunk_id: dump_unique_id_hex(chunk.unique_id), metadata: metadata
|
|
210
210
|
|
|
211
211
|
return chunk
|
|
@@ -247,8 +247,8 @@ module Fluent
|
|
|
247
247
|
|
|
248
248
|
def escaped_patterns(patterns)
|
|
249
249
|
patterns.map { |pattern|
|
|
250
|
-
# '{' '}' are special character in Dir.glob
|
|
251
|
-
pattern.gsub(/[\{\}]/) { |c| "\\#{c}" }
|
|
250
|
+
# '{', '}', '[' and ']' are special character in Dir.glob
|
|
251
|
+
pattern.gsub(/[\{\}\[\]]/) { |c| "\\#{c}" }
|
|
252
252
|
}
|
|
253
253
|
end
|
|
254
254
|
end
|
|
@@ -183,7 +183,7 @@ module Fluent
|
|
|
183
183
|
end
|
|
184
184
|
|
|
185
185
|
begin
|
|
186
|
-
chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(m, path, mode, @key_in_path, compress: @compress)
|
|
186
|
+
chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(m, path, mode, @key_in_path, compress: @compress, decompression_size_limit: @decompression_size_limit)
|
|
187
187
|
chunk.restore_size(@chunk_format) if @calc_num_records
|
|
188
188
|
rescue Fluent::Plugin::Buffer::FileSingleChunk::FileChunkError => e
|
|
189
189
|
exist_broken_file = true
|
|
@@ -216,7 +216,7 @@ module Fluent
|
|
|
216
216
|
def generate_chunk(metadata)
|
|
217
217
|
# FileChunk generates real path with unique_id
|
|
218
218
|
perm = @file_permission || system_config.file_permission
|
|
219
|
-
chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(metadata, @path, :create, @key_in_path, perm: perm, compress: @compress)
|
|
219
|
+
chunk = Fluent::Plugin::Buffer::FileSingleChunk.new(metadata, @path, :create, @key_in_path, perm: perm, compress: @compress, decompression_size_limit: @decompression_size_limit)
|
|
220
220
|
|
|
221
221
|
log.debug "Created new chunk", chunk_id: dump_unique_id_hex(chunk.unique_id), metadata: metadata
|
|
222
222
|
|
|
@@ -27,7 +27,7 @@ module Fluent
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def generate_chunk(metadata)
|
|
30
|
-
Fluent::Plugin::Buffer::MemoryChunk.new(metadata, compress: @compress)
|
|
30
|
+
Fluent::Plugin::Buffer::MemoryChunk.new(metadata, compress: @compress, decompression_size_limit: @decompression_size_limit)
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
end
|
|
@@ -48,7 +48,7 @@ module Fluent
|
|
|
48
48
|
|
|
49
49
|
# TODO: CompressedPackedMessage of forward protocol?
|
|
50
50
|
|
|
51
|
-
def initialize(metadata, compress: :text)
|
|
51
|
+
def initialize(metadata, compress: :text, decompression_size_limit: Compressable::DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
52
52
|
super()
|
|
53
53
|
@unique_id = generate_unique_id
|
|
54
54
|
@metadata = metadata
|
|
@@ -64,6 +64,7 @@ module Fluent
|
|
|
64
64
|
elsif compress == :zstd
|
|
65
65
|
extend ZstdDecompressable
|
|
66
66
|
end
|
|
67
|
+
@decompression_size_limit = decompression_size_limit
|
|
67
68
|
end
|
|
68
69
|
|
|
69
70
|
attr_reader :unique_id, :metadata, :state
|
|
@@ -39,8 +39,8 @@ module Fluent
|
|
|
39
39
|
|
|
40
40
|
attr_reader :path, :meta_path, :permission
|
|
41
41
|
|
|
42
|
-
def initialize(metadata, path, mode, perm: nil, compress: :text)
|
|
43
|
-
super(metadata, compress: compress)
|
|
42
|
+
def initialize(metadata, path, mode, perm: nil, compress: :text, decompression_size_limit: Compressable::DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
43
|
+
super(metadata, compress: compress, decompression_size_limit: decompression_size_limit)
|
|
44
44
|
perm ||= Fluent::DEFAULT_FILE_PERMISSION
|
|
45
45
|
@permission = perm.is_a?(String) ? perm.to_i(8) : perm
|
|
46
46
|
@bytesize = @size = @adding_bytes = @adding_size = 0
|
|
@@ -35,8 +35,8 @@ module Fluent
|
|
|
35
35
|
|
|
36
36
|
attr_reader :path, :permission
|
|
37
37
|
|
|
38
|
-
def initialize(metadata, path, mode, key, perm: Fluent::DEFAULT_FILE_PERMISSION, compress: :text)
|
|
39
|
-
super(metadata, compress: compress)
|
|
38
|
+
def initialize(metadata, path, mode, key, perm: Fluent::DEFAULT_FILE_PERMISSION, compress: :text, decompression_size_limit: Compressable::DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
39
|
+
super(metadata, compress: compress, decompression_size_limit: decompression_size_limit)
|
|
40
40
|
@key = key
|
|
41
41
|
perm ||= Fluent::DEFAULT_FILE_PERMISSION
|
|
42
42
|
@permission = perm.is_a?(String) ? perm.to_i(8) : perm
|
|
@@ -20,7 +20,7 @@ module Fluent
|
|
|
20
20
|
module Plugin
|
|
21
21
|
class Buffer
|
|
22
22
|
class MemoryChunk < Chunk
|
|
23
|
-
def initialize(metadata, compress: :text)
|
|
23
|
+
def initialize(metadata, compress: :text, decompression_size_limit: Compressable::DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
24
24
|
super
|
|
25
25
|
@chunk = ''.force_encoding(Encoding::ASCII_8BIT)
|
|
26
26
|
@chunk_bytes = 0
|
data/lib/fluent/plugin/buffer.rb
CHANGED
|
@@ -66,6 +66,9 @@ module Fluent
|
|
|
66
66
|
desc 'Compress buffered data.'
|
|
67
67
|
config_param :compress, :enum, list: [:text, :gzip, :zstd], default: :text
|
|
68
68
|
|
|
69
|
+
desc 'The size limit of the decompressed element.'
|
|
70
|
+
config_param :decompression_size_limit, :size, default: Compressable::DEFAULT_DECOMPRESSION_SIZE_LIMIT
|
|
71
|
+
|
|
69
72
|
desc 'If true, chunks are thrown away when unrecoverable error happens'
|
|
70
73
|
config_param :disable_chunk_backup, :bool, default: false
|
|
71
74
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# limitations under the License.
|
|
15
15
|
#
|
|
16
16
|
|
|
17
|
+
require 'fluent/plugin/extractor'
|
|
17
18
|
require 'stringio'
|
|
18
19
|
require 'zlib'
|
|
19
20
|
require 'zstd-ruby'
|
|
@@ -21,6 +22,8 @@ require 'zstd-ruby'
|
|
|
21
22
|
module Fluent
|
|
22
23
|
module Plugin
|
|
23
24
|
module Compressable
|
|
25
|
+
DEFAULT_DECOMPRESSION_SIZE_LIMIT = 256 * 1024 * 1024
|
|
26
|
+
|
|
24
27
|
def compress(data, type: :gzip, **kwargs)
|
|
25
28
|
output_io = kwargs[:output_io]
|
|
26
29
|
io = output_io || StringIO.new
|
|
@@ -60,79 +63,21 @@ module Fluent
|
|
|
60
63
|
|
|
61
64
|
private
|
|
62
65
|
|
|
63
|
-
def string_decompress_gzip(compressed_data)
|
|
64
|
-
io = StringIO.new(compressed_data)
|
|
65
|
-
out = ''
|
|
66
|
-
loop do
|
|
67
|
-
reader = Zlib::GzipReader.new(io)
|
|
68
|
-
out << reader.read
|
|
69
|
-
unused = reader.unused
|
|
70
|
-
reader.finish
|
|
71
|
-
unless unused.nil?
|
|
72
|
-
adjust = unused.length
|
|
73
|
-
io.pos -= adjust
|
|
74
|
-
end
|
|
75
|
-
break if io.eof?
|
|
76
|
-
end
|
|
77
|
-
out
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def string_decompress_zstd(compressed_data)
|
|
81
|
-
io = StringIO.new(compressed_data)
|
|
82
|
-
reader = Zstd::StreamReader.new(io)
|
|
83
|
-
out = ''
|
|
84
|
-
loop do
|
|
85
|
-
# Zstd::StreamReader needs to specify the size of the buffer
|
|
86
|
-
out << reader.read(1024)
|
|
87
|
-
# Zstd::StreamReader doesn't provide unused data, so we have to manually adjust the position
|
|
88
|
-
break if io.eof?
|
|
89
|
-
end
|
|
90
|
-
out
|
|
91
|
-
end
|
|
92
|
-
|
|
93
66
|
def string_decompress(compressed_data, type = :gzip)
|
|
94
67
|
if type == :gzip
|
|
95
|
-
|
|
68
|
+
Extractor.decompress_gzip(compressed_data, limit: @decompression_size_limit || DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
96
69
|
elsif type == :zstd
|
|
97
|
-
|
|
70
|
+
Extractor.decompress_zstd(compressed_data, limit: @decompression_size_limit || DEFAULT_DECOMPRESSION_SIZE_LIMIT)
|
|
98
71
|
else
|
|
99
72
|
raise ArgumentError, "Unknown compression type: #{type}"
|
|
100
73
|
end
|
|
101
74
|
end
|
|
102
75
|
|
|
103
|
-
def io_decompress_gzip(input, output)
|
|
104
|
-
loop do
|
|
105
|
-
reader = Zlib::GzipReader.new(input)
|
|
106
|
-
v = reader.read
|
|
107
|
-
output.write(v)
|
|
108
|
-
unused = reader.unused
|
|
109
|
-
reader.finish
|
|
110
|
-
unless unused.nil?
|
|
111
|
-
adjust = unused.length
|
|
112
|
-
input.pos -= adjust
|
|
113
|
-
end
|
|
114
|
-
break if input.eof?
|
|
115
|
-
end
|
|
116
|
-
output
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
def io_decompress_zstd(input, output)
|
|
120
|
-
reader = Zstd::StreamReader.new(input)
|
|
121
|
-
loop do
|
|
122
|
-
# Zstd::StreamReader needs to specify the size of the buffer
|
|
123
|
-
v = reader.read(1024)
|
|
124
|
-
output.write(v)
|
|
125
|
-
# Zstd::StreamReader doesn't provide unused data, so we have to manually adjust the position
|
|
126
|
-
break if input.eof?
|
|
127
|
-
end
|
|
128
|
-
output
|
|
129
|
-
end
|
|
130
|
-
|
|
131
76
|
def io_decompress(input, output, type = :gzip)
|
|
132
77
|
if type == :gzip
|
|
133
|
-
io_decompress_gzip(input, output)
|
|
78
|
+
Extractor.io_decompress_gzip(input, output)
|
|
134
79
|
elsif type == :zstd
|
|
135
|
-
io_decompress_zstd(input, output)
|
|
80
|
+
Extractor.io_decompress_zstd(input, output)
|
|
136
81
|
else
|
|
137
82
|
raise ArgumentError, "Unknown compression type: #{type}"
|
|
138
83
|
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Fluentd
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
require 'stringio'
|
|
18
|
+
require 'zlib'
|
|
19
|
+
require 'zstd-ruby'
|
|
20
|
+
require 'fluent/error'
|
|
21
|
+
|
|
22
|
+
module Fluent
|
|
23
|
+
module Plugin
|
|
24
|
+
module Extractor
|
|
25
|
+
class SizeLimitError < UnrecoverableError; end
|
|
26
|
+
|
|
27
|
+
BYTES_TO_READ = 64 * 1024
|
|
28
|
+
INFLATE_BYTES_TO_READ = 1024
|
|
29
|
+
|
|
30
|
+
def self.decompress_gzip(compressed_data, limit:)
|
|
31
|
+
io = StringIO.new(compressed_data)
|
|
32
|
+
out = ''
|
|
33
|
+
loop do
|
|
34
|
+
reader = Zlib::GzipReader.new(io)
|
|
35
|
+
while (chunk = reader.read(BYTES_TO_READ))
|
|
36
|
+
out << chunk
|
|
37
|
+
if out.bytesize > limit
|
|
38
|
+
raise SizeLimitError, "Decompressed data exceeds limit of #{limit} bytes"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
unused = reader.unused
|
|
43
|
+
reader.finish
|
|
44
|
+
unless unused.nil?
|
|
45
|
+
adjust = unused.length
|
|
46
|
+
io.pos -= adjust
|
|
47
|
+
end
|
|
48
|
+
break if io.eof?
|
|
49
|
+
end
|
|
50
|
+
out
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.decompress_zstd(compressed_data, limit:)
|
|
54
|
+
io = StringIO.new(compressed_data)
|
|
55
|
+
reader = Zstd::StreamReader.new(io)
|
|
56
|
+
out = ''
|
|
57
|
+
loop do
|
|
58
|
+
# Zstd::StreamReader needs to specify the size of the buffer
|
|
59
|
+
out << reader.read(BYTES_TO_READ)
|
|
60
|
+
if out.bytesize > limit
|
|
61
|
+
raise SizeLimitError, "Decompressed data exceeds limit of #{limit} bytes"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Zstd::StreamReader doesn't provide unused data, so we have to manually adjust the position
|
|
65
|
+
break if io.eof?
|
|
66
|
+
end
|
|
67
|
+
out
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.decompress_deflate(compressed_data, limit:)
|
|
71
|
+
io = StringIO.new(compressed_data)
|
|
72
|
+
out = ''
|
|
73
|
+
begin
|
|
74
|
+
zstream = Zlib::Inflate.new
|
|
75
|
+
while (chunk = io.read(INFLATE_BYTES_TO_READ))
|
|
76
|
+
out << zstream.inflate(chunk)
|
|
77
|
+
if out.bytesize > limit
|
|
78
|
+
raise SizeLimitError, "Decompressed data exceeds limit of #{limit} bytes"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
out << zstream.finish
|
|
82
|
+
if out.bytesize > limit
|
|
83
|
+
raise SizeLimitError, "Decompressed data exceeds limit of #{limit} bytes"
|
|
84
|
+
end
|
|
85
|
+
ensure
|
|
86
|
+
zstream&.close
|
|
87
|
+
end
|
|
88
|
+
out
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def self.io_decompress_gzip(input, output)
|
|
92
|
+
loop do
|
|
93
|
+
reader = Zlib::GzipReader.new(input)
|
|
94
|
+
while (chunk = reader.read(BYTES_TO_READ))
|
|
95
|
+
output.write(chunk)
|
|
96
|
+
end
|
|
97
|
+
unused = reader.unused
|
|
98
|
+
reader.finish
|
|
99
|
+
unless unused.nil?
|
|
100
|
+
adjust = unused.length
|
|
101
|
+
input.pos -= adjust
|
|
102
|
+
end
|
|
103
|
+
break if input.eof?
|
|
104
|
+
end
|
|
105
|
+
output
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def self.io_decompress_zstd(input, output)
|
|
109
|
+
reader = Zstd::StreamReader.new(input)
|
|
110
|
+
loop do
|
|
111
|
+
# Zstd::StreamReader needs to specify the size of the buffer
|
|
112
|
+
chunk = reader.read(BYTES_TO_READ)
|
|
113
|
+
output.write(chunk)
|
|
114
|
+
# Zstd::StreamReader doesn't provide unused data, so we have to manually adjust the position
|
|
115
|
+
break if input.eof?
|
|
116
|
+
end
|
|
117
|
+
output
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -71,7 +71,7 @@ module Fluent::Plugin
|
|
|
71
71
|
# require utilities which would be used in ruby placeholders
|
|
72
72
|
require 'pathname'
|
|
73
73
|
require 'uri'
|
|
74
|
-
require 'cgi'
|
|
74
|
+
require 'cgi/escape'
|
|
75
75
|
RubyPlaceholderExpander.new(placeholder_expander_params)
|
|
76
76
|
else
|
|
77
77
|
PlaceholderExpander.new(placeholder_expander_params)
|
|
@@ -26,7 +26,7 @@ module Fluent::Plugin
|
|
|
26
26
|
super
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
config_param :bind, :string, default: '
|
|
29
|
+
config_param :bind, :string, default: '127.0.0.1'
|
|
30
30
|
config_param :port, :integer, default: 24230
|
|
31
31
|
config_param :unix_path, :string, default: nil
|
|
32
32
|
#config_param :unix_mode # TODO
|
|
@@ -54,6 +54,8 @@ module Fluent::Plugin
|
|
|
54
54
|
config_param :chunk_size_warn_limit, :size, default: nil
|
|
55
55
|
desc 'Received chunk is dropped if it is larger than this value.'
|
|
56
56
|
config_param :chunk_size_limit, :size, default: nil
|
|
57
|
+
desc 'The size limit of the decompressed element.'
|
|
58
|
+
config_param :decompression_size_limit, :size, default: 256*1024*1024
|
|
57
59
|
desc 'Skip an event if incoming event is invalid.'
|
|
58
60
|
config_param :skip_invalid_event, :bool, default: true
|
|
59
61
|
|
|
@@ -311,7 +313,7 @@ module Fluent::Plugin
|
|
|
311
313
|
size = option['size'] || 0
|
|
312
314
|
|
|
313
315
|
if option['compressed'] && option['compressed'] != 'text'
|
|
314
|
-
es = Fluent::CompressedMessagePackEventStream.new(entries, nil, size.to_i, compress: option['compressed'].to_sym)
|
|
316
|
+
es = Fluent::CompressedMessagePackEventStream.new(entries, nil, size.to_i, compress: option['compressed'].to_sym, decompression_size_limit: @decompression_size_limit)
|
|
315
317
|
else
|
|
316
318
|
es = Fluent::MessagePackEventStream.new(entries, nil, size.to_i)
|
|
317
319
|
end
|