fluentd 1.19.3 → 1.20.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/AGENTS.md +46 -0
  3. data/CHANGELOG.md +120 -0
  4. data/GithubWorkflow.md +1 -1
  5. data/MAINTAINERS.md +2 -2
  6. data/README.md +3 -2
  7. data/Rakefile +2 -1
  8. data/SECURITY.md +26 -1
  9. data/lib/fluent/command/cat.rb +3 -3
  10. data/lib/fluent/compat/exec_util.rb +20 -5
  11. data/lib/fluent/config/basic_parser.rb +0 -1
  12. data/lib/fluent/config/literal_parser.rb +22 -10
  13. data/lib/fluent/config/types.rb +10 -2
  14. data/lib/fluent/config/yaml_parser/loader.rb +12 -1
  15. data/lib/fluent/config/yaml_parser/parser.rb +14 -13
  16. data/lib/fluent/configurable.rb +1 -0
  17. data/lib/fluent/daemon.rb +2 -1
  18. data/lib/fluent/env.rb +1 -0
  19. data/lib/fluent/event.rb +37 -0
  20. data/lib/fluent/load.rb +0 -1
  21. data/lib/fluent/log.rb +2 -2
  22. data/lib/fluent/plugin/base.rb +7 -2
  23. data/lib/fluent/plugin/buf_file.rb +3 -3
  24. data/lib/fluent/plugin/buf_file_single.rb +6 -2
  25. data/lib/fluent/plugin/buffer/chunk.rb +14 -6
  26. data/lib/fluent/plugin/buffer/file_chunk.rb +28 -13
  27. data/lib/fluent/plugin/buffer/file_single_chunk.rb +28 -13
  28. data/lib/fluent/plugin/buffer.rb +125 -41
  29. data/lib/fluent/plugin/compressable.rb +2 -2
  30. data/lib/fluent/plugin/extractor.rb +17 -6
  31. data/lib/fluent/plugin/filter_record_transformer.rb +2 -1
  32. data/lib/fluent/plugin/formatter_out_file.rb +3 -4
  33. data/lib/fluent/plugin/in_exec.rb +6 -4
  34. data/lib/fluent/plugin/in_forward.rb +39 -29
  35. data/lib/fluent/plugin/in_http.rb +83 -2
  36. data/lib/fluent/plugin/in_monitor_agent.rb +2 -1
  37. data/lib/fluent/plugin/in_object_space.rb +2 -2
  38. data/lib/fluent/plugin/in_sample.rb +2 -1
  39. data/lib/fluent/plugin/in_syslog.rb +72 -6
  40. data/lib/fluent/plugin/in_tail/compatibility.rb +111 -0
  41. data/lib/fluent/plugin/in_tail/dir_watcher.rb +713 -0
  42. data/lib/fluent/plugin/in_tail/group_watch.rb +13 -13
  43. data/lib/fluent/plugin/in_tail/io_handler.rb +391 -0
  44. data/lib/fluent/plugin/in_tail/line_feeder.rb +230 -0
  45. data/lib/fluent/plugin/in_tail/stat_watcher.rb +52 -0
  46. data/lib/fluent/plugin/in_tail/tail_watcher.rb +276 -0
  47. data/lib/fluent/plugin/in_tail/worker_pool.rb +298 -0
  48. data/lib/fluent/plugin/in_tail.rb +324 -815
  49. data/lib/fluent/plugin/in_unix.rb +5 -3
  50. data/lib/fluent/plugin/out_exec_filter.rb +2 -2
  51. data/lib/fluent/plugin/out_file.rb +10 -4
  52. data/lib/fluent/plugin/out_forward/connection_manager.rb +18 -0
  53. data/lib/fluent/plugin/out_forward.rb +21 -2
  54. data/lib/fluent/plugin/out_http.rb +0 -10
  55. data/lib/fluent/plugin/output.rb +81 -31
  56. data/lib/fluent/plugin/parser_csv.rb +7 -2
  57. data/lib/fluent/plugin/parser_json.rb +25 -12
  58. data/lib/fluent/plugin/parser_ltsv.rb +2 -4
  59. data/lib/fluent/plugin/parser_msgpack.rb +7 -6
  60. data/lib/fluent/plugin/parser_syslog.rb +55 -8
  61. data/lib/fluent/plugin/parser_tsv.rb +6 -1
  62. data/lib/fluent/plugin/sd_file.rb +2 -1
  63. data/lib/fluent/plugin/storage_local.rb +2 -2
  64. data/lib/fluent/plugin_helper/http_server/server.rb +29 -13
  65. data/lib/fluent/plugin_helper/http_server.rb +2 -1
  66. data/lib/fluent/root_agent.rb +1 -1
  67. data/lib/fluent/supervisor.rb +32 -6
  68. data/lib/fluent/system_config.rb +5 -2
  69. data/lib/fluent/time.rb +8 -7
  70. data/lib/fluent/version.rb +1 -1
  71. data/templates/new_gem/.gitignore +8 -0
  72. metadata +41 -21
