From 034e20ad2ceb62f05e83029a0e81a7545317cdbd Mon Sep 17 00:00:00 2001 From: Greg <2653109+glinton@users.noreply.github.com> Date: Thu, 16 May 2019 16:59:19 -0600 Subject: [PATCH] Support tags in enum processor (#5855) --- plugins/processors/enum/README.md | 17 +++++----- plugins/processors/enum/enum.go | 47 +++++++++++++++++++++++----- plugins/processors/enum/enum_test.go | 19 +++++++++++ 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/plugins/processors/enum/README.md b/plugins/processors/enum/README.md index 20c6110a18337..29821e83dac9d 100644 --- a/plugins/processors/enum/README.md +++ b/plugins/processors/enum/README.md @@ -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: @@ -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 diff --git a/plugins/processors/enum/enum.go b/plugins/processors/enum/enum.go index b08307f0940ad..427b7fb435402 100644 --- a/plugins/processors/enum/enum.go +++ b/plugins/processors/enum/enum.go @@ -1,6 +1,7 @@ package enum import ( + "fmt" "strconv" "github.com/influxdata/telegraf" @@ -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 @@ -24,7 +28,7 @@ var sampleConfig = ` ## Table of mappings [processors.enum.mapping.value_mappings] green = 1 - yellow = 2 + amber = 2 red = 3 ` @@ -33,6 +37,7 @@ type EnumMapper struct { } type Mapping struct { + Tag string Field string Dest string Default interface{} @@ -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)) + } } } } @@ -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{} diff --git a/plugins/processors/enum/enum_test.go b/plugins/processors/enum/enum_test.go index d8c0e26de6924..06204523d559a 100644 --- a/plugins/processors/enum/enum_test.go +++ b/plugins/processors/enum/enum_test.go @@ -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() @@ -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)}}}}