diff --git a/plugins/parsers/json/README.md b/plugins/parsers/json/README.md index 08aeef18e..45f4a98c6 100644 --- a/plugins/parsers/json/README.md +++ b/plugins/parsers/json/README.md @@ -18,6 +18,10 @@ ignored unless specified in the `tag_key` or `json_string_fields` options. ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md data_format = "json" + ## When strict is true and a JSON array is being parsed, all objects within the + ## array must be valid + strict = false + ## Query is a GJSON path that specifies a specific chunk of JSON to be ## parsed, if not specified the whole document will be parsed. ## diff --git a/plugins/parsers/json/parser.go b/plugins/parsers/json/parser.go index fb64997fe..ae8c15c0d 100644 --- a/plugins/parsers/json/parser.go +++ b/plugins/parsers/json/parser.go @@ -32,6 +32,7 @@ type Config struct { TimeFormat string Timezone string DefaultTags map[string]string + Strict bool } type Parser struct { @@ -44,6 +45,7 @@ type Parser struct { timeFormat string timezone string defaultTags map[string]string + strict bool } func New(config *Config) (*Parser, error) { @@ -62,6 +64,7 @@ func New(config *Config) (*Parser, error) { timeFormat: config.TimeFormat, timezone: config.Timezone, defaultTags: config.DefaultTags, + strict: config.Strict, }, nil } @@ -73,7 +76,10 @@ func (p *Parser) parseArray(data []interface{}) ([]telegraf.Metric, error) { case map[string]interface{}: metrics, err := p.parseObject(v) if err != nil { - return nil, err + if p.strict { + return nil, err + } + continue } results = append(results, metrics...) default: diff --git a/plugins/parsers/json/parser_test.go b/plugins/parsers/json/parser_test.go index 44ae73af5..0b9493b40 100644 --- a/plugins/parsers/json/parser_test.go +++ b/plugins/parsers/json/parser_test.go @@ -17,6 +17,7 @@ const ( validJSONArrayMultiple = "[{\"a\": 5, \"b\": {\"c\": 6}}, {\"a\": 7, \"b\": {\"c\": 8}}]" invalidJSON = "I don't think this is JSON" invalidJSON2 = "{\"a\": 5, \"b\": \"c\": 6}}" + mixedValidityJSON = "[{\"a\": 5, \"time\": \"2006-01-02T15:04:05\"}, {\"a\": 2}]" ) const validJSONTags = ` @@ -152,6 +153,41 @@ func TestParseInvalidJSON(t *testing.T) { require.Error(t, err) } +func TestParseJSONImplicitStrictness(t *testing.T) { + parserImplicitNoStrict, err := New(&Config{ + MetricName: "json_test", + TimeKey: "time", + }) + require.NoError(t, err) + + _, err = parserImplicitNoStrict.Parse([]byte(mixedValidityJSON)) + require.NoError(t, err) +} + +func TestParseJSONExplicitStrictnessFalse(t *testing.T) { + parserNoStrict, err := New(&Config{ + MetricName: "json_test", + TimeKey: "time", + Strict: false, + }) + require.NoError(t, err) + + _, err = parserNoStrict.Parse([]byte(mixedValidityJSON)) + require.NoError(t, err) +} + +func TestParseJSONExplicitStrictnessTrue(t *testing.T) { + parserStrict, err := New(&Config{ + MetricName: "json_test", + TimeKey: "time", + Strict: true, + }) + require.NoError(t, err) + + _, err = parserStrict.Parse([]byte(mixedValidityJSON)) + require.Error(t, err) +} + func TestParseWithTagKeys(t *testing.T) { // Test that strings not matching tag keys are ignored parser, err := New(&Config{ diff --git a/plugins/parsers/registry.go b/plugins/parsers/registry.go index 9e4ea2b1f..1c3af2763 100644 --- a/plugins/parsers/registry.go +++ b/plugins/parsers/registry.go @@ -89,6 +89,9 @@ type Config struct { // default timezone JSONTimezone string `toml:"json_timezone"` + // Whether to continue if a JSON object can't be coerced + JSONStrict bool `toml:"json_strict"` + // Authentication file for collectd CollectdAuthFile string `toml:"collectd_auth_file"` // One of none (default), sign, or encrypt @@ -164,6 +167,7 @@ func NewParser(config *Config) (Parser, error) { TimeFormat: config.JSONTimeFormat, Timezone: config.JSONTimezone, DefaultTags: config.DefaultTags, + Strict: config.JSONStrict, }, ) case "value":