feat(processors.template): Allow `tag` to be a template (#13253)
This commit is contained in:
parent
d7dfe4ed48
commit
7da5d68315
|
|
@ -24,12 +24,14 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
```toml @sample.conf
|
```toml @sample.conf
|
||||||
# Uses a Go template to create a new tag
|
# Uses a Go template to create a new tag
|
||||||
[[processors.template]]
|
[[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"
|
tag = "topic"
|
||||||
|
|
||||||
## Go template used to create the tag value. In order to ease TOML
|
## Go template used to create the tag value of the output. In order to
|
||||||
## escaping requirements, you may wish to use single quotes around the
|
## ease TOML escaping requirements, you should use single quotes around
|
||||||
## template string.
|
## the template string.
|
||||||
template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}'
|
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
|
+ 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
|
### Add measurement name as a tag
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
# Uses a Go template to create a new tag
|
# Uses a Go template to create a new tag
|
||||||
[[processors.template]]
|
[[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"
|
tag = "topic"
|
||||||
|
|
||||||
## Go template used to create the tag value. In order to ease TOML
|
## Go template used to create the tag value of the output. In order to
|
||||||
## escaping requirements, you may wish to use single quotes around the
|
## ease TOML escaping requirements, you should use single quotes around
|
||||||
## template string.
|
## the template string.
|
||||||
template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}'
|
template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}'
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package template
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
|
|
@ -17,7 +18,9 @@ type TemplateProcessor struct {
|
||||||
Tag string `toml:"tag"`
|
Tag string `toml:"tag"`
|
||||||
Template string `toml:"template"`
|
Template string `toml:"template"`
|
||||||
Log telegraf.Logger `toml:"-"`
|
Log telegraf.Logger `toml:"-"`
|
||||||
tmpl *template.Template
|
|
||||||
|
tmplTag *template.Template
|
||||||
|
tmplValue *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*TemplateProcessor) SampleConfig() string {
|
func (*TemplateProcessor) SampleConfig() string {
|
||||||
|
|
@ -27,27 +30,40 @@ func (*TemplateProcessor) SampleConfig() string {
|
||||||
func (r *TemplateProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric {
|
func (r *TemplateProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric {
|
||||||
// for each metric in "in" array
|
// for each metric in "in" array
|
||||||
for _, metric := range in {
|
for _, metric := range in {
|
||||||
var b strings.Builder
|
|
||||||
newM := TemplateMetric{metric}
|
newM := TemplateMetric{metric}
|
||||||
|
|
||||||
// supply TemplateMetric and Template from configuration to Template.Execute
|
var b strings.Builder
|
||||||
err := r.tmpl.Execute(&b, &newM)
|
if err := r.tmplTag.Execute(&b, &newM); err != nil {
|
||||||
if err != nil {
|
r.Log.Errorf("failed to execute tag name template: %v", err)
|
||||||
r.Log.Errorf("failed to execute template: %v", err)
|
|
||||||
continue
|
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
|
return in
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *TemplateProcessor) Init() error {
|
func (r *TemplateProcessor) Init() error {
|
||||||
// create template
|
var err error
|
||||||
t, err := template.New("configured_template").Parse(r.Template)
|
|
||||||
|
|
||||||
r.tmpl = t
|
r.tmplTag, err = template.New("tag template").Parse(r.Tag)
|
||||||
return err
|
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() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,43 @@ func TestName(t *testing.T) {
|
||||||
testutil.RequireMetricsEqual(t, expected, actual)
|
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) {
|
func TestTagTemplateConcatenate(t *testing.T) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue