feat(processors.template): Unify template metric (#13606)

This commit is contained in:
Sven Rebhan 2023-07-12 17:00:19 +02:00 committed by GitHub
parent d8f8d3cbc5
commit f001b29eee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 110 additions and 12 deletions

View File

@ -129,6 +129,10 @@ type Metric interface {
// e.g. '{{.Neasurement}}-{{.Tag "foo"}}-{{.Field "bar"}}'
type TemplateMetric interface {
Name() string
Tag(key string) string
Field(key string) interface{}
Fields() map[string]interface{}
Tag(key string) string
Tags() map[string]string
Time() time.Time
String() string
}

View File

@ -88,12 +88,12 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
Sometimes it is usefull to pass all fields with their values into a single
message for sending it to a monitoring system (e.g. Syslog, GroundWork), then
you can use `.FieldList` or `.TagList`:
you can use `.Fields` or `.Tags`:
```toml
[[processors.template]]
tag = "message"
template = 'Message about {{.Name}} fields: {{.FieldList}}'
template = 'Message about {{.Name}} fields: {{.Fields}}'
```
```diff
@ -107,7 +107,7 @@ More advanced example, which might make more sense:
[[processors.template]]
tag = "message"
template = '''Message about {{.Name}} fields:
{{ range $field, $value := .FieldList -}}
{{ range $field, $value := .Fields -}}
{{$field}}:{{$value}}
{{ end }}'''
```

View File

@ -30,7 +30,12 @@ func (*TemplateProcessor) SampleConfig() string {
func (r *TemplateProcessor) Apply(in ...telegraf.Metric) []telegraf.Metric {
// for each metric in "in" array
for _, metric := range in {
newM := TemplateMetric{metric}
m, ok := metric.(telegraf.TemplateMetric)
if !ok {
r.Log.Errorf("metric of type %T is not a template metric", metric)
continue
}
newM := TemplateMetric{m}
var b strings.Builder
if err := r.tmplTag.Execute(&b, &newM); err != nil {

View File

@ -1,14 +1,20 @@
package template
import (
"fmt"
"sync"
"time"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/models"
)
var (
onceTagList sync.Once
onceFieldList sync.Once
)
type TemplateMetric struct {
metric telegraf.Metric
metric telegraf.TemplateMetric
}
func (m *TemplateMetric) Name() string {
@ -16,27 +22,53 @@ func (m *TemplateMetric) Name() string {
}
func (m *TemplateMetric) Tag(key string) string {
tagString, _ := m.metric.GetTag(key)
return tagString
return m.metric.Tag(key)
}
func (m *TemplateMetric) Field(key string) interface{} {
field, _ := m.metric.GetField(key)
return field
return m.metric.Field(key)
}
func (m *TemplateMetric) Time() time.Time {
return m.metric.Time()
}
func (m *TemplateMetric) Tags() map[string]string {
return m.metric.Tags()
}
func (m *TemplateMetric) Fields() map[string]interface{} {
return m.metric.Fields()
}
func (m *TemplateMetric) String() string {
return fmt.Sprint(m.metric)
return m.metric.String()
}
func (m *TemplateMetric) TagList() map[string]string {
onceTagList.Do(func() {
models.PrintOptionValueDeprecationNotice(
telegraf.Warn, "processors.template", "template", "{{.TagList}}",
telegraf.DeprecationInfo{
Since: "1.28.0",
RemovalIn: "1.34.0",
Notice: "use '{{.Tags}}' instead",
},
)
})
return m.metric.Tags()
}
func (m *TemplateMetric) FieldList() map[string]interface{} {
onceFieldList.Do(func() {
models.PrintOptionValueDeprecationNotice(
telegraf.Warn, "processors.template", "template", "{{.FieldList}}",
telegraf.DeprecationInfo{
Since: "1.28.0",
RemovalIn: "1.34.0",
Notice: "use '{{.Fields}}' instead",
},
)
})
return m.metric.Fields()
}

View File

@ -192,6 +192,63 @@ func TestTagList(t *testing.T) {
testutil.RequireMetricsEqual(t, []telegraf.Metric{expected}, actual)
}
func TestFields(t *testing.T) {
// Prepare
plugin := TemplateProcessor{
Tag: "fields",
Template: "{{.Fields}}",
Log: testutil.Logger{},
}
require.NoError(t, plugin.Init())
// Run
m := testutil.TestMetric(1.23)
actual := plugin.Apply(m)
// Verify
expected := m.Copy()
expected.AddTag("fields", "map[value:1.23]")
testutil.RequireMetricsEqual(t, []telegraf.Metric{expected}, actual)
}
func TestTags(t *testing.T) {
// Prepare
plugin := TemplateProcessor{
Tag: "tags",
Template: "{{.Tags}}",
Log: testutil.Logger{},
}
require.NoError(t, plugin.Init())
// Run
m := testutil.TestMetric(1.23)
actual := plugin.Apply(m)
// Verify
expected := m.Copy()
expected.AddTag("tags", "map[tag1:value1]")
testutil.RequireMetricsEqual(t, []telegraf.Metric{expected}, actual)
}
func TestString(t *testing.T) {
// Prepare
plugin := TemplateProcessor{
Tag: "tags",
Template: "{{.}}",
Log: testutil.Logger{},
}
require.NoError(t, plugin.Init())
// Run
m := testutil.TestMetric(1.23)
actual := plugin.Apply(m)
// Verify
expected := m.Copy()
expected.AddTag("tags", "test1 map[tag1:value1] map[value:1.23] 1257894000000000000")
testutil.RequireMetricsEqual(t, []telegraf.Metric{expected}, actual)
}
func TestDot(t *testing.T) {
// Prepare
plugin := TemplateProcessor{Tag: "metric", Template: "{{.}}"}