Skip to content

Commit

Permalink
added rename processor
Browse files Browse the repository at this point in the history
  • Loading branch information
goldibex committed Aug 7, 2018
1 parent 0759c8b commit 023f449
Show file tree
Hide file tree
Showing 5 changed files with 202 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ formats may be used with input plugins supporting the `data_format` option:
* [override](./plugins/processors/override)
* [printer](./plugins/processors/printer)
* [regex](./plugins/processors/regex)
* [rename](./plugins/processors/rename)
* [topk](./plugins/processors/topk)

## Aggregator Plugins
Expand Down
1 change: 1 addition & 0 deletions plugins/processors/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ import (
_ "github.com/influxdata/telegraf/plugins/processors/override"
_ "github.com/influxdata/telegraf/plugins/processors/printer"
_ "github.com/influxdata/telegraf/plugins/processors/regex"
_ "github.com/influxdata/telegraf/plugins/processors/rename"
_ "github.com/influxdata/telegraf/plugins/processors/topk"
)
41 changes: 41 additions & 0 deletions plugins/processors/rename/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Rename Processor Plugin

The `rename` processor renames measurements, fields, and tags.

### Configuration:

```toml
## Measurement, tag, and field renamings are stored in separate sub-tables.
## Specify one sub-table per rename operation.
[[processors.rename]]
[[processors.rename.measurement]]
## measurement to change
from = "network_interface_throughput"
to = "throughput"

[[processors.rename.tag]]
## tag to change
from = "hostname"
to = "host"

[[processors.rename.field]]
## field to change
from = "lower"
to = "min"

[[processors.rename.field]]
## field to change
from = "upper"
to = "max"
```

### Tags:

No tags are applied by this processor, though it can alter them by renaming.

### Example processing:

```diff
- network_interface_throughput,hostname=backend.example.com,units=kbps lower=10i,upper=1000i,mean=500i 1502489900000000000
+ throughput,host=backend.example.com,units=kbps min=10i,max=1000i,mean=500i 1502489900000000000
```
101 changes: 101 additions & 0 deletions plugins/processors/rename/rename.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package rename

import (
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
"sync"
)

const sampleConfig = `
## Measurement, tag, and field renamings are stored in separate sub-tables.
## Specify one sub-table per rename operation.
# [[processors.rename.measurement]]
# ## measurement to change
# from = "kilobytes_per_second"
# to = "kbps"
# [[processors.rename.tag]]
# ## tag to change
# from = "host"
# to = "hostname"
# [[processors.rename.field]]
# ## field to change
# from = "lower"
# to = "min"
# [[processors.rename.field]]
# ## field to change
# from = "upper"
# to = "max"
`

type renamer struct {
From string
To string
}

type Rename struct {
Measurement []renamer
Tag []renamer
Field []renamer
measurements map[string]string
tags map[string]string
fields map[string]string
once sync.Once
}

func (r *Rename) SampleConfig() string {
return sampleConfig
}

func (r *Rename) Description() string {
return "Rename measurements, tags, and fields that pass through this filter."
}

func (r *Rename) Apply(in ...telegraf.Metric) []telegraf.Metric {
r.once.Do(r.init)

for _, point := range in {
if newMeasurementName, ok := r.measurements[point.Name()]; ok {
point.SetName(newMeasurementName)
}
for oldTagName, tagValue := range point.Tags() {
if newTagName, ok := r.tags[oldTagName]; ok {
point.RemoveTag(oldTagName)
point.AddTag(newTagName, tagValue)
}
}
for oldFieldName, fieldValue := range point.Fields() {
if newFieldName, ok := r.fields[oldFieldName]; ok {
point.RemoveField(oldFieldName)
point.AddField(newFieldName, fieldValue)
}
}
}

return in
}

func (r *Rename) init() {
if r.measurements == nil || r.tags == nil || r.fields == nil {
r.measurements = make(map[string]string, len(r.Measurement))
for _, o := range r.Measurement {
r.measurements[o.From] = o.To
}
r.tags = make(map[string]string, len(r.Tag))
for _, o := range r.Tag {
r.tags[o.From] = o.To
}
r.fields = make(map[string]string, len(r.Field))
for _, o := range r.Field {
r.fields[o.From] = o.To
}
}
}

func init() {
processors.Add("rename", func() telegraf.Processor {
return &Rename{}
})
}
58 changes: 58 additions & 0 deletions plugins/processors/rename/rename_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package rename

import (
"testing"
"time"

"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/metric"
"github.com/stretchr/testify/assert"
)

func newMetric(name string, tags map[string]string, fields map[string]interface{}) telegraf.Metric {
if tags == nil {
tags = map[string]string{}
}
if fields == nil {
fields = map[string]interface{}{}
}
m, _ := metric.New(name, tags, fields, time.Now())
return m
}

func TestMeasurementRename(t *testing.T) {
r := Rename{}
r.Measurement = []renamer{
{From: "foo", To: "bar"},
{From: "baz", To: "quux"},
}
m1 := newMetric("foo", nil, nil)
m2 := newMetric("bar", nil, nil)
m3 := newMetric("baz", nil, nil)
results := r.Apply(m1, m2, m3)
assert.Equal(t, "bar", results[0].Name(), "Should change name from 'foo' to 'bar'")
assert.Equal(t, "bar", results[1].Name(), "Should not name from 'bar'")
assert.Equal(t, "quux", results[2].Name(), "Should change name from 'baz' to 'quux'")
}

func TestTagRename(t *testing.T) {
r := Rename{}
r.Tag = []renamer{
{From: "hostname", To: "host"},
}
m := newMetric("foo", map[string]string{"hostname": "localhost", "region": "east-1"}, nil)
results := r.Apply(m)

assert.Equal(t, map[string]string{"host": "localhost", "region": "east-1"}, results[0].Tags(), "should change tag 'hostname' to 'host'")
}

func TestFieldRename(t *testing.T) {
r := Rename{}
r.Field = []renamer{
{From: "time_msec", To: "time"},
}
m := newMetric("foo", nil, map[string]interface{}{"time_msec": int64(1250), "snakes": true})
results := r.Apply(m)

assert.Equal(t, map[string]interface{}{"time": int64(1250), "snakes": true}, results[0].Fields(), "should change field 'time_msec' to 'time'")
}

0 comments on commit 023f449

Please sign in to comment.