From 342d3d633a8c8d5db6ec5e501a9788aec961e89f Mon Sep 17 00:00:00 2001 From: Max U Date: Thu, 28 Jun 2018 14:33:38 -0700 Subject: [PATCH] initial jsonpath functionality --- plugins/parsers/jsonpath/parser.go | 76 +++++++++++++++++++++++++ plugins/parsers/jsonpath/parser_test.go | 39 +++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 plugins/parsers/jsonpath/parser.go create mode 100644 plugins/parsers/jsonpath/parser_test.go diff --git a/plugins/parsers/jsonpath/parser.go b/plugins/parsers/jsonpath/parser.go new file mode 100644 index 000000000..608c5907e --- /dev/null +++ b/plugins/parsers/jsonpath/parser.go @@ -0,0 +1,76 @@ +package jsonpath + +import ( + "encoding/json" + "log" + "reflect" + "strconv" + "time" + + "github.com/influxdata/telegraf" + "github.com/influxdata/telegraf/metric" + "github.com/jsonpath" +) + +type JSONPath struct { + MetricName string + TagPath map[string]string + FieldPath map[string]string +} + +func (j *JSONPath) Parse(buf []byte) ([]telegraf.Metric, error) { + tags := make(map[string]string) + fields := make(map[string]interface{}) + metrics := make([]telegraf.Metric, 0) + + //turn buf into json interface + var jsonData interface{} + json.Unmarshal(buf, &jsonData) + log.Printf("unmarshaled jsonData: %v", jsonData) + + for k, v := range j.TagPath { + c, err := jsonpath.JsonPathLookup(jsonData, v) + if err != nil { + log.Printf("E! Could not find JSON Path: %v", v) + } + cType := reflect.TypeOf(c) + + //if path returns multiple values, split each into a different metric + if cType.Kind() == reflect.Array { + log.Printf("E! Multiple return values for path: %v", v) + continue + } + + switch ct := c.(type) { + case string: + tags[k] = ct + case bool: + tags[k] = strconv.FormatBool(ct) + case float64: + tags[k] = strconv.FormatFloat(ct, 'f', -1, 64) + default: + log.Printf("E! [parsers.json] Unrecognized type %T", ct) + } + } + + for k, v := range j.FieldPath { + c, err := jsonpath.JsonPathLookup(jsonData, v) + if err != nil { + log.Printf("E! Could not find JSON Path: %v", v) + continue + } + + cType := reflect.TypeOf(c) + + //if path returns multiple values, split each into a different metric + if cType.Kind() == reflect.Array { + log.Printf("E! Multiple return values for path: %v", v) + continue + } + fields[k] = c + } + + m, _ := metric.New(j.MetricName, tags, fields, time.Now()) + metrics = append(metrics, m) + return metrics, nil +} diff --git a/plugins/parsers/jsonpath/parser_test.go b/plugins/parsers/jsonpath/parser_test.go new file mode 100644 index 000000000..c404758f8 --- /dev/null +++ b/plugins/parsers/jsonpath/parser_test.go @@ -0,0 +1,39 @@ +package jsonpath + +import ( + "log" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseJsonPath(t *testing.T) { + testString := `{ + "total_devices": 5, + "total_threads": 10, + "shares": { + "total": 5, + "accepted": 5, + "rejected": 0, + "avg_find_time": 4, + "tester": "work", + "tester2": "don't want this", + "tester3": { + "hello":"sup", + "fun":"money", + "break":9 + } + } + }` + + jsonParser := JSONPath{ + MetricName: "jsonpather", + TagPath: map[string]string{"total": "$.shares.tester3"}, + } + + metrics, err := jsonParser.Parse([]byte(testString)) + assert.NoError(t, err) + log.Printf("m[0] name: %v, tags: %v, fields: %v", metrics[0].Name(), metrics[0].Tags(), metrics[0].Fields()) + t.Error() + +}