Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support tags in enum processor #5855

Merged
merged 3 commits into from
May 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions plugins/processors/enum/README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Enum Processor Plugin

The Enum Processor allows the configuration of value mappings for metric fields.
The Enum Processor allows the configuration of value mappings for metric tags or fields.
The main use-case for this is to rewrite status codes such as _red_, _amber_ and
_green_ by numeric values such as 0, 1, 2. The plugin supports string and bool
types for the field values. Multiple Fields can be configured with separate
value mappings for each field. Default mapping values can be configured to be
types for the field values. Multiple tags or fields can be configured with separate
value mappings for each. Default mapping values can be configured to be
used for all values, which are not contained in the value_mappings. The
processor supports explicit configuration of a destination field. By default the
source field is overwritten.
processor supports explicit configuration of a destination tag or field. By default the
source tag or field is overwritten.

### Configuration:

Expand All @@ -17,8 +17,11 @@ source field is overwritten.
## Name of the field to map
field = "status"

## Destination field to be used for the mapped value. By default the source
## field is used, overwriting the original value.
## Name of the tag to map
# tag = "status"

## Destination tag or field to be used for the mapped value. By default the
## source tag or field is used, overwriting the original value.
dest = "status_code"

## Default value to be used for all values not contained in the mapping
Expand Down
47 changes: 39 additions & 8 deletions plugins/processors/enum/enum.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package enum

import (
"fmt"
"strconv"

"github.com/influxdata/telegraf"
Expand All @@ -12,9 +13,12 @@ var sampleConfig = `
## Name of the field to map
field = "status"

## Destination field to be used for the mapped value. By default the source
## field is used, overwriting the original value.
# dest = "status_code"
## Name of the tag to map
# tag = "status"

## Destination tag or field to be used for the mapped value. By default the
## source tag or field is used, overwriting the original value.
dest = "status_code"

## Default value to be used for all values not contained in the mapping
## table. When unset, the unmodified value for the field will be used if no
Expand All @@ -24,7 +28,7 @@ var sampleConfig = `
## Table of mappings
[processors.enum.mapping.value_mappings]
green = 1
yellow = 2
amber = 2
red = 3
`

Expand All @@ -33,6 +37,7 @@ type EnumMapper struct {
}

type Mapping struct {
Tag string
Field string
Dest string
Default interface{}
Expand All @@ -56,10 +61,24 @@ func (mapper *EnumMapper) Apply(in ...telegraf.Metric) []telegraf.Metric {

func (mapper *EnumMapper) applyMappings(metric telegraf.Metric) telegraf.Metric {
for _, mapping := range mapper.Mappings {
if originalValue, isPresent := metric.GetField(mapping.Field); isPresent == true {
if adjustedValue, isString := adjustBoolValue(originalValue).(string); isString == true {
if mappedValue, isMappedValuePresent := mapping.mapValue(adjustedValue); isMappedValuePresent == true {
writeField(metric, mapping.getDestination(), mappedValue)
if mapping.Field != "" {
if originalValue, isPresent := metric.GetField(mapping.Field); isPresent {
if adjustedValue, isString := adjustBoolValue(originalValue).(string); isString {
if mappedValue, isMappedValuePresent := mapping.mapValue(adjustedValue); isMappedValuePresent {
writeField(metric, mapping.getDestination(), mappedValue)
}
}
}
}
if mapping.Tag != "" {
if originalValue, isPresent := metric.GetTag(mapping.Tag); isPresent {
if mappedValue, isMappedValuePresent := mapping.mapValue(originalValue); isMappedValuePresent {
switch val := mappedValue.(type) {
case string:
writeTag(metric, mapping.getDestinationTag(), val)
default:
writeTag(metric, mapping.getDestinationTag(), fmt.Sprintf("%v", val))
}
}
}
}
Expand Down Expand Up @@ -91,11 +110,23 @@ func (mapping *Mapping) getDestination() string {
return mapping.Field
}

func (mapping *Mapping) getDestinationTag() string {
if mapping.Dest != "" {
return mapping.Dest
}
return mapping.Tag
}

func writeField(metric telegraf.Metric, name string, value interface{}) {
metric.RemoveField(name)
metric.AddField(name, value)
}

func writeTag(metric telegraf.Metric, name string, value string) {
metric.RemoveTag(name)
metric.AddTag(name, value)
}

func init() {
processors.Add("enum", func() telegraf.Processor {
return &EnumMapper{}
Expand Down
19 changes: 19 additions & 0 deletions plugins/processors/enum/enum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,23 @@ func calculateProcessedValues(mapper EnumMapper, metric telegraf.Metric) map[str
return processed[0].Fields()
}

func calculateProcessedTags(mapper EnumMapper, metric telegraf.Metric) map[string]string {
processed := mapper.Apply(metric)
return processed[0].Tags()
}

func assertFieldValue(t *testing.T, expected interface{}, field string, fields map[string]interface{}) {
value, present := fields[field]
assert.True(t, present, "value of field '"+field+"' was not present")
assert.EqualValues(t, expected, value)
}

func assertTagValue(t *testing.T, expected interface{}, tag string, tags map[string]string) {
value, present := tags[tag]
assert.True(t, present, "value of tag '"+tag+"' was not present")
assert.EqualValues(t, expected, value)
}

func TestRetainsMetric(t *testing.T) {
mapper := EnumMapper{}
source := createTestMetric()
Expand All @@ -56,6 +67,14 @@ func TestMapsSingleStringValue(t *testing.T) {
assertFieldValue(t, 1, "string_value", fields)
}

func TestMapsSingleStringValueTag(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Tag: "tag", ValueMappings: map[string]interface{}{"tag_value": "valuable"}}}}

tags := calculateProcessedTags(mapper, createTestMetric())

assertTagValue(t, "valuable", "tag", tags)
}

func TestNoFailureOnMappingsOnNonStringValuedFields(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Field: "int_value", ValueMappings: map[string]interface{}{"13i": int64(7)}}}}

Expand Down