@@ -32,8 +32,13 @@ module Fluent
32
32
  end
33
33
 
34
34
  def parse(text)
35
+ r = {}
36
+ i = 0
35
37
  values = text.split(@delimiter, @key_num)
36
- r = Hash[@keys.zip(values)]
38
+ while i < @key_num
39
+ r[@keys[i]] = values[i]
40
+ i += 1
41
+ end
37
42
  time, record = convert_values(parse_time(r), r)
38
43
  yield time, record
39
44
  end
@@ -16,6 +16,7 @@
16
16
 
17
17
  require 'cool.io'
18
18
 
19
+ require 'fluent/env'
19
20
  require 'fluent/plugin_helper'
20
21
  require 'fluent/plugin/service_discovery'
21
22
 
@@ -75,7 +76,7 @@ module Fluent
75
76
  -> (v) { YAML.safe_load(v).map }
76
77
  when :json
77
78
  require 'json'
78
- -> (v) { JSON.parse(v) }
79
+ -> (v) { JSON.parse(v, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) }
79
80
  end
80
81
  end
81
82
 
@@ -90,7 +90,7 @@ module Fluent
90
90
  log.warn "detect empty plugin storage file during startup. Ignored: #{@path}"
91
91
  return
92
92
  end
93
- data = JSON.parse(data)
93
+ data = JSON.parse(data, **Fluent::DEFAULT_JSON_PARSE_OPTIONS)
94
94
  raise Fluent::ConfigError, "Invalid contents (not object) in plugin storage file: '#{@path}'" unless data.is_a?(Hash)
95
95
  rescue => e
96
96
  log.error "failed to read data from plugin storage file", path: @path, error: e
@@ -114,7 +114,7 @@ module Fluent
114
114
  return unless File.exist?(@path)
115
115
  begin
116
116
  json_string = File.open(@path, 'r:utf-8:utf-8'){ |io| io.read }
117
- json = JSON.parse(json_string)
117
+ json = JSON.parse(json_string, **Fluent::DEFAULT_JSON_PARSE_OPTIONS)
118
118
  unless json.is_a?(Hash)
119
119
  log.error "broken content for plugin storage (Hash required: ignored)", type: json.class
120
120
  log.debug "broken content", content: json_string
@@ -31,15 +31,28 @@ module Fluent
31
31
  # @param default_app [Object] This method must have #call.
32
32
  # @param tls_context [OpenSSL::SSL::SSLContext]
33
33
  def initialize(addr:, port:, logger:, default_app: nil, tls_context: nil)
34
- @addr = addr
34
+ # Normalize the address: strip brackets if present
35
+ # Brackets are only for URI formatting, not for socket binding
36
+ @addr = if addr.start_with?('[') && addr.end_with?(']')
37
+ addr[1..-2] # Remove surrounding brackets
38
+ else
39
+ addr
40
+ end
35
41
  @port = port
