Skip to content

Commit

Permalink
Add integer support to enum processor (influxdata#7483)
Browse files Browse the repository at this point in the history
  • Loading branch information
HarshitOnGitHub authored and idohalevi committed Sep 23, 2020
1 parent 70e920c commit 71c3285
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 25 deletions.
2 changes: 1 addition & 1 deletion plugins/processors/enum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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
_green_ by numeric values such as 0, 1, 2. The plugin supports string, int and bool
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
Expand Down
16 changes: 11 additions & 5 deletions plugins/processors/enum/enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (mapper *EnumMapper) applyMappings(metric telegraf.Metric) telegraf.Metric
for _, mapping := range mapper.Mappings {
if mapping.Field != "" {
if originalValue, isPresent := metric.GetField(mapping.Field); isPresent {
if adjustedValue, isString := adjustBoolValue(originalValue).(string); isString {
if adjustedValue, isString := adjustValue(originalValue).(string); isString {
if mappedValue, isMappedValuePresent := mapping.mapValue(adjustedValue); isMappedValuePresent {
writeField(metric, mapping.getDestination(), mappedValue)
}
Expand All @@ -86,11 +86,17 @@ func (mapper *EnumMapper) applyMappings(metric telegraf.Metric) telegraf.Metric
return metric
}

func adjustBoolValue(in interface{}) interface{} {
if mappedBool, isBool := in.(bool); isBool == true {
return strconv.FormatBool(mappedBool)
func adjustValue(in interface{}) interface{} {
switch val := in.(type) {
case bool:
return strconv.FormatBool(val)
case int64:
return strconv.FormatInt(val, 10)
case uint64:
return strconv.FormatUint(val, 10)
default:
return in
}
return in
}

func (mapping *Mapping) mapValue(original string) (interface{}, bool) {
Expand Down
63 changes: 44 additions & 19 deletions plugins/processors/enum/enum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ func createTestMetric() telegraf.Metric {
map[string]string{"tag": "tag_value"},
map[string]interface{}{
"string_value": "test",
"int_value": int(13),
"int_value": int(200),
"uint_value": uint(500),
"float_value": float64(3.14),
"true_value": true,
},
time.Now(),
Expand Down Expand Up @@ -52,21 +54,14 @@ func TestRetainsMetric(t *testing.T) {
fields := target.Fields()

assertFieldValue(t, "test", "string_value", fields)
assertFieldValue(t, 13, "int_value", fields)
assertFieldValue(t, 200, "int_value", fields)
assertFieldValue(t, 500, "uint_value", fields)
assertFieldValue(t, true, "true_value", fields)
assert.Equal(t, "m1", target.Name())
assert.Equal(t, source.Tags(), target.Tags())
assert.Equal(t, source.Time(), target.Time())
}

func TestMapsSingleStringValue(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Field: "string_value", ValueMappings: map[string]interface{}{"test": int64(1)}}}}

fields := calculateProcessedValues(mapper, createTestMetric())

assertFieldValue(t, 1, "string_value", fields)
}

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

Expand All @@ -75,20 +70,50 @@ func TestMapsSingleStringValueTag(t *testing.T) {
assertTagValue(t, "valuable", "tag", tags)
}

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

fields := calculateProcessedValues(mapper, createTestMetric())

assertFieldValue(t, 13, "int_value", fields)
assertFieldValue(t, float64(3.14), "float_value", fields)
}

func TestMapSingleBoolValue(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Field: "true_value", ValueMappings: map[string]interface{}{"true": int64(1)}}}}

fields := calculateProcessedValues(mapper, createTestMetric())

assertFieldValue(t, 1, "true_value", fields)
func TestMappings(t *testing.T) {
mappings := []map[string][]interface{}{
{
"field_name": []interface{}{"string_value"},
"target_values": []interface{}{"test", "test", "test", "not_test", "50", "true"},
"mapped_values": []interface{}{"test_1", 5, true, "test_1", 10, false},
"expected_values": []interface{}{"test_1", 5, true, "test", "test", "test"},
},
{
"field_name": []interface{}{"true_value"},
"target_value": []interface{}{"true", "true", "true", "false", "test", "5"},
"mapped_value": []interface{}{false, 1, "false", false, false, false},
"expected_value": []interface{}{false, 1, "false", true, true, true},
},
{
"field_name": []interface{}{"int_value"},
"target_value": []interface{}{"200", "200", "200", "200", "test", "5"},
"mapped_value": []interface{}{"http_ok", true, 1, float64(200.001), false, false},
"expected_value": []interface{}{"http_ok", true, 1, float64(200.001), 200, 200},
},
{
"field_name": []interface{}{"uint_value"},
"target_value": []interface{}{"500", "500", "500", "test", "false", "5"},
"mapped_value": []interface{}{"internal_error", 1, false, false, false, false},
"expected_value": []interface{}{"internal_error", 1, false, 500, 500, 500},
},
}

for _, mapping := range mappings {
field_name := mapping["field_name"][0].(string)
for index := range mapping["target_value"] {
mapper := EnumMapper{Mappings: []Mapping{{Field: field_name, ValueMappings: map[string]interface{}{mapping["target_value"][index].(string): mapping["mapped_value"][index]}}}}
fields := calculateProcessedValues(mapper, createTestMetric())
assertFieldValue(t, mapping["expected_value"][index], field_name, fields)
}
}
}

func TestMapsToDefaultValueOnUnknownSourceValue(t *testing.T) {
Expand Down

0 comments on commit 71c3285

Please sign in to comment.