Add integer support to enum processor (#7483)

This commit is contained in:
Harshit Bansal 2020-05-12 00:06:21 +05:30 committed by GitHub
parent 134c84f45d
commit 568cb8e64c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 24 deletions

View File

@ -2,7 +2,7 @@
The Enum Processor allows the configuration of value mappings for metric tags or 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 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 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 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 used for all values, which are not contained in the value_mappings. The

View File

@ -63,7 +63,7 @@ func (mapper *EnumMapper) applyMappings(metric telegraf.Metric) telegraf.Metric
for _, mapping := range mapper.Mappings { for _, mapping := range mapper.Mappings {
if mapping.Field != "" { if mapping.Field != "" {
if originalValue, isPresent := metric.GetField(mapping.Field); isPresent { 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 { if mappedValue, isMappedValuePresent := mapping.mapValue(adjustedValue); isMappedValuePresent {
writeField(metric, mapping.getDestination(), mappedValue) writeField(metric, mapping.getDestination(), mappedValue)
} }
@ -86,11 +86,17 @@ func (mapper *EnumMapper) applyMappings(metric telegraf.Metric) telegraf.Metric
return metric return metric
} }
func adjustBoolValue(in interface{}) interface{} { func adjustValue(in interface{}) interface{} {
if mappedBool, isBool := in.(bool); isBool == true { switch val := in.(type) {
return strconv.FormatBool(mappedBool) 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) { func (mapping *Mapping) mapValue(original string) (interface{}, bool) {

View File

@ -14,7 +14,9 @@ func createTestMetric() telegraf.Metric {
map[string]string{"tag": "tag_value"}, map[string]string{"tag": "tag_value"},
map[string]interface{}{ map[string]interface{}{
"string_value": "test", "string_value": "test",
"int_value": int(13), "int_value": int(200),
"uint_value": uint(500),
"float_value": float64(3.14),
"true_value": true, "true_value": true,
}, },
time.Now(), time.Now(),
@ -52,21 +54,14 @@ func TestRetainsMetric(t *testing.T) {
fields := target.Fields() fields := target.Fields()
assertFieldValue(t, "test", "string_value", 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) assertFieldValue(t, true, "true_value", fields)
assert.Equal(t, "m1", target.Name()) assert.Equal(t, "m1", target.Name())
assert.Equal(t, source.Tags(), target.Tags()) assert.Equal(t, source.Tags(), target.Tags())
assert.Equal(t, source.Time(), target.Time()) 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) { func TestMapsSingleStringValueTag(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Tag: "tag", ValueMappings: map[string]interface{}{"tag_value": "valuable"}}}} mapper := EnumMapper{Mappings: []Mapping{{Tag: "tag", ValueMappings: map[string]interface{}{"tag_value": "valuable"}}}}
@ -75,20 +70,50 @@ func TestMapsSingleStringValueTag(t *testing.T) {
assertTagValue(t, "valuable", "tag", tags) assertTagValue(t, "valuable", "tag", tags)
} }
func TestNoFailureOnMappingsOnNonStringValuedFields(t *testing.T) { func TestNoFailureOnMappingsOnNonSupportedValuedFields(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Field: "int_value", ValueMappings: map[string]interface{}{"13i": int64(7)}}}} mapper := EnumMapper{Mappings: []Mapping{{Field: "float_value", ValueMappings: map[string]interface{}{"3.14": "pi"}}}}
fields := calculateProcessedValues(mapper, createTestMetric()) fields := calculateProcessedValues(mapper, createTestMetric())
assertFieldValue(t, 13, "int_value", fields) assertFieldValue(t, float64(3.14), "float_value", fields)
} }
func TestMapSingleBoolValue(t *testing.T) { func TestMappings(t *testing.T) {
mapper := EnumMapper{Mappings: []Mapping{{Field: "true_value", ValueMappings: map[string]interface{}{"true": int64(1)}}}} 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},
},
}
fields := calculateProcessedValues(mapper, createTestMetric()) for _, mapping := range mappings {
field_name := mapping["field_name"][0].(string)
assertFieldValue(t, 1, "true_value", fields) 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) { func TestMapsToDefaultValueOnUnknownSourceValue(t *testing.T) {