Skip to content

Commit

Permalink
Value parser, for parsing a single value into a metric
Browse files Browse the repository at this point in the history
closes #849
  • Loading branch information
sparrc committed Mar 18, 2016
1 parent 26e0a4b commit 03289bb
Show file tree
Hide file tree
Showing 5 changed files with 355 additions and 2 deletions.
39 changes: 39 additions & 0 deletions docs/DATA_FORMATS_INPUT.md
Original file line number Diff line number Diff line change
@@ -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:
Expand Down Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
23 changes: 21 additions & 2 deletions plugins/parsers/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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
}
Expand All @@ -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":
Expand Down Expand Up @@ -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
}
68 changes: 68 additions & 0 deletions plugins/parsers/value/parser.go
Original file line number Diff line number Diff line change
@@ -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 first.
values := bytes.Fields(buf)
if len(values) < 1 {
return []telegraf.Metric{}, nil
}
valueStr := string(values[0])

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
}
Loading

0 comments on commit 03289bb

Please sign in to comment.