36
42
  @logger = logger
37
43
 
38
44
  # TODO: support http2
39
45
  scheme = tls_context ? 'https' : 'http'
40
- @uri = URI("#{scheme}://#{@addr}:#{@port}").to_s
46
+ # Handle IPv6 addresses properly in URI construction per RFC 3986
47
+ # Add brackets to IPv6 addresses for URI compliance (ip-literal per RFC 3986)
48
+ ip_literal = if @addr.include?(":")
49
+ "[#{@addr}]" # IPv6 address - add brackets
50
+ else
51
+ @addr # IPv4 or hostname - use directly
52
+ end
53
+ @uri = URI("#{scheme}://#{ip_literal}:#{@port}").to_s
41
54
  @router = Router.new(default_app)
42
- @server_task = nil
55
+ @server_task_queue = ::Thread::Queue.new
43
56
  Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
44
57
 
45
58
  opts = if tls_context
@@ -60,17 +73,20 @@ module Fluent
60
73
 
61
74
  Async do |task|
62
75
  Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
63
- @server_task = task.async do
64
- Console.logger = Fluent::Log::ConsoleAdapter.wrap(@logger)
65
- @server.run
66
- end
67
- if notify
68
- notify.push(:ready)
69
- end
76
+ begin
77
+ @server.endpoint.accept(&@server.method(:accept))
78
+ if notify
79
+ notify.push(:ready)
80
+ end
70
81
 
71
- @server_task_queue = ::Thread::Queue.new
72
- @server_task_queue.pop
73
- @server_task&.stop
82
+ @server_task_queue.pop
83
+ rescue => e
84
+ @logger.error("Failed to run HTTP server listening #{@uri}: #{e.class}: #{e.message}")
85
+ raise unless notify
86
+ notify.push(e)
87
+ ensure
88
+ task.children&.each(&:stop)
89
+ end
74
90
  end
75
91
 
76
92
  @logger.debug('Finished HTTP server')
@@ -121,7 +121,8 @@ module Fluent
121
121
  def _block_until_http_server_start
122
122
  que = Queue.new
123
123
  yield(que)
124
- que.pop
124
+ result = que.pop
125
+ raise result if result.is_a?(Exception)
125
126
  end
126
127
  end
127
128
  end
@@ -415,7 +415,7 @@ module Fluent
415
415
  input.configure(conf)
416
416
  input.event_emitter_apply_source_only if @source_only_mode.enabled?
417
417
  if @enable_input_metrics
418
- @event_router.add_metric_callbacks(input.plugin_id, Proc.new {|es| input.metric_callback(es) })
418
+ input.event_emitter_router(conf['@label']).add_metric_callbacks(input.plugin_id, Proc.new {|es| input.metric_callback(es) })
419
419
  end
420
420
  @inputs << input
421
421
 
@@ -100,7 +100,14 @@ module Fluent
100
100
  end
101
101
 
102
102
  def cleanup_lock_dir
103
- FileUtils.rm(Dir.glob(File.join(@fluentd_lock_dir, "fluentd-*.lock")))
103
+ begin
104
+ Dir.each_child(@fluentd_lock_dir) do |name|
105
+ FileUtils.rm_f(File.join(@fluentd_lock_dir, name)) if File.fnmatch?("fluentd-*.lock", name)
106
+ end
107
+ rescue Errno::ENOENT
108
+ # Directory is already missing. Fall through and let rmdir below
109
+ # fail in the same way as the current implementation.
110
+ end
104
111
  FileUtils.rmdir(@fluentd_lock_dir)
105
112
  end
106
113
 
@@ -366,6 +373,7 @@ module Fluent
366
373
  encoding: config[:conf_encoding],
367
374
  additional_config: config[:inline_config],
368
375
  use_v1_config: config[:use_v1_config],
376
+ type: config[:config_file_type],
369
377
  )
370
378
 
371
379
  Fluent::VariableStore.try_to_reset do
