Telegraf Template Processor 完全指南:用 Go Template 动态生成 Tag 实现指标路由
2026/9/14 15:37:38 网站建设 项目流程

Telegraf Template Processor 完全指南:用 Go Template 动态生成 Tag 实现指标路由

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

本文面向 Telegraf 用户,系统讲解processors.template处理器(自 Telegraf v1.14.0 起提供)的配置语法、模板语言上下文与底层实现原理。通过本文,你将掌握如何基于测量名(measurement name)、标签、字段与时间戳,用 Go Template 语法动态生成新标签,为多输出动态路由、字段转标签、时间维度拆分等场景构建可落地的配置方案。

一、插件定位与典型应用场景

Template Processor 的核心能力是对指标应用模板,生成一个新的 Tag(既有 Tag 名、又有 Tag 值都可以由模板动态计算)。该插件的首要设计用途是:创建可用于多输出插件动态路由的标签,或者配合输出插件特定的路由选项使用——例如按hostnamelevel等标签拼接出topic,让不同来源的指标落到不同的 Kafka Topic、MQTT 主题或 InfluxDB 存储桶。

模板中可以访问每一条指标的全部要素:

可访问数据说明
测量名(measurement name)例如cpumem
标签(tags)指标的全部键值对标签
字段(fields)指标的全部字段及其值
时间戳(timestamp)指标采集时间,可参与格式化

模板遵循 Go Template 语法(标准库text/template),并内置了 Sprig 函数库(sprig.TxtFuncMap()),因此可以使用defaultloweruppertrimjoin等大量实用函数对模板结果做二次加工。

二、快速开始:完整配置解析

插件只需两个配置项,完整样例见 sample.conf:

# Uses a Go template to create a new tag [[processors.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 of the output. In order to ## ease TOML escaping requirements, you should use single quotes around ## the template string. template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}'

两个参数的核心要点:

  • tag:输出标签的名称。它本身也是一个 Go 模板——静态字符串(如"topic")或动态表达式(如'{{ .Field "type" }}')均可,详见下文“字段值作为标签名”示例。
  • template:输出标签的模板。
  • 两个参数都支持模板语法,因此“标签名”和“标签值”都可以完全动态生成。
  • 文档与样例都特别建议:使用单引号包裹模板字符串,以规避 TOML 对反斜杠、花括号等字符的转义负担(单引号字符串在 TOML 中为字面量,不做转义处理)。

从源码 template.go 可以看出,插件结构体只保存TagTemplate两个toml字段,与上述配置一一对应。

三、模板上下文:TemplateMetric 接口全解

模板的执行对象不是原始指标对象本身,而是 Telegraf 专门为模板场景暴露的TemplateMetric接口。该接口定义在仓库根目录 metric.go:

// TemplateMetric is an interface to use in templates (e.g text/template) // to generate complex strings from metric properties // e.g. '{{.Name}}-{{.Tag "foo"}}-{{.Field "bar"}}' type TemplateMetric interface { Name() string Field(key string) interface{} Fields() map[string]interface{} Tag(key string) string Tags() map[string]string Time() time.Time String() string }

模板中可直接调用的方法:

方法返回类型作用模板写法示例
Name()string测量名{{ .Name }}
Tag(key)string取指定标签值{{ .Tag "hostname" }}
Tags()map[string]string全部标签的 map{{ .Tags }}
Field(key)interface{}取指定字段值{{ .Field "temperature" }}
Fields()map[string]interface{}全部字段的 map{{ .Fields }}
Time()time.Time指标时间戳(Go 的time.Time,可继续链式调用UTC()Year()Format等){{ .Time.UTC.Year }}
String()string指标的整体字符串表示{{ . }}

接口的默认实现位于 metric/metric.go。例如String()的实现为fmt.Sprintf("%s %v %v %d", name, tags, fields, timeUnixNano),这也是下文{{.}}示例输出格式的来源;Time()直接返回内部time.Time,因此{{.Time.UTC.Year}}这样的链式调用在 Go 模板中是合法的。

从源码看,处理器在Apply中会先尝试对指标调用Unwrap()(处理跟踪指标包装),再断言为TemplateMetric后执行模板——这保证了该插件对普通指标和跟踪型指标都能正常工作。

四、实战示例全解

以下示例完整继承自插件官方文档 README.md,并辅以源码与测试佐证。

4.1 合并多个标签生成单一标签(动态路由首选)

