fix(parsers.json_v2): Properly handle optional fields (#14008)

Co-authored-by: Christian Allinson <christian.allinson@rebuildmanufacturing.com>
This commit is contained in:
Christian Allinson 2023-10-02 01:29:11 -07:00 committed by GitHub
parent 3ffa5f615a
commit 69612a8e4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 107 additions and 17 deletions

View File

@ -210,8 +210,8 @@ func (p *Parser) processMetric(input []byte, data []DataSet, tag bool, timestamp
return nil, fmt.Errorf("GJSON path is required")
}
result := gjson.GetBytes(input, c.Path)
if skip, err := p.checkResult(result, c.Path, c.Optional); err != nil {
if skip {
if err := p.checkResult(result, c.Path); err != nil {
if c.Optional {
continue
}
return nil, err
@ -456,8 +456,8 @@ func (p *Parser) processObjects(input []byte, objects []Object, timestamp time.T
}
result := gjson.GetBytes(input, c.Path)
if skip, err := p.checkResult(result, c.Path, c.Optional); err != nil {
if skip {
if err := p.checkResult(result, c.Path); err != nil {
if c.Optional {
continue
}
return nil, err
@ -467,8 +467,8 @@ func (p *Parser) processObjects(input []byte, objects []Object, timestamp time.T
for _, f := range c.FieldPaths {
var r PathResult
r.result = gjson.GetBytes(scopedJSON, f.Path)
if skip, err := p.checkResult(r.result, f.Path, f.Optional); err != nil {
if skip {
if err := p.checkResult(r.result, f.Path); err != nil {
if f.Optional {
continue
}
return nil, err
@ -480,8 +480,8 @@ func (p *Parser) processObjects(input []byte, objects []Object, timestamp time.T
for _, f := range c.TagPaths {
var r PathResult
r.result = gjson.GetBytes(scopedJSON, f.Path)
if skip, err := p.checkResult(r.result, f.Path, f.Optional); err != nil {
if skip {
if err := p.checkResult(r.result, f.Path); err != nil {
if f.Optional {
continue
}
return nil, err
@ -700,18 +700,14 @@ func (p *Parser) convertType(input gjson.Result, desiredType string, name string
return input.Value(), nil
}
func (p *Parser) checkResult(result gjson.Result, path string, optional bool) (bool, error) {
// Check if gjson result exists and return error if it does not
func (p *Parser) checkResult(result gjson.Result, path string) error {
if !result.Exists() {
if optional {
// If path is marked as optional don't error if path doesn't return a result
p.Log.Debugf("the path %q doesn't exist", path)
return true, nil
}
return false, fmt.Errorf("the path %q doesn't exist", path)
p.Log.Debugf("the path %q doesn't exist", path)
return fmt.Errorf("the path %q doesn't exist", path)
}
return false, nil
return nil
}
func init() {

View File

@ -0,0 +1,5 @@
file,datatype=float,name=inlet-1/temperature value_f=0.20791169081775931 1695679023000000000
file,datatype=float value_f=-0.3090169943749477,name="inlet-1/temperature" 1695679077000000000
file,datatype=string value_s="-0.3090169943749477",name="inlet-3/flow" 1695679077000000000
file,datatype=int value_i=95i,name="inlet-2/temperature" 1695679077000000000
file,datatype=bool value_b=true,name="inlet-2/flow" 1695679077000000000

View File

@ -0,0 +1,25 @@
{
"timestamp": 1695679077118.0,
"metrics": [
{
"value": -0.3090169943749477,
"name": "inlet-1/temperature",
"datatype": "float"
},
{
"value": 95,
"name": "inlet-2/temperature",
"datatype": "int"
},
{
"value": true,
"name": "inlet-2/flow",
"datatype": "bool"
},
{
"value": "-0.3090169943749477",
"name": "inlet-3/flow",
"datatype": "string"
}
]
}

View File

@ -0,0 +1,6 @@
{
"timestamp": 1695679022882.0,
"value": 0.20791169081775931,
"name": "inlet-1/temperature",
"datatype": "float"
}

View File

@ -0,0 +1,58 @@
# Example taken from: https://github.com/influxdata/telegraf/issues/13990
# Parse String types from JSON
[[inputs.file]]
files = ["./testdata/nested_objects_optional/nested_objects_single.json", "./testdata/nested_objects_optional/nested_objects_nest.json"]
data_format = "json_v2"
[[inputs.file.json_v2]]
timestamp_path = 'timestamp'
timestamp_format = 'unix_ms'
[[inputs.file.json_v2.tag]]
path = 'name'
optional = true
[[inputs.file.json_v2.tag]]
path = 'datatype'
optional = true
[[inputs.file.json_v2.field]]
path = 'value'
rename = 'value_f'
optional = true
[[inputs.file.json_v2.object]]
path = 'metrics.#(datatype=="float")#'
optional = true
tags = ['datatype']
[inputs.file.json_v2.object.renames]
value = 'value_f'
[inputs.file.json_v2.object.fields]
value = 'float'
[[inputs.file.json_v2.object]]
path = 'metrics.#(datatype=="string")#'
optional = true
tags = ['datatype']
[inputs.file.json_v2.object.renames]
value = 'value_s'
[inputs.file.json_v2.object.fields]
value = 'string'
[[inputs.file.json_v2.object]]
path = 'metrics.#(datatype=="int")#'
optional = true
tags = ['datatype']
[inputs.file.json_v2.object.renames]
value = 'value_i'
[inputs.file.json_v2.object.fields]
value = 'int'
[[inputs.file.json_v2.object]]
path = 'metrics.#(datatype=="bool")#'
optional = true
tags = ['datatype']
[inputs.file.json_v2.object.renames]
value = 'value_b'
[inputs.file.json_v2.object.fields]
value = 'bool'