diff --git a/docs/DATA_FORMATS_INPUT.md b/docs/DATA_FORMATS_INPUT.md index 6a916711b..67bb9060b 100644 --- a/docs/DATA_FORMATS_INPUT.md +++ b/docs/DATA_FORMATS_INPUT.md @@ -150,8 +150,14 @@ as the parsed metric. #### Value Configuration: -You **must** tell Telegraf what type of metric to collect by using the -`data_type` configuration option. +You **should** tell Telegraf what type of metric to collect by using the +`data_type` configuration option. The options are: + +1. integer +1. float +1. string +1. boolean +1. auto (this will try parsing into the above types, in order) **Note:** It is also recommended that you set `name_override` to a measurement name that makes sense for your metric, otherwise it will just be set to the @@ -170,7 +176,7 @@ name of the plugin. ## more about them here: ## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md data_format = "value" - data_type = "integer" # required + data_type = "integer" ``` # Graphite: diff --git a/plugins/parsers/value/parser.go b/plugins/parsers/value/parser.go index 00673eced..966192057 100644 --- a/plugins/parsers/value/parser.go +++ b/plugins/parsers/value/parser.go @@ -26,7 +26,9 @@ func (v *ValueParser) Parse(buf []byte) ([]telegraf.Metric, error) { var value interface{} var err error switch v.DataType { - case "", "int", "integer": + case "", "auto": + value, err = autoParse(valueStr) + case "int", "integer": value, err = strconv.Atoi(valueStr) case "float", "long": value, err = strconv.ParseFloat(valueStr, 64) @@ -49,6 +51,30 @@ func (v *ValueParser) Parse(buf []byte) ([]telegraf.Metric, error) { return []telegraf.Metric{metric}, nil } +// autoParse tries to parse the given string into (in order): +// 1. integer +// 2. float +// 3. boolean +// 4. string +func autoParse(valueStr string) (interface{}, error) { + var value interface{} + var err error + // 1st try integer: + if value, err = strconv.Atoi(valueStr); err == nil { + return value, err + } + // 2nd try float: + if value, err = strconv.ParseFloat(valueStr, 64); err == nil { + return value, err + } + // 3rd try boolean: + if value, err = strconv.ParseBool(valueStr); err == nil { + return value, err + } + // 4th, none worked, so string + return valueStr, nil +} + func (v *ValueParser) ParseLine(line string) (telegraf.Metric, error) { metrics, err := v.Parse([]byte(line)) diff --git a/plugins/parsers/value/parser_test.go b/plugins/parsers/value/parser_test.go index f60787491..e871a090e 100644 --- a/plugins/parsers/value/parser_test.go +++ b/plugins/parsers/value/parser_test.go @@ -60,6 +60,60 @@ func TestParseValidValues(t *testing.T) { assert.Equal(t, map[string]string{}, metrics[0].Tags()) } +func TestParseAutoValues(t *testing.T) { + parser := ValueParser{ + MetricName: "value_test", + DataType: "auto", + } + metrics, err := parser.Parse([]byte("55")) + assert.NoError(t, err) + assert.Len(t, metrics, 1) + assert.Equal(t, "value_test", metrics[0].Name()) + assert.Equal(t, map[string]interface{}{ + "value": int64(55), + }, metrics[0].Fields()) + assert.Equal(t, map[string]string{}, metrics[0].Tags()) + + parser = ValueParser{ + MetricName: "value_test", + DataType: "auto", + } + metrics, err = parser.Parse([]byte("64.1")) + assert.NoError(t, err) + assert.Len(t, metrics, 1) + assert.Equal(t, "value_test", metrics[0].Name()) + assert.Equal(t, map[string]interface{}{ + "value": float64(64.1), + }, metrics[0].Fields()) + assert.Equal(t, map[string]string{}, metrics[0].Tags()) + + parser = ValueParser{ + MetricName: "value_test", + DataType: "auto", + } + metrics, err = parser.Parse([]byte("foobar")) + assert.NoError(t, err) + assert.Len(t, metrics, 1) + assert.Equal(t, "value_test", metrics[0].Name()) + assert.Equal(t, map[string]interface{}{ + "value": "foobar", + }, metrics[0].Fields()) + assert.Equal(t, map[string]string{}, metrics[0].Tags()) + + parser = ValueParser{ + MetricName: "value_test", + DataType: "auto", + } + metrics, err = parser.Parse([]byte("true")) + assert.NoError(t, err) + assert.Len(t, metrics, 1) + assert.Equal(t, "value_test", metrics[0].Name()) + assert.Equal(t, map[string]interface{}{ + "value": true, + }, metrics[0].Fields()) + assert.Equal(t, map[string]string{}, metrics[0].Tags()) +} + func TestParseMultipleValues(t *testing.T) { parser := ValueParser{ MetricName: "value_test",