diff --git a/plugins/processors/template/README.md b/plugins/processors/template/README.md index 909e5abbf..7e75a3f7f 100644 --- a/plugins/processors/template/README.md +++ b/plugins/processors/template/README.md @@ -24,12 +24,14 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. ```toml @sample.conf # Uses a Go template to create a new tag [[processors.template]] - ## Tag to set with the output of the template. + ## Go template used to create the tag name of the output. In order to + ## ease TOML escaping requirements, you should use single quotes around + ## the template string. tag = "topic" - ## Go template used to create the tag value. In order to ease TOML - ## escaping requirements, you may wish to use single quotes around the - ## template string. + ## Go template used to create the tag value of the output. In order to + ## ease TOML escaping requirements, you should use single quotes around + ## the template string. template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}' ``` @@ -48,6 +50,19 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details. + cpu,level=debug,hostname=localhost,topic=localhost.debug time_idle=42 ``` +### Use a field value as tag name + +```toml +[[processors.template]] + tag = '{{ .Field "type" }}' + template = '{{ .Name }}' +``` + +```diff +- cpu,level=debug,hostname=localhost time_idle=42,type=sensor ++ cpu,level=debug,hostname=localhost,sensor=cpu time_idle=42,type=sensor +``` + ### Add measurement name as a tag ```toml diff --git a/plugins/processors/template/sample.conf b/plugins/processors/template/sample.conf index aded7faf4..bed6b79b4 100644 --- a/plugins/processors/template/sample.conf +++ b/plugins/processors/template/sample.conf @@ -1,9 +1,11 @@ # Uses a Go template to create a new tag [[processors.template]] - ## Tag to set with the output of the template. + ## Go template used to create the tag name of the output. In order to + ## ease TOML escaping requirements, you should use single quotes around + ## the template string. tag = "topic" - ## Go template used to create the tag value. In order to ease TOML - ## escaping requirements, you may wish to use single quotes around the - ## template string. + ## Go template used to create the tag value of the output. In order to + ## ease TOML escaping requirements, you should use single quotes around + ## the template string. template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}' diff --git a/plugins/processors/template/template.go b/plugins/processors/template/template.go index 8a6c033df..06d931023 100644 --- a/plugins/processors/template/template.go +++ b/plugins/processors/template/template.go @@ -3,6 +3,7 @@ package template import ( _ "embed" + "fmt" "strings" "text/template" @@ -17,7 +18,9 @@ type TemplateProcessor struct { Tag string `toml:"tag"` Template string `toml:"template"` Log telegraf.Logger `toml:"-"` - tmpl *template.Template + + tmplTag *template.Template + tmplValue *template.Template } func (*TemplateProcessor) SampleConfig() string { @@ -27,27 +30,40 @@ func (*TemplateProcessor) SampleConfig() string { func (r *TemplateProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric { // for each metric in "in" array for _, metric := range in { - var b strings.Builder newM := TemplateMetric{metric} - // supply TemplateMetric and Template from configuration to Template.Execute - err := r.tmpl.Execute(&b, &newM) - if err != nil { - r.Log.Errorf("failed to execute template: %v", err) + var b strings.Builder + if err := r.tmplTag.Execute(&b, &newM); err != nil { + r.Log.Errorf("failed to execute tag name template: %v", err) continue } + tag := b.String() - metric.AddTag(r.Tag, b.String()) + b.Reset() + if err := r.tmplValue.Execute(&b, &newM); err != nil { + r.Log.Errorf("failed to execute value template: %v", err) + continue + } + value := b.String() + + metric.AddTag(tag, value) } return in } func (r *TemplateProcessor) Init() error { - // create template - t, err := template.New("configured_template").Parse(r.Template) + var err error - r.tmpl = t - return err + r.tmplTag, err = template.New("tag template").Parse(r.Tag) + if err != nil { + return fmt.Errorf("creating tag name template failed: %w", err) + } + + r.tmplValue, err = template.New("value template").Parse(r.Template) + if err != nil { + return fmt.Errorf("creating value template failed: %w", err) + } + return nil } func init() { diff --git a/plugins/processors/template/template_test.go b/plugins/processors/template/template_test.go index 8ee32c525..af533d98f 100644 --- a/plugins/processors/template/template_test.go +++ b/plugins/processors/template/template_test.go @@ -46,6 +46,43 @@ func TestName(t *testing.T) { testutil.RequireMetricsEqual(t, expected, actual) } +func TestNameTemplate(t *testing.T) { + plugin := TemplateProcessor{ + Tag: `{{ .Tag "foo" }}`, + Template: `{{ .Name }}`, + } + + err := plugin.Init() + require.NoError(t, err) + + input := []telegraf.Metric{ + testutil.MustMetric( + "cpu", + map[string]string{"foo": "measurement"}, + map[string]interface{}{ + "time_idle": 42, + }, + time.Unix(0, 0), + ), + } + + actual := plugin.Apply(input...) + expected := []telegraf.Metric{ + testutil.MustMetric( + "cpu", + map[string]string{ + "foo": "measurement", + "measurement": "cpu", + }, + map[string]interface{}{ + "time_idle": 42, + }, + time.Unix(0, 0), + ), + } + testutil.RequireMetricsEqual(t, expected, actual) +} + func TestTagTemplateConcatenate(t *testing.T) { now := time.Now()