[[processors.template]] tag = "topic" template = '{{ .Tag "hostname" }}.{{ .Tag "level" }}'

处理前后对比:

- cpu,level=debug,hostname=localhost time_idle=42 + cpu,level=debug,hostname=localhost,topic=localhost.debug time_idle=42

这正是 README 中“为多输出动态路由创建标签”这一首要用例的标准形态。对应单元测试见 template_test.go 的TestTagTemplateConcatenate:输入带hostname=localhostlevel=debug标签的指标,断言输出新增topic=localhost.debug

4.2 使用字段值作为标签名(动态标签名)

[[processors.template]] tag = '{{ .Field "type" }}' template = '{{ .Name }}'

处理前后对比:

- cpu,level=debug,hostname=localhost time_idle=42,type=sensor + cpu,level=debug,hostname=localhost,sensor=cpu time_idle=42,type=sensor

tag参数本身是模板的体现:标签名来自字段type的值(sensor),标签值来自测量名(cpu)。对应测试为 template_test.go 的TestNameTemplate

4.3 将测量名添加为标签

[[processors.template]] tag = "measurement" template = '{{ .Name }}'

处理前后对比:

- cpu,hostname=localhost time_idle=42 + cpu,hostname=localhost,measurement=cpu time_idle=42

把测量名显式沉淀为标签,便于在 InfluxDB、Prometheus 等时序存储中按测量名做统一的标签维度查询。对应测试TestName见 template_test.go。

4.4 添加年份标签(类似 date 处理器的用法)

[[processors.template]] tag = "year" template = '{{.Time.UTC.Year}}'

利用Time()返回的time.Time进行链式调用:UTC()转为 UTC 时区、Year()取年份,即可为每条指标打上采集年份标签,可用于数据按时间分桶或归档。

4.5 将全部字段打包为单个标签(消息型输出场景)

当需要把全部字段连同值拼进一条消息,转发给 Syslog、GroundWork 等监控系统时,可直接使用.Fields.Tags输出 map 的字符串表示:

[[processors.template]] tag = "message" template = 'Message about {{.Name}} fields: {{.Fields}}'

处理前后对比:

- cpu,hostname=localhost time_idle=42 + cpu,hostname=localhost,message=Message\ about\ cpu\ fields:\ map[time_idle:42] time_idle=42

更高级的写法——用range逐字段迭代并换行格式化,得到多行消息:

[[processors.template]] tag = "message" template = '''Message about {{.Name}} fields: {{ range $field, $value := .Fields -}} {{$field}}:{{$value}} {{ end }}'''

处理前后对比:

- cpu,hostname=localhost time_idle=42 + cpu,hostname=localhost,message=Message\ about\ cpu\ fields:\ntime_idle:42\n time_idle=42

注意这里使用了 TOML 的三引号'''包裹多行模板,range循环后的-用于去除相邻空白,这是 Go 模板控制流的常用写法。

4.6 将完整指标作为标签(调试与原始数据透传)

[[processors.template]] tag = "metric" template = '{{.}}'

处理前后对比:

- cpu,hostname=localhost time_idle=42 + cpu,hostname=localhost,metric=cpu\ map[hostname:localhost]\ map[time_idle:42]\ 1257894000000000000 time_idle=42

{{.}}输出TemplateMetric.String()的结果,格式为“测量名 + 标签 map + 字段 map + UnixNano 时间戳”。测试TestStringTestDot验证了该行为(见 template_test.go),输出形如test1 map[tag1:value1] map[value:1.23] 1257894000000000000

五、源码级实现原理

插件核心实现在 template.go,处理流程可分为两个阶段:

5.1 Init 阶段:模板预编译

func (r *Template) Init() error { r.tmplTag, err = template.New("tag template").Funcs(sprig.TxtFuncMap()).Parse(r.Tag) ... r.tmplValue, err = template.New("value template").Funcs(sprig.TxtFuncMap()).Parse(r.Template) ... }

两个模板(标签名模板、标签值模板)在Init()一次性解析并注册 Sprig 函数库,解析失败会直接返回错误(例如模板语法错误),插件无法启动。这意味着模板的合法性检查发生在启动阶段而非运行阶段,符合 Telegraf 插件Init() -> Apply()的生命周期约定。

5.2 Apply 阶段:逐指标执行

func (r *Template) Apply(in ...telegraf.Metric) []telegraf.Metric { for _, raw := range in { m := raw if wm, ok := raw.(telegraf.UnwrappableMetric); ok { m = wm.Unwrap() } tm, ok := m.(telegraf.TemplateMetric) if !ok { r.Log.Errorf("metric of type %T is not a template metric", raw) continue } ... raw.AddTag(tag, value) } return in }

值得注意的工程细节:

  • 指标不丢失:即使某条指标模板执行失败(如引用了不存在的标签导致空值拼接),插件也只是记录错误日志并跳过该条,绝不会丢弃或吞掉指标。测试TestMetricMissingTagsIsNotLost(见 template_test.go)专门断言了“输入条数 = 输出条数”这一不变量。
  • Unwrap()兼容:对实现了UnwrappableMetric的跟踪型指标先解包再断言为TemplateMetric,确保与 Telegraf 的指标跟踪机制(metric/tracking.go)协同工作;测试TestTracking验证了带投递通知的指标经模板处理后仍能正确触发Accept()回调。
  • 模板结果直接落标签:标签名、标签值两个模板执行结果拼接后,通过raw.AddTag(tag, value)写入原指标,因此处理器输出的是在原始指标上新增标签的新指标,测量名、字段、时间戳均保持不变。

5.3 Sprig 函数加持

由于Init()中注入了sprig.TxtFuncMap(),模板可以自由调用 Sprig 提供的字符串、列表、数学等函数。测试TestSprig(见 template_test.go)展示了典型组合:

[[processors.template]] tag = '{{ .Tag "foo" | lower }}' template = '{{ .Name | upper }}'

即标签名先取foo标签值再转小写,标签值取测量名转大写——|管道是 Go 模板的标准用法。

六、处理器顺序与全局配置

Template Processor 同样支持 Telegraf 的全局/插件级配置能力,例如通过namepassnamedroptagexclude等过滤器限定其作用范围,或通过order指定与其它处理器的执行先后。完整说明参见 CONFIGURATION.md。

在处理器编排上需注意:模板处理器读取的是到达它时指标已有的标签与字段。若需要先由其它处理器(如 rename、regex)整理标签,再基于整理结果做模板拼接,应合理设置order(隐式顺序按配置文件中[[processors.template]]出现的位置,显式顺序可用order指定)。从源码结构看,处理器经由 processors 注册机制 注册为"template"名称。

七、延伸:同一模板引擎在其它组件中的应用

TemplateMetric与 Go 模板 + Sprig 的组合并非 template 处理器独有。仓库中的 template 序列化器 使用了完全相同的机制:在Init()中解析模板并注入sprig.TxtFuncMap(),在序列化时对指标执行同样的Unwrap()TemplateMetric断言,支持单指标模板与批量模板(batch_template)。两者的差异在于:处理器把模板结果写入标签,序列化器把模板结果作为输出数据的正文。

这意味着你在此处学到的全部模板写法,都可以直接复用到输出序列化场景;而当需要把模板结果用于动态路由时,优先选择 processor 方案,因为路由标签必须附着在指标上随指标流转。

八、排查与使用建议

  • 模板执行失败不会丢指标:只会输出错误日志(failed to execute tag name template/failed to execute value template),可通过 Telegraf 日志定位问题(参考 LOGGING.md)。
  • 单引号优先:模板字符串在 TOML 中尽量使用单引号或三引号,避免转义错误。
  • 注意拼接空值{{ .Tag "xxx" }}在标签不存在时返回空字符串,拼接出的标签值可能形如.debug(前导点),可用 Sprig 的default函数兜底,例如'{{ .Tag "hostname" | default "unknown" }}.{{ .Tag "level" }}'
  • 标签值长度与基数:生成的标签会成为时序数据的维度,注意控制其基数(cardinality),避免因拼接时间戳等高频变化值造成存储膨胀。
  • 版本前提:本插件自 Telegraf v1.14.0 引入,TemplateMetric接口、UnwrappableMetric解包逻辑均以当前仓库源码为准。

参考文件索引

  • 官方插件文档:plugins/processors/template/README.md
  • 插件源码:plugins/processors/template/template.go
  • 样例配置:plugins/processors/template/sample.conf
  • 单元测试:plugins/processors/template/template_test.go
  • TemplateMetric接口定义:metric.go
  • 默认实现:metric/metric.go
  • 同引擎序列化器:plugins/serializers/template/template.go

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询