From eff7f0f0830f4ac19b891ecaf90463c2ebb211fd Mon Sep 17 00:00:00 2001 From: Daniel Nelson Date: Tue, 11 Sep 2018 16:03:47 -0700 Subject: [PATCH] Use operation subtables in enum and rename processors (#4672) --- plugins/processors/enum/README.md | 20 ++++--- plugins/processors/enum/enum.go | 33 ++++++------ plugins/processors/enum/enum_test.go | 14 ++--- plugins/processors/rename/README.md | 35 ++++++------ plugins/processors/rename/rename.go | 69 ++++++++++-------------- plugins/processors/rename/rename_test.go | 23 ++++---- 6 files changed, 93 insertions(+), 101 deletions(-) diff --git a/plugins/processors/enum/README.md b/plugins/processors/enum/README.md index f0ed58566..291c25c8f 100644 --- a/plugins/processors/enum/README.md +++ b/plugins/processors/enum/README.md @@ -13,13 +13,13 @@ source field is overwritten. ```toml [[processors.enum]] - [[processors.enum.fields]] + [[processors.enum.mapping]] ## Name of the field to map - source = "name" + field = "status" ## Destination field to be used for the mapped value. By default the source ## field is used, overwriting the original value. - # destination = "mapped" + # 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 @@ -27,7 +27,15 @@ source field is overwritten. # default = 0 ## Table of mappings - [processors.enum.fields.value_mappings] - value1 = 1 - value2 = 2 + [processors.enum.mapping.value_mappings] + green = 1 + amber = 2 + red = 3 +``` + +### Example: + +```diff +- xyzzy status="green" 1502489900000000000 ++ xyzzy status="green",status_code=1i 1502489900000000000 ``` diff --git a/plugins/processors/enum/enum.go b/plugins/processors/enum/enum.go index 134a02bb1..b08307f09 100644 --- a/plugins/processors/enum/enum.go +++ b/plugins/processors/enum/enum.go @@ -8,13 +8,13 @@ import ( ) var sampleConfig = ` - [[processors.enum.fields]] + [[processors.enum.mapping]] ## Name of the field to map - source = "name" + field = "status" ## Destination field to be used for the mapped value. By default the source ## field is used, overwriting the original value. - # destination = "mapped" + # 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 @@ -22,18 +22,19 @@ var sampleConfig = ` # default = 0 ## Table of mappings - [processors.enum.fields.value_mappings] - value1 = 1 - value2 = 2 + [processors.enum.mapping.value_mappings] + green = 1 + yellow = 2 + red = 3 ` type EnumMapper struct { - Fields []Mapping + Mappings []Mapping `toml:"mapping"` } type Mapping struct { - Source string - Destination string + Field string + Dest string Default interface{} ValueMappings map[string]interface{} } @@ -54,8 +55,8 @@ func (mapper *EnumMapper) Apply(in ...telegraf.Metric) []telegraf.Metric { } func (mapper *EnumMapper) applyMappings(metric telegraf.Metric) telegraf.Metric { - for _, mapping := range mapper.Fields { - if originalValue, isPresent := metric.GetField(mapping.Source); isPresent == true { + 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) @@ -84,16 +85,14 @@ func (mapping *Mapping) mapValue(original string) (interface{}, bool) { } func (mapping *Mapping) getDestination() string { - if mapping.Destination != "" { - return mapping.Destination + if mapping.Dest != "" { + return mapping.Dest } - return mapping.Source + return mapping.Field } func writeField(metric telegraf.Metric, name string, value interface{}) { - if metric.HasField(name) { - metric.RemoveField(name) - } + metric.RemoveField(name) metric.AddField(name, value) } diff --git a/plugins/processors/enum/enum_test.go b/plugins/processors/enum/enum_test.go index 2185b91b6..d8c0e26de 100644 --- a/plugins/processors/enum/enum_test.go +++ b/plugins/processors/enum/enum_test.go @@ -49,7 +49,7 @@ func TestRetainsMetric(t *testing.T) { } func TestMapsSingleStringValue(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "string_value", ValueMappings: map[string]interface{}{"test": int64(1)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "string_value", ValueMappings: map[string]interface{}{"test": int64(1)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) @@ -57,7 +57,7 @@ func TestMapsSingleStringValue(t *testing.T) { } func TestNoFailureOnMappingsOnNonStringValuedFields(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "int_value", ValueMappings: map[string]interface{}{"13i": int64(7)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "int_value", ValueMappings: map[string]interface{}{"13i": int64(7)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) @@ -65,7 +65,7 @@ func TestNoFailureOnMappingsOnNonStringValuedFields(t *testing.T) { } func TestMapSingleBoolValue(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "true_value", ValueMappings: map[string]interface{}{"true": int64(1)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "true_value", ValueMappings: map[string]interface{}{"true": int64(1)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) @@ -73,7 +73,7 @@ func TestMapSingleBoolValue(t *testing.T) { } func TestMapsToDefaultValueOnUnknownSourceValue(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "string_value", Default: int64(42), ValueMappings: map[string]interface{}{"other": int64(1)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "string_value", Default: int64(42), ValueMappings: map[string]interface{}{"other": int64(1)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) @@ -81,7 +81,7 @@ func TestMapsToDefaultValueOnUnknownSourceValue(t *testing.T) { } func TestDoNotMapToDefaultValueKnownSourceValue(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "string_value", Default: int64(42), ValueMappings: map[string]interface{}{"test": int64(1)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "string_value", Default: int64(42), ValueMappings: map[string]interface{}{"test": int64(1)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) @@ -89,7 +89,7 @@ func TestDoNotMapToDefaultValueKnownSourceValue(t *testing.T) { } func TestNoMappingWithoutDefaultOrDefinedMappingValue(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "string_value", ValueMappings: map[string]interface{}{"other": int64(1)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "string_value", ValueMappings: map[string]interface{}{"other": int64(1)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) @@ -97,7 +97,7 @@ func TestNoMappingWithoutDefaultOrDefinedMappingValue(t *testing.T) { } func TestWritesToDestination(t *testing.T) { - mapper := EnumMapper{Fields: []Mapping{{Source: "string_value", Destination: "string_code", ValueMappings: map[string]interface{}{"test": int64(1)}}}} + mapper := EnumMapper{Mappings: []Mapping{{Field: "string_value", Dest: "string_code", ValueMappings: map[string]interface{}{"test": int64(1)}}}} fields := calculateProcessedValues(mapper, createTestMetric()) diff --git a/plugins/processors/rename/README.md b/plugins/processors/rename/README.md index dbd31490e..cc3c61a94 100644 --- a/plugins/processors/rename/README.md +++ b/plugins/processors/rename/README.md @@ -5,28 +5,23 @@ The `rename` processor renames measurements, fields, and tags. ### Configuration: ```toml -## Measurement, tag, and field renamings are stored in separate sub-tables. -## Specify one sub-table per rename operation. [[processors.rename]] -[[processors.rename.measurement]] - ## measurement to change - from = "network_interface_throughput" - to = "throughput" + ## Specify one sub-table per rename operation. + [[processors.rename.replace]] + measurement = "network_interface_throughput" + dest = "throughput" -[[processors.rename.tag]] - ## tag to change - from = "hostname" - to = "host" + [[processors.rename.replace]] + tag = "hostname" + dest = "host" -[[processors.rename.field]] - ## field to change - from = "lower" - to = "min" + [[processors.rename.replace]] + field = "lower" + dest = "min" -[[processors.rename.field]] - ## field to change - from = "upper" - to = "max" + [[processors.rename.replace]] + field = "upper" + dest = "max" ``` ### Tags: @@ -36,6 +31,6 @@ No tags are applied by this processor, though it can alter them by renaming. ### Example processing: ```diff -- network_interface_throughput,hostname=backend.example.com,units=kbps lower=10i,upper=1000i,mean=500i 1502489900000000000 -+ throughput,host=backend.example.com,units=kbps min=10i,max=1000i,mean=500i 1502489900000000000 +- network_interface_throughput,hostname=backend.example.com lower=10i,upper=1000i,mean=500i 1502489900000000000 ++ throughput,host=backend.example.com min=10i,max=1000i,mean=500i 1502489900000000000 ``` diff --git a/plugins/processors/rename/rename.go b/plugins/processors/rename/rename.go index 2da787a35..acb6d2ccc 100644 --- a/plugins/processors/rename/rename.go +++ b/plugins/processors/rename/rename.go @@ -6,38 +6,17 @@ import ( ) const sampleConfig = ` - ## Measurement, tag, and field renamings are stored in separate sub-tables. - ## Specify one sub-table per rename operation. - # [[processors.rename.measurement]] - # ## measurement to change - # from = "kilobytes_per_second" - # to = "kbps" - - # [[processors.rename.tag]] - # ## tag to change - # from = "host" - # to = "hostname" - - # [[processors.rename.field]] - # ## field to change - # from = "lower" - # to = "min" - - # [[processors.rename.field]] - # ## field to change - # from = "upper" - # to = "max" ` -type renamer struct { - From string - To string +type Replace struct { + Measurement string `toml:"measurement"` + Tag string `toml:"tag"` + Field string `toml:"field"` + Dest string `toml:"dest"` } type Rename struct { - Measurement []renamer - Tag []renamer - Field []renamer + Replaces []Replace `toml:"replace"` } func (r *Rename) SampleConfig() string { @@ -50,24 +29,32 @@ func (r *Rename) Description() string { func (r *Rename) Apply(in ...telegraf.Metric) []telegraf.Metric { for _, point := range in { - for _, measurementRenamer := range r.Measurement { - if point.Name() == measurementRenamer.From { - point.SetName(measurementRenamer.To) - break + for _, replace := range r.Replaces { + if replace.Dest == "" { + continue } - } - for _, tagRenamer := range r.Tag { - if value, ok := point.GetTag(tagRenamer.From); ok { - point.RemoveTag(tagRenamer.From) - point.AddTag(tagRenamer.To, value) + if replace.Measurement != "" { + if value := point.Name(); value == replace.Measurement { + point.SetName(replace.Dest) + } + continue } - } - for _, fieldRenamer := range r.Field { - if value, ok := point.GetField(fieldRenamer.From); ok { - point.RemoveField(fieldRenamer.From) - point.AddField(fieldRenamer.To, value) + if replace.Tag != "" { + if value, ok := point.GetTag(replace.Tag); ok { + point.RemoveTag(replace.Tag) + point.AddTag(replace.Dest, value) + } + continue + } + + if replace.Field != "" { + if value, ok := point.GetField(replace.Field); ok { + point.RemoveField(replace.Field) + point.AddField(replace.Dest, value) + } + continue } } } diff --git a/plugins/processors/rename/rename_test.go b/plugins/processors/rename/rename_test.go index 43f7fcc30..1f8e0b7db 100644 --- a/plugins/processors/rename/rename_test.go +++ b/plugins/processors/rename/rename_test.go @@ -21,10 +21,11 @@ func newMetric(name string, tags map[string]string, fields map[string]interface{ } func TestMeasurementRename(t *testing.T) { - r := Rename{} - r.Measurement = []renamer{ - {From: "foo", To: "bar"}, - {From: "baz", To: "quux"}, + r := Rename{ + Replaces: []Replace{ + {Measurement: "foo", Dest: "bar"}, + {Measurement: "baz", Dest: "quux"}, + }, } m1 := newMetric("foo", nil, nil) m2 := newMetric("bar", nil, nil) @@ -36,9 +37,10 @@ func TestMeasurementRename(t *testing.T) { } func TestTagRename(t *testing.T) { - r := Rename{} - r.Tag = []renamer{ - {From: "hostname", To: "host"}, + r := Rename{ + Replaces: []Replace{ + {Tag: "hostname", Dest: "host"}, + }, } m := newMetric("foo", map[string]string{"hostname": "localhost", "region": "east-1"}, nil) results := r.Apply(m) @@ -47,9 +49,10 @@ func TestTagRename(t *testing.T) { } func TestFieldRename(t *testing.T) { - r := Rename{} - r.Field = []renamer{ - {From: "time_msec", To: "time"}, + r := Rename{ + Replaces: []Replace{ + {Field: "time_msec", Dest: "time"}, + }, } m := newMetric("foo", nil, map[string]interface{}{"time_msec": int64(1250), "snakes": true}) results := r.Apply(m)