Add strict mode to JSON parser (#6536)

This commit is contained in:
David McKay 2019-10-23 22:06:39 +01:00 committed by Daniel Nelson
parent 41d6a1a787
commit a9a0d4048a
4 changed files with 51 additions and 1 deletions

View File

@ -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.
##

View File

@ -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,8 +76,11 @@ func (p *Parser) parseArray(data []interface{}) ([]telegraf.Metric, error) {
case map[string]interface{}:
metrics, err := p.parseObject(v)
if err != nil {
if p.strict {
return nil, err
}
continue
}
results = append(results, metrics...)
default:
return nil, ErrWrongType

View File

@ -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{

View File

@ -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":