Describe the bug
The JSON parser plugin can sometimes emit records as a string rather than as a Hash. Similar to #1279, the expectation of plugins further down the line is that the record it receives is always a Hash, but this contract is broken in some circumstances by the JSON plugin leading to some very difficult to diagnose bugs.
This happens because a string is considered valid JSON (SO) and the JSON parser (Oj at least) treats it as such and parses it successfully. But the thing it outputs from it's parsing is not a Hash type, it is a string, and at no point in the JSON parser does it throw if the record it is returning isn't a Hash object.
To Reproduce
If you setup a fluentd configmap which a super simple JSON filter setup:
<filter gearset.*>
@type parser
<parse>
@type json
json_parser oj
</parse>
replace_invalid_sequence true
key_name message
emit_invalid_record_to_error false
</filter>
When presented with a record which has {"message": "\"HELLO\""} it will parse it so that the resulting record is "HELLO" (i.e. not a Hash type, but just a string. This then causes errors in plugins further down the line (for example in my example this was followed by the Prometheus plugin which threw an error undefined method map' for #String:0x00007fdbb6b32308\nDid you mean? tap` which was rather hard to debug).
Expected behavior
I would of expected the parser plugin to call error out if the thing it was parsing is a string (i.e. the same behaviour you see if the parser failed to parse the JSON).
Potentially I would just expect us to check if values is a Hash on
But that might change behaviour in an unexpected way for people, so it might need to be a configuration value. It is this question what led me to doing an Issue rather than a PR
Your Environment
- Fluentd version: `fluentd 1.14.6`
- Operating system: `PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"`
- Kernel version: `5.10.102.1-microsoft-standard-WSL2`
Your Configuration
<source>
@type tail
read_from_head true
path /var/log/containers/__.log
pos_file /fluentd/pos/__.log.pos
tag gearset.x
<parse>
@type cri
</parse>
</source>
<filter gearset.*>
@type parser
<parse>
@type json
json_parser oj
</parse>
replace_invalid_sequence true
key_name message
emit_invalid_record_to_error false
</filter>
<filter gearset.*>
@type prometheus
<metric>
name na
type counter
desc NA
<labels>
tag ${tag}
</labels>
</metric>
</filter>
Note the plugin which causes the error is the JSON plugin because it is emitting records of string type, but it is the Prometheus plugin which is throwing the error because it is the next thing handling the records (and is not designed to be able to)
Your Error Log
dump an error event: error_class=NoMethodError error="undefined method `map' for #<String:0x00007fdbb6b32308>\nDid you mean? tap" location="/usr/local/bundle/gems/fluent-plugin-prometheus-2.0.3/lib/fluent/plugin/prometheus.rb:90:in `stringify_keys'" tag="gearset.x" time=2023-03-14 12:48:13.381801632 +0000 record="HELLO"
Additional context
No response
Describe the bug
The JSON parser plugin can sometimes emit records as a string rather than as a
Hash. Similar to #1279, the expectation of plugins further down the line is that the record it receives is always aHash, but this contract is broken in some circumstances by the JSON plugin leading to some very difficult to diagnose bugs.This happens because a string is considered valid JSON (SO) and the JSON parser (Oj at least) treats it as such and parses it successfully. But the thing it outputs from it's parsing is not a
Hashtype, it is a string, and at no point in the JSON parser does it throw if the record it is returning isn't aHashobject.To Reproduce
If you setup a fluentd configmap which a super simple JSON filter setup:
When presented with a record which has
{"message": "\"HELLO\""}it will parse it so that the resulting record is"HELLO"(i.e. not aHashtype, but just a string. This then causes errors in plugins further down the line (for example in my example this was followed by the Prometheus plugin which threw an errorundefined methodmap' for #String:0x00007fdbb6b32308\nDid you mean? tap` which was rather hard to debug).Expected behavior
I would of expected the parser plugin to call error out if the thing it was parsing is a string (i.e. the same behaviour you see if the parser failed to parse the JSON).
Potentially I would just expect us to check if
valuesis aHashonfluentd/lib/fluent/plugin/filter_parser.rb
Line 74 in d5df992
But that might change behaviour in an unexpected way for people, so it might need to be a configuration value. It is this question what led me to doing an Issue rather than a PR
Your Environment
Your Configuration
<source> @type tail read_from_head true path /var/log/containers/__.log pos_file /fluentd/pos/__.log.pos tag gearset.x <parse> @type cri </parse> </source> <filter gearset.*> @type parser <parse> @type json json_parser oj </parse> replace_invalid_sequence true key_name message emit_invalid_record_to_error false </filter> <filter gearset.*> @type prometheus <metric> name na type counter desc NA <labels> tag ${tag} </labels> </metric> </filter>Note the plugin which causes the error is the JSON plugin because it is emitting records of string type, but it is the Prometheus plugin which is throwing the error because it is the next thing handling the records (and is not designed to be able to)
Your Error Log
dump an error event: error_class=NoMethodError error="undefined method `map' for #<String:0x00007fdbb6b32308>\nDid you mean? tap" location="/usr/local/bundle/gems/fluent-plugin-prometheus-2.0.3/lib/fluent/plugin/prometheus.rb:90:in `stringify_keys'" tag="gearset.x" time=2023-03-14 12:48:13.381801632 +0000 record="HELLO"Additional context
No response