Add pivot and unpivot processors (#5991)

This commit is contained in:
Daniel Nelson
2019-06-14 15:26:56 -07:00
committed by GitHub
parent 7f04511c30
commit 1ea7863b9b
8 changed files with 386 additions and 2 deletions

View File

@@ -0,0 +1,30 @@
# Pivot Processor
You can use the `pivot` processor to rotate single valued metrics into a multi
field metric. This transformation often results in data that is more easily
to apply mathematical operators and comparisons between, and flatten into a
more compact representation for write operations with some output data
formats.
To perform the reverse operation use the [unpivot] processor.
### Configuration
```toml
[[processors.pivot]]
## Tag to use for naming the new field.
tag_key = "name"
## Field to use as the value of the new field.
value_key = "value"
```
### Example
```diff
- cpu,cpu=cpu0,name=time_idle value=42i
- cpu,cpu=cpu0,name=time_user value=43i
+ cpu,cpu=cpu0 time_idle=42i
+ cpu,cpu=cpu0 time_user=42i
```
[unpivot]: /plugins/processors/unpivot/README.md

View File

@@ -0,0 +1,54 @@
package pivot
import (
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/plugins/processors"
)
const (
description = "Rotate a single valued metric into a multi field metric"
sampleConfig = `
## Tag to use for naming the new field.
tag_key = "name"
## Field to use as the value of the new field.
value_key = "value"
`
)
type Pivot struct {
TagKey string `toml:"tag_key"`
ValueKey string `toml:"value_key"`
}
func (p *Pivot) SampleConfig() string {
return sampleConfig
}
func (p *Pivot) Description() string {
return description
}
func (p *Pivot) Apply(metrics ...telegraf.Metric) []telegraf.Metric {
for _, m := range metrics {
key, ok := m.GetTag(p.TagKey)
if !ok {
continue
}
value, ok := m.GetField(p.ValueKey)
if !ok {
continue
}
m.RemoveTag(p.TagKey)
m.RemoveField(p.ValueKey)
m.AddField(key, value)
}
return metrics
}
func init() {
processors.Add("pivot", func() telegraf.Processor {
return &Pivot{}
})
}

View File

@@ -0,0 +1,111 @@
package pivot
import (
"testing"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/testutil"
)
func TestPivot(t *testing.T) {
now := time.Now()
tests := []struct {
name string
pivot *Pivot
metrics []telegraf.Metric
expected []telegraf.Metric
}{
{
name: "simple",
pivot: &Pivot{
TagKey: "name",
ValueKey: "value",
},
metrics: []telegraf.Metric{
testutil.MustMetric("cpu",
map[string]string{
"name": "idle_time",
},
map[string]interface{}{
"value": int64(42),
},
now,
),
},
expected: []telegraf.Metric{
testutil.MustMetric("cpu",
map[string]string{},
map[string]interface{}{
"idle_time": int64(42),
},
now,
),
},
},
{
name: "missing tag",
pivot: &Pivot{
TagKey: "name",
ValueKey: "value",
},
metrics: []telegraf.Metric{
testutil.MustMetric("cpu",
map[string]string{
"foo": "idle_time",
},
map[string]interface{}{
"value": int64(42),
},
now,
),
},
expected: []telegraf.Metric{
testutil.MustMetric("cpu",
map[string]string{
"foo": "idle_time",
},
map[string]interface{}{
"value": int64(42),
},
now,
),
},
},
{
name: "missing field",
pivot: &Pivot{
TagKey: "name",
ValueKey: "value",
},
metrics: []telegraf.Metric{
testutil.MustMetric("cpu",
map[string]string{
"name": "idle_time",
},
map[string]interface{}{
"foo": int64(42),
},
now,
),
},
expected: []telegraf.Metric{
testutil.MustMetric("cpu",
map[string]string{
"name": "idle_time",
},
map[string]interface{}{
"foo": int64(42),
},
now,
),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
actual := tt.pivot.Apply(tt.metrics...)
testutil.RequireMetricsEqual(t, tt.expected, actual)
})
}
}