@@ -604,6 +612,8 @@ module Fluent
604
612
  fluentd_conf: params['fluentd_conf'],
605
613
  conf_encoding: params['conf_encoding'],
606
614
  inline_config: params['inline_config'],
615
+ use_v1_config: params['use_v1_config'],
616
+ config_file_type: params['config_file_type']&.to_sym,
607
617
  main_cmd: params['main_cmd'],
608
618
  signame: params['signame'],
609
619
  disable_shared_socket: params['disable_shared_socket'],
@@ -780,6 +790,7 @@ module Fluent
780
790
  MessagePackFactory.init(enable_time_support: @system_config.enable_msgpack_time_support)
781
791
  Fluent::Engine.init(@system_config, start_in_parallel: ENV.key?("FLUENT_RUNNING_IN_PARALLEL_WITH_OLD"))
782
792
  Fluent::Engine.run_configure(@conf)
793
+ enable_ruby_jit if @system_config.enable_jit
783
794
  Fluent::Engine.run
784
795
  self.class.cleanup_socketmanager_path if @standalone_worker
785
796
  exit 0
@@ -808,6 +819,12 @@ module Fluent
808
819
  )
809
820
  @system_config = build_system_config(@conf)
810
821
 
822
+ # `<system> umask` sets the process umask, just like the `--umask` command
823
+ # line option. The command line option takes precedence when both are given.
824
+ if @system_config.umask && !@cl_opt.key?(:chumask)
825
+ @chumask = @system_config.umask
826
+ end
827
+
811
828
  $log.info :supervisor, 'parsing config file is succeeded', path: @config_path
812
829
 
813
830
  build_additional_configurations(parsed_files) do |additional_conf|
@@ -964,6 +981,7 @@ module Fluent
964
981
  'fluentd_conf_path' => @config_path,
965
982
  'fluentd_conf' => @conf.to_s,
966
983
  'use_v1_config' => @use_v1_config,
984
+ 'config_file_type' => @config_file_type,
967
985
  'conf_encoding' => @conf_encoding,
968
986
  'signame' => @signame,
969
987
 
@@ -1208,6 +1226,19 @@ module Fluent
1208
1226
  exit!(unrecoverable_error ? 2 : 1)
1209
1227
  end
1210
1228
 
1229
+ def enable_ruby_jit
1230
+ unless defined?(RubyVM::YJIT) && RubyVM::YJIT.respond_to?(:enable)
1231
+ $log.info "Ruby JIT is not available on this Ruby"
1232
+ return
1233
+ end
1234
+
1235
+ if RubyVM::YJIT.enable
1236
+ $log.info "enabled Ruby JIT"
1237
+ else
1238
+ $log.warn "failed to enable Ruby JIT"
1239
+ end
1240
+ end
1241
+
1211
1242
  def build_system_config(conf)
1212
1243
  system_config = SystemConfig.create(conf, @cl_opt[:strict_config_value])
1213
1244
  # Prefer the options explicitly specified in the command line
@@ -1275,11 +1306,6 @@ module Fluent
1275
1306
  fluentd_spawn_cmd << '-Eascii-8bit:ascii-8bit'
1276
1307
  end
1277
1308
 
1278
- if @system_config.enable_jit
1279
- $log.info "enable Ruby JIT for workers (--jit)"
1280
- fluentd_spawn_cmd << '--jit'
1281
- end
1282
-
1283
1309
  # Adding `-h` so that it can avoid ruby's command blocking
1284
1310
  # e.g. `ruby -Eascii-8bit:ascii-8bit` will block. but `ruby -Eascii-8bit:ascii-8bit -h` won't.
1285
1311
  _, e, s = Open3.capture3(*fluentd_spawn_cmd, "-h")
@@ -30,7 +30,7 @@ module Fluent
30
30
  :file_permission, :dir_permission, :counter_server, :counter_client,
31
31
  :strict_config_value, :enable_msgpack_time_support, :disable_shared_socket,
32
32
  :metrics, :enable_input_metrics, :enable_size_metrics, :enable_jit, :source_only_buffer,
