From 83e9a6a3f0683c8a17650fe6a6e20fb8e9a05fc4 Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Wed, 9 Sep 2026 14:00:25 +0900 Subject: [PATCH] support json gem v3.x json 3.0 dropped the positional options argument from JSON.parse, so every call passing Fluent::DEFAULT_JSON_PARSE_OPTIONS now fails with ArgumentError: wrong number of arguments (given 2, expected 1). This breaks fluentd at startup because the config parser cannot read any JSON literal. Pass the options as keyword arguments instead, which works with both json 2.21 and 3.0. JSON::ResumableParser still accepts a positional hash, but switch it over as well so that the constant is always passed the same way. Signed-off-by: Shizuo Fujita --- lib/fluent/command/cat.rb | 2 +- lib/fluent/compat/exec_util.rb | 2 +- lib/fluent/config/literal_parser.rb | 4 ++-- lib/fluent/config/types.rb | 4 ++-- lib/fluent/daemon.rb | 2 +- lib/fluent/plugin/filter_record_transformer.rb | 2 +- lib/fluent/plugin/in_forward.rb | 2 +- lib/fluent/plugin/in_monitor_agent.rb | 2 +- lib/fluent/plugin/in_sample.rb | 2 +- lib/fluent/plugin/in_unix.rb | 2 +- lib/fluent/plugin/parser_json.rb | 4 ++-- lib/fluent/plugin/sd_file.rb | 2 +- lib/fluent/plugin/storage_local.rb | 4 ++-- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/lib/fluent/command/cat.rb b/lib/fluent/command/cat.rb index d313c37472..ba0ab9c35a 100644 --- a/lib/fluent/command/cat.rb +++ b/lib/fluent/command/cat.rb @@ -326,7 +326,7 @@ def abort_message(time, record) when 'json' begin while line = $stdin.gets - record = JSON.parse(line, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + record = JSON.parse(line, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) w.write(record) end rescue diff --git a/lib/fluent/compat/exec_util.rb b/lib/fluent/compat/exec_util.rb index ac0f034459..c83b6da31f 100644 --- a/lib/fluent/compat/exec_util.rb +++ b/lib/fluent/compat/exec_util.rb @@ -80,7 +80,7 @@ class JSONParser < Parser BYTES_TO_READ = 8192 def call(io) - parser = JSON::ResumableParser.new(Fluent::DEFAULT_JSON_PARSE_OPTIONS) + parser = JSON::ResumableParser.new(**Fluent::DEFAULT_JSON_PARSE_OPTIONS) begin chunk = +"".b while io.readpartial(BYTES_TO_READ, chunk) diff --git a/lib/fluent/config/literal_parser.rb b/lib/fluent/config/literal_parser.rb index febe6f2bb5..eb6b0710ee 100644 --- a/lib/fluent/config/literal_parser.rb +++ b/lib/fluent/config/literal_parser.rb @@ -253,7 +253,7 @@ def scan_json(is_array) # '{"foo":"bar", #' -> '{"foo":"bar"}' (to check) parsed = nil begin - parsed = JSON.parse(buffer + line_buffer.rstrip.sub(/,$/, '') + (is_array ? "]" : "}"), Fluent::DEFAULT_JSON_PARSE_OPTIONS) + parsed = JSON.parse(buffer + line_buffer.rstrip.sub(/,$/, '') + (is_array ? "]" : "}"), **Fluent::DEFAULT_JSON_PARSE_OPTIONS) rescue JSON::ParserError # This '#' is in json string literals end @@ -288,7 +288,7 @@ def scan_json(is_array) line_buffer << char begin - result = JSON.parse(buffer + line_buffer, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + result = JSON.parse(buffer + line_buffer, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) rescue JSON::ParserError # Incomplete json string yet end diff --git a/lib/fluent/config/types.rb b/lib/fluent/config/types.rb index 2fe5cd4c8e..26f104e4dd 100644 --- a/lib/fluent/config/types.rb +++ b/lib/fluent/config/types.rb @@ -201,7 +201,7 @@ def self.hash_value(val, opts = {}, name = nil) return nil if val.nil? param = if val.is_a?(String) - val.start_with?('{') ? JSON.parse(val, Fluent::DEFAULT_JSON_PARSE_OPTIONS) : Hash[val.strip.split(/\s*,\s*/).map{|v| v.split(':', 2)}] + val.start_with?('{') ? JSON.parse(val, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) : Hash[val.strip.split(/\s*,\s*/).map{|v| v.split(':', 2)}] else val end @@ -228,7 +228,7 @@ def self.array_value(val, opts = {}, name = nil) return nil if val.nil? param = if val.is_a?(String) - val.start_with?('[') ? JSON.parse(val, Fluent::DEFAULT_JSON_PARSE_OPTIONS) : val.strip.split(/\s*,\s*/) + val.start_with?('[') ? JSON.parse(val, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) : val.strip.split(/\s*,\s*/) elsif val.is_a?(Array) val elsif val.is_a?(Numeric) || val == true || val == false diff --git a/lib/fluent/daemon.rb b/lib/fluent/daemon.rb index ed45758042..b76bbb9da1 100644 --- a/lib/fluent/daemon.rb +++ b/lib/fluent/daemon.rb @@ -10,5 +10,5 @@ server_module = Fluent.const_get(ARGV[0]) worker_module = Fluent.const_get(ARGV[1]) -params = JSON.parse(ARGV[2], Fluent::DEFAULT_JSON_PARSE_OPTIONS) +params = JSON.parse(ARGV[2], **Fluent::DEFAULT_JSON_PARSE_OPTIONS) ServerEngine::Daemon.run_server(server_module, worker_module) { Fluent::Supervisor.serverengine_config(params) } diff --git a/lib/fluent/plugin/filter_record_transformer.rb b/lib/fluent/plugin/filter_record_transformer.rb index 57e4cba260..bccb09299d 100644 --- a/lib/fluent/plugin/filter_record_transformer.rb +++ b/lib/fluent/plugin/filter_record_transformer.rb @@ -117,7 +117,7 @@ def filter_stream(tag, es) def parse_value(value_str) if value_str.start_with?('{', '[') - JSON.parse(value_str, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + JSON.parse(value_str, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) else value_str end diff --git a/lib/fluent/plugin/in_forward.rb b/lib/fluent/plugin/in_forward.rb index ba1c81aaf2..98a959faab 100644 --- a/lib/fluent/plugin/in_forward.rb +++ b/lib/fluent/plugin/in_forward.rb @@ -257,7 +257,7 @@ def read_messages(conn, &block) unless feeder first = data[0] if first == '{' || first == '[' # json - parser = JSON::ResumableParser.new(Fluent::DEFAULT_JSON_PARSE_OPTIONS) + parser = JSON::ResumableParser.new(**Fluent::DEFAULT_JSON_PARSE_OPTIONS) serializer = :to_json.to_proc feeder = ->(d){ parser << d diff --git a/lib/fluent/plugin/in_monitor_agent.rb b/lib/fluent/plugin/in_monitor_agent.rb index 3e743a50cc..e4cd5576ca 100644 --- a/lib/fluent/plugin/in_monitor_agent.rb +++ b/lib/fluent/plugin/in_monitor_agent.rb @@ -102,7 +102,7 @@ def render_json(obj, code: 200, pretty_json: nil) end def render_ltsv(obj, code: 200) - normalized = JSON.parse(obj.to_json, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + normalized = JSON.parse(obj.to_json, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) text = '' normalized.each do |hash| row = [] diff --git a/lib/fluent/plugin/in_sample.rb b/lib/fluent/plugin/in_sample.rb index a2b5b3926f..1bdc9821f9 100644 --- a/lib/fluent/plugin/in_sample.rb +++ b/lib/fluent/plugin/in_sample.rb @@ -45,7 +45,7 @@ class SampleInput < Input desc "The sample data to be generated. An array of JSON hashes or a single JSON hash." config_param :sample, alias: :dummy, default: [{"message" => "sample"}] do |val| begin - parsed = JSON.parse(val, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + parsed = JSON.parse(val, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) rescue JSON::ParserError => ex # Fluent::ConfigParseError, "got incomplete JSON" will be raised # at literal_parser.rb with --use-v1-config, but I had to diff --git a/lib/fluent/plugin/in_unix.rb b/lib/fluent/plugin/in_unix.rb index a9df09cfea..21ed482e07 100644 --- a/lib/fluent/plugin/in_unix.rb +++ b/lib/fluent/plugin/in_unix.rb @@ -158,7 +158,7 @@ def on_read(data) first = data[0] if first == '{'.freeze || first == '['.freeze m = method(:on_read_json) - @parser = JSON::ResumableParser.new(Fluent::DEFAULT_JSON_PARSE_OPTIONS) + @parser = JSON::ResumableParser.new(**Fluent::DEFAULT_JSON_PARSE_OPTIONS) else m = method(:on_read_msgpack) @parser = Fluent::MessagePackFactory.msgpack_unpacker diff --git a/lib/fluent/plugin/parser_json.rb b/lib/fluent/plugin/parser_json.rb index 8687dc4da2..45fe8607c7 100644 --- a/lib/fluent/plugin/parser_json.rb +++ b/lib/fluent/plugin/parser_json.rb @@ -38,7 +38,7 @@ class JSONParser < Parser # Use a shared proc rather than a per-call lambda so that # configure_json_parser returns the same object every time. - JSON_PARSE_PROC = ->(text) { JSON.parse(text, Fluent::DEFAULT_JSON_PARSE_OPTIONS) } + JSON_PARSE_PROC = ->(text) { JSON.parse(text, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) } def configure(conf) if conf.has_key?('time_format') @@ -96,7 +96,7 @@ def parser_type end def parse_io(io, &block) - parser = JSON::ResumableParser.new(Fluent::DEFAULT_JSON_PARSE_OPTIONS) + parser = JSON::ResumableParser.new(**Fluent::DEFAULT_JSON_PARSE_OPTIONS) begin chunk = +"".b while io.readpartial(@stream_buffer_size, chunk) diff --git a/lib/fluent/plugin/sd_file.rb b/lib/fluent/plugin/sd_file.rb index 0b30541c35..322f7814d0 100644 --- a/lib/fluent/plugin/sd_file.rb +++ b/lib/fluent/plugin/sd_file.rb @@ -76,7 +76,7 @@ def parser -> (v) { YAML.safe_load(v).map } when :json require 'json' - -> (v) { JSON.parse(v, Fluent::DEFAULT_JSON_PARSE_OPTIONS) } + -> (v) { JSON.parse(v, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) } end end diff --git a/lib/fluent/plugin/storage_local.rb b/lib/fluent/plugin/storage_local.rb index bc66c83d2e..8afb3f05eb 100644 --- a/lib/fluent/plugin/storage_local.rb +++ b/lib/fluent/plugin/storage_local.rb @@ -90,7 +90,7 @@ def configure(conf) log.warn "detect empty plugin storage file during startup. Ignored: #{@path}" return end - data = JSON.parse(data, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + data = JSON.parse(data, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) raise Fluent::ConfigError, "Invalid contents (not object) in plugin storage file: '#{@path}'" unless data.is_a?(Hash) rescue => e log.error "failed to read data from plugin storage file", path: @path, error: e @@ -114,7 +114,7 @@ def load return unless File.exist?(@path) begin json_string = File.open(@path, 'r:utf-8:utf-8'){ |io| io.read } - json = JSON.parse(json_string, Fluent::DEFAULT_JSON_PARSE_OPTIONS) + json = JSON.parse(json_string, **Fluent::DEFAULT_JSON_PARSE_OPTIONS) unless json.is_a?(Hash) log.error "broken content for plugin storage (Hash required: ignored)", type: json.class log.debug "broken content", content: json_string