parent
26e0a4bbde
commit
5c1b635229
|
@ -1,5 +1,12 @@
|
|||
# Telegraf Input Data Formats
|
||||
|
||||
Telegraf is able to parse the following input data formats into metrics:
|
||||
|
||||
1. InfluxDB Line Protocol
|
||||
1. JSON
|
||||
1. Graphite
|
||||
1. Value, ie 45 or "booyah"
|
||||
|
||||
Telegraf metrics, like InfluxDB
|
||||
[points](https://docs.influxdata.com/influxdb/v0.10/write_protocols/line/),
|
||||
are a combination of four basic parts:
|
||||
|
@ -134,6 +141,38 @@ Your Telegraf metrics would get tagged with "my_tag_1"
|
|||
exec_mycollector,my_tag_1=foo a=5,b_c=6
|
||||
```
|
||||
|
||||
## Value:
|
||||
|
||||
The "value" data format translates single values into Telegraf metrics. This
|
||||
is done by assigning a measurement name (which can be overridden using the
|
||||
`name_override` config option), and setting a single field ("value") as the
|
||||
parsed metric.
|
||||
|
||||
#### Value Configuration:
|
||||
|
||||
You can tell Telegraf what type of metric to collect by using the `data_type`
|
||||
configuration option.
|
||||
|
||||
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 name of the
|
||||
plugin.
|
||||
|
||||
```toml
|
||||
[[inputs.exec]]
|
||||
## Commands array
|
||||
commands = ["cat /proc/sys/kernel/random/entropy_avail"]
|
||||
|
||||
## override the default metric name of "exec"
|
||||
name_override = "entropy_available"
|
||||
|
||||
## Data format to consume. This can be "json", "value", influx" or "graphite"
|
||||
## Each data format has it's own unique set of configuration options, read
|
||||
## more about them here:
|
||||
## https://github.com/influxdata/telegraf/blob/master/docs/DATA_FORMATS_INPUT.md
|
||||
data_format = "value"
|
||||
data_type = "integer"
|
||||
```
|
||||
|
||||
## Graphite:
|
||||
|
||||
The Graphite data format translates graphite _dot_ buckets directly into
|
||||
|
|
|
@ -701,12 +701,21 @@ func buildParser(name string, tbl *ast.Table) (parsers.Parser, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if node, ok := tbl.Fields["data_type"]; ok {
|
||||
if kv, ok := node.(*ast.KeyValue); ok {
|
||||
if str, ok := kv.Value.(*ast.String); ok {
|
||||
c.DataType = str.Value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.MetricName = name
|
||||
|
||||
delete(tbl.Fields, "data_format")
|
||||
delete(tbl.Fields, "separator")
|
||||
delete(tbl.Fields, "templates")
|
||||
delete(tbl.Fields, "tag_keys")
|
||||
delete(tbl.Fields, "data_type")
|
||||
|
||||
return parsers.NewParser(c)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/influxdata/telegraf/plugins/parsers/graphite"
|
||||
"github.com/influxdata/telegraf/plugins/parsers/influx"
|
||||
"github.com/influxdata/telegraf/plugins/parsers/json"
|
||||
"github.com/influxdata/telegraf/plugins/parsers/value"
|
||||
)
|
||||
|
||||
// ParserInput is an interface for input plugins that are able to parse
|
||||
|
@ -38,7 +39,7 @@ type Parser interface {
|
|||
// Config is a struct that covers the data types needed for all parser types,
|
||||
// and can be used to instantiate _any_ of the parsers.
|
||||
type Config struct {
|
||||
// Dataformat can be one of: json, influx, graphite
|
||||
// Dataformat can be one of: json, influx, graphite, value
|
||||
DataFormat string
|
||||
|
||||
// Separator only applied to Graphite data.
|
||||
|
@ -48,9 +49,12 @@ type Config struct {
|
|||
|
||||
// TagKeys only apply to JSON data
|
||||
TagKeys []string
|
||||
// MetricName only applies to JSON data. This will be the name of the measurement.
|
||||
// MetricName applies to JSON & value. This will be the name of the measurement.
|
||||
MetricName string
|
||||
|
||||
// DataType only applies to value, this will be the type to parse value to
|
||||
DataType string
|
||||
|
||||
// DefaultTags are the default tags that will be added to all parsed metrics.
|
||||
DefaultTags map[string]string
|
||||
}
|
||||
|
@ -63,6 +67,9 @@ func NewParser(config *Config) (Parser, error) {
|
|||
case "json":
|
||||
parser, err = NewJSONParser(config.MetricName,
|
||||
config.TagKeys, config.DefaultTags)
|
||||
case "value":
|
||||
parser, err = NewValueParser(config.MetricName,
|
||||
config.DataType, config.DefaultTags)
|
||||
case "influx":
|
||||
parser, err = NewInfluxParser()
|
||||
case "graphite":
|
||||
|
@ -98,3 +105,15 @@ func NewGraphiteParser(
|
|||
) (Parser, error) {
|
||||
return graphite.NewGraphiteParser(separator, templates, defaultTags)
|
||||
}
|
||||
|
||||
func NewValueParser(
|
||||
metricName string,
|
||||
dataType string,
|
||||
defaultTags map[string]string,
|
||||
) (Parser, error) {
|
||||
return &value.ValueParser{
|
||||
MetricName: metricName,
|
||||
DataType: dataType,
|
||||
DefaultTags: defaultTags,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package value
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/influxdata/telegraf"
|
||||
)
|
||||
|
||||
type ValueParser struct {
|
||||
MetricName string
|
||||
DataType string
|
||||
DefaultTags map[string]string
|
||||
}
|
||||
|
||||
func (v *ValueParser) Parse(buf []byte) ([]telegraf.Metric, error) {
|
||||
// separate out any fields in the buffer, ignore anything but the last.
|
||||
values := bytes.Fields(buf)
|
||||
if len(values) < 1 {
|
||||
return []telegraf.Metric{}, nil
|
||||
}
|
||||
valueStr := string(values[len(values)-1])
|
||||
|
||||
var value interface{}
|
||||
var err error
|
||||
switch v.DataType {
|
||||
case "", "int", "integer":
|
||||
value, err = strconv.Atoi(valueStr)
|
||||
case "float", "long":
|
||||
value, err = strconv.ParseFloat(valueStr, 64)
|
||||
case "str", "string":
|
||||
value = valueStr
|
||||
case "bool", "boolean":
|
||||
value, err = strconv.ParseBool(valueStr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fields := map[string]interface{}{"value": value}
|
||||
metric, err := telegraf.NewMetric(v.MetricName, v.DefaultTags,
|
||||
fields, time.Now().UTC())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return []telegraf.Metric{metric}, nil
|
||||
}
|
||||
|
||||
func (v *ValueParser) ParseLine(line string) (telegraf.Metric, error) {
|
||||
metrics, err := v.Parse([]byte(line))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(metrics) < 1 {
|
||||
return nil, fmt.Errorf("Can not parse the line: %s, for data format: value", line)
|
||||
}
|
||||
|
||||
return metrics[0], nil
|
||||
}
|
||||
|
||||
func (v *ValueParser) SetDefaultTags(tags map[string]string) {
|
||||
v.DefaultTags = tags
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
package value
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestParseValidValues(t *testing.T) {
|
||||
parser := ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "integer",
|
||||
}
|
||||
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: "float",
|
||||
}
|
||||
metrics, err = parser.Parse([]byte("64"))
|
||||
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),
|
||||
}, metrics[0].Fields())
|
||||
assert.Equal(t, map[string]string{}, metrics[0].Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "string",
|
||||
}
|
||||
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: "boolean",
|
||||
}
|
||||
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",
|
||||
DataType: "integer",
|
||||
}
|
||||
metrics, err := parser.Parse([]byte(`55
|
||||
45
|
||||
223
|
||||
12
|
||||
999
|
||||
`))
|
||||
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(999),
|
||||
}, metrics[0].Fields())
|
||||
assert.Equal(t, map[string]string{}, metrics[0].Tags())
|
||||
}
|
||||
|
||||
func TestParseLineValidValues(t *testing.T) {
|
||||
parser := ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "integer",
|
||||
}
|
||||
metric, err := parser.ParseLine("55")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "value_test", metric.Name())
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"value": int64(55),
|
||||
}, metric.Fields())
|
||||
assert.Equal(t, map[string]string{}, metric.Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "float",
|
||||
}
|
||||
metric, err = parser.ParseLine("64")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "value_test", metric.Name())
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"value": float64(64),
|
||||
}, metric.Fields())
|
||||
assert.Equal(t, map[string]string{}, metric.Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "string",
|
||||
}
|
||||
metric, err = parser.ParseLine("foobar")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "value_test", metric.Name())
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"value": "foobar",
|
||||
}, metric.Fields())
|
||||
assert.Equal(t, map[string]string{}, metric.Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "boolean",
|
||||
}
|
||||
metric, err = parser.ParseLine("true")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "value_test", metric.Name())
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"value": true,
|
||||
}, metric.Fields())
|
||||
assert.Equal(t, map[string]string{}, metric.Tags())
|
||||
}
|
||||
|
||||
func TestParseInvalidValues(t *testing.T) {
|
||||
parser := ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "integer",
|
||||
}
|
||||
metrics, err := parser.Parse([]byte("55.0"))
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, metrics, 0)
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "float",
|
||||
}
|
||||
metrics, err = parser.Parse([]byte("foobar"))
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, metrics, 0)
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "boolean",
|
||||
}
|
||||
metrics, err = parser.Parse([]byte("213"))
|
||||
assert.Error(t, err)
|
||||
assert.Len(t, metrics, 0)
|
||||
}
|
||||
|
||||
func TestParseLineInvalidValues(t *testing.T) {
|
||||
parser := ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "integer",
|
||||
}
|
||||
_, err := parser.ParseLine("55.0")
|
||||
assert.Error(t, err)
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "float",
|
||||
}
|
||||
_, err = parser.ParseLine("foobar")
|
||||
assert.Error(t, err)
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "boolean",
|
||||
}
|
||||
_, err = parser.ParseLine("213")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestParseValidValuesDefaultTags(t *testing.T) {
|
||||
parser := ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "integer",
|
||||
}
|
||||
parser.SetDefaultTags(map[string]string{"test": "tag"})
|
||||
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{"test": "tag"}, metrics[0].Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "float",
|
||||
}
|
||||
parser.SetDefaultTags(map[string]string{"test": "tag"})
|
||||
metrics, err = parser.Parse([]byte("64"))
|
||||
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),
|
||||
}, metrics[0].Fields())
|
||||
assert.Equal(t, map[string]string{"test": "tag"}, metrics[0].Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "string",
|
||||
}
|
||||
parser.SetDefaultTags(map[string]string{"test": "tag"})
|
||||
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{"test": "tag"}, metrics[0].Tags())
|
||||
|
||||
parser = ValueParser{
|
||||
MetricName: "value_test",
|
||||
DataType: "boolean",
|
||||
}
|
||||
parser.SetDefaultTags(map[string]string{"test": "tag"})
|
||||
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{"test": "tag"}, metrics[0].Tags())
|
||||
}
|
Loading…
Reference in New Issue