33
- :config_include_dir
33
+ :config_include_dir, :umask
34
34
  ]
35
35
 
36
36
  config_param :workers, :integer, default: 1
@@ -53,7 +53,7 @@ module Fluent
53
53
  config_param :disable_shared_socket, :bool, default: nil
54
54
  config_param :enable_input_metrics, :bool, default: true
55
55
  config_param :enable_size_metrics, :bool, default: nil
56
- config_param :enable_jit, :bool, default: false
56
+ config_param :enable_jit, :bool, default: true
57
57
  config_param :file_permission, default: nil do |v|
58
58
  v.to_i(8)
59
59
  end
@@ -61,6 +61,9 @@ module Fluent
61
61
  v.to_i(8)
62
62
  end
63
63
  config_param :config_include_dir, default: Fluent::DEFAULT_CONFIG_INCLUDE_DIR
64
+ # Kept as a string (like the `--umask` command line option) so that it flows
65
+ # through the existing chumask handling, which applies `to_i(8)` later.
66
+ config_param :umask, :string, default: nil
64
67
  config_section :log, required: false, init: true, multi: false do
65
68
  config_param :path, :string, default: nil
66
69
  config_param :format, :enum, list: [:text, :json], default: :text
data/lib/fluent/time.rb CHANGED
@@ -112,9 +112,8 @@ module Fluent
112
112
  end
113
113
 
114
114
  def self.now
115
- # This method is called many time. so call Process.clock_gettime directly instead of Fluent::Clock.real_now
116
- now = Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
117
- Fluent::EventTime.new(now / 1_000_000_000, now % 1_000_000_000)
115
+ time = Time.now
116
+ Fluent::EventTime.new(time.to_i, time.nsec)
118
117
  end
119
118
 
120
119
  def self.parse(*args)
@@ -362,6 +361,8 @@ module Fluent
362
361
 
363
362
  class TimeFormatter
364
363
  def initialize(format = nil, localtime = true, timezone = nil)
364
+ # An empty cache slot is marked by a nil string, not by its key: 0 is a
365
+ # valid timestamp, so a key can never say whether the slot is filled.
365
366
  @tc1 = 0
366
367
  @tc1_str = nil
367
368
  @tc2 = 0
@@ -389,9 +390,9 @@ module Fluent
389
390
  end
390
391
 
391
392
  def format_without_subsec(time)
392
- if @tc1 == time
393
+ if @tc1_str && @tc1 == time
393
394
  return @tc1_str
394
- elsif @tc2 == time
395
+ elsif @tc2_str && @tc2 == time
395
396
  return @tc2_str
396
397
  else
397
398
  str = format_nocache(time)
@@ -407,9 +408,9 @@ module Fluent
407
408
  end
408
409
 
409
410
  def format_with_subsec(time)
410
- if Fluent::EventTime.eq?(@tc1, time)
411
+ if @tc1_str && Fluent::EventTime.eq?(@tc1, time)
411
412
  return @tc1_str
412
- elsif Fluent::EventTime.eq?(@tc2, time)
413
+ elsif @tc2_str && Fluent::EventTime.eq?(@tc2, time)
413
414
  return @tc2_str
414
415
  else
415
416
  str = format_nocache(time)
@@ -16,6 +16,6 @@
16
16
 
17
17
  module Fluent
18
18
 
19
- VERSION = '1.19.3'
19
+ VERSION = '1.20.0'
20
20
 
21
21
  end
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluentd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.3
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2026-06-25 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: bundler
@@ -44,20 +43,6 @@ dependencies:
44
43
  - - "<"
45
44
  - !ruby/object:Gem::Version
46
45
  version: 2.0.0
47
- - !ruby/object:Gem::Dependency
48
- name: yajl-ruby
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - "~>"
52
- - !ruby/object:Gem::Version
53
- version: '1.0'
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '1.0'
61
46
  - !ruby/object:Gem::Dependency
62
47
  name: cool.io
63
48
  requirement: !ruby/object:Gem::Requirement
@@ -256,6 +241,34 @@ dependencies:
256
241
  - - "~>"
257
242
  - !ruby/object:Gem::Version
258
243
  version: '0.86'
244
+ - !ruby/object:Gem::Dependency
245
+ name: json
246
+ requirement: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '2.21'
251
+ type: :runtime
252
+ prerelease: false
253
+ version_requirements: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - ">="
256
+ - !ruby/object:Gem::Version
257
+ version: '2.21'
258
+ - !ruby/object:Gem::Dependency
259
+ name: yajl-ruby
260
+ requirement: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - "~>"
263
+ - !ruby/object:Gem::Version
264
+ version: '1.0'
265
+ type: :runtime
266
+ prerelease: false
267
+ version_requirements: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - "~>"
270
+ - !ruby/object:Gem::Version
271
+ version: '1.0'
259
272
  - !ruby/object:Gem::Dependency
260
273
  name: base64
261
274
  requirement: !ruby/object:Gem::Requirement
@@ -534,6 +547,7 @@ extra_rdoc_files: []
534
547
  files:
535
548
  - ".rubocop.yml"
536
549
  - ADOPTERS.md
550
+ - AGENTS.md
537
551
  - AUTHORS
538
552
  - CHANGELOG.md
539
553
  - CONTRIBUTING.md
@@ -719,8 +733,15 @@ files:
719
733
  - lib/fluent/plugin/in_sample.rb
720
734
  - lib/fluent/plugin/in_syslog.rb
721
735
  - lib/fluent/plugin/in_tail.rb
736
+ - lib/fluent/plugin/in_tail/compatibility.rb
737
+ - lib/fluent/plugin/in_tail/dir_watcher.rb
722
738
  - lib/fluent/plugin/in_tail/group_watch.rb
739
+ - lib/fluent/plugin/in_tail/io_handler.rb
740
+ - lib/fluent/plugin/in_tail/line_feeder.rb
723
741
  - lib/fluent/plugin/in_tail/position_file.rb
742
+ - lib/fluent/plugin/in_tail/stat_watcher.rb
743
+ - lib/fluent/plugin/in_tail/tail_watcher.rb
744
+ - lib/fluent/plugin/in_tail/worker_pool.rb
724
745
  - lib/fluent/plugin/in_tcp.rb
725
746
  - lib/fluent/plugin/in_udp.rb
726
747
  - lib/fluent/plugin/in_unix.rb
@@ -841,6 +862,7 @@ files:
841
862
  - lib/fluent/version.rb
842
863
  - lib/fluent/win32api.rb
843
864
  - lib/fluent/winsvc.rb
865
+ - templates/new_gem/.gitignore
844
866
  - templates/new_gem/Gemfile
845
867
  - templates/new_gem/README.md.erb
846
868
  - templates/new_gem/Rakefile
@@ -870,7 +892,6 @@ metadata:
870
892
  source_code_uri: https://github.com/fluent/fluentd
871
893
  changelog_uri: https://github.com/fluent/fluentd/blob/master/CHANGELOG.md
872
894
  bug_tracker_uri: https://github.com/fluent/fluentd/issues
873
- post_install_message:
874
895
  rdoc_options: []
875
896
  require_paths:
876
897
  - lib
@@ -878,15 +899,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
878
899
  requirements:
879
900
  - - ">="
880
901
  - !ruby/object:Gem::Version
881
- version: '3.2'
902
+ version: '3.3'
882
903
  required_rubygems_version: !ruby/object:Gem::Requirement
883
904
  requirements:
884
905
  - - ">="
885
906
  - !ruby/object:Gem::Version
886
907
  version: '0'
887
908
  requirements: []
888
- rubygems_version: 3.5.22
889
- signing_key:
909
+ rubygems_version: 4.0.20
890
910
  specification_version: 4
891
911
  summary: Fluentd event collector
892
912
  test_files: []