Telegraf Prometheus Serializer 实战指南:将指标序列化为 Prometheus 文本格式
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
Prometheus 文本暴露格式(Text Exposition Format)是监控生态中最通用的指标交换格式之一。本文聚焦 Telegraf 内置的prometheus数据格式序列化器,讲解其核心配置、字段到样本的映射规则、名称净化机制、Histogram/Summary 类型支持,以及如何与prometheus输入插件配合实现指标无损往返(round-trip)。读完本文,你将能够在任意支持data_format的输出插件中正确配置并产出标准的 Prometheus 文本输出。
概述:prometheus 序列化器的定位
Telegraf 支持大量输出插件,而data_format机制允许你在输出侧统一选择序列化格式。prometheus序列化器就是其中之一,它把 Telegraf 内部的度量(Metric)转换成 Prometheus 文本暴露格式(见 输出数据格式总览)。它通常用于:
- 通过
file输出插件落盘或打印 Prometheus 格式的指标; - 通过 HTTP 类输出向 Prometheus 生态的采集端暴露指标;
- 与
prometheus输入插件配对,实现指标采集→处理→再输出的闭环。
文档特别强调:当配合prometheus输入插件使用时,输入侧应启用metric_version = 2选项,才能保证指标类型信息正确往返(该选项定义见 prometheus 输入插件)。
完整配置示例
以下配置将序列化结果打印到标准输出,并开启批量格式(batch format):
[[outputs.file]] files = ["stdout"] use_batch_format = true ## Include the metric timestamp on each sample. prometheus_export_timestamp = false ## Sort prometheus metric families and metric samples. Useful for ## debugging. prometheus_sort_metrics = false ## Output string fields as metric labels; when false string fields are ## discarded. prometheus_string_as_label = false ## Encode metrics without HELP metadata. This helps reduce the payload ## size. prometheus_compact_encoding = false ## Control how metric names and label names are sanitized. ## The default "legacy" keeps ASCII-only Prometheus name rules. ## Set to "utf8" to allow UTF-8 metric and label names. ## Valid options: "legacy", "utf8" prometheus_name_sanitization = "legacy" ## Data format to output. ## Each data format has its own unique set of configuration options, read ## more about them here: ## docs/DATA_FORMATS_INPUT.md data_format = "prometheus" ## Specify the metric type explicitly. ## This overrides the metric-type of the Telegraf metric. Globbing is allowed. [outputs.file.prometheus_metric_types] counter = [] gauge = []配置项详解
prometheus序列化器的所有配置项都在结构体FormatConfig中定义,位于 prometheus.go,并注册在serializers注册表中(serializers.Add("prometheus", ...))。下面逐一说明:
| 配置项 | TOML 键 | 默认值 | 作用 |
|---|---|---|---|
prometheus_export_timestamp | ExportTimestamp | false | 是否在每个样本上附带指标时间戳(毫秒精度)。 |
prometheus_sort_metrics | SortMetrics | false | 是否对 metric family 与样本排序,便于调试时输出稳定。 |
prometheus_string_as_label | StringAsLabel | false | 是否把字符串字段输出为标签;为false时字符串字段直接丢弃。 |
prometheus_compact_encoding | CompactEncoding | false | 是否省略 HELP 元数据行,缩小输出体积。 |
prometheus_name_sanitization | NameSanitization | "legacy" | 指标名与标签名的净化策略,可选"legacy"或"utf8"。 |
prometheus_metric_types | TypeMappings | 空 | 通过 glob 显式指定指标类型,覆盖 Telegraf 自带类型。 |
在Init()方法中,序列化器会校验prometheus_name_sanitization的值:空值回退为"legacy","legacy"与"utf8"为合法值,其余取值(如"gzip")会直接报错invalid prometheus_name_sanitization,这一行为有单元测试覆盖(见 prometheus_test.go)。
字段到 Prometheus 样本的映射规则
序列化的核心逻辑位于 collection.go 的Collection.Add方法。规则如下:
- 每个数值字段产生一个样本:每个整数、浮点数、布尔或无符号整数字段都会生成一个 Prometheus 样本;布尔值
true转换为1.0,false转换为0.0。数值转换函数见 convert.go。 - 指标名 = measurement + "_" + field key:例如 measurement 为
cpu、字段为time_idle,得到cpu_time_idle。 - 特殊 case:当 measurement 名恰好是
prometheus时,它不参与指标名拼接,直接使用字段名。这保证了从prometheus输入采集到的指标(measurement 固定为prometheus)在序列化时能还原原始名称,相关逻辑见 convert.go。 - 每个 tag 生成一个标签:标签名来自 tag 键,标签值来自 tag 值。
- 字符串字段默认被忽略:在
prometheus_string_as_label = false时,字符串字段不会产生任何 Prometheus 指标(测试用例 "discard strings" 验证了该行为)。
完整示例:输入与输出
示例输入(InfluxDB line protocol):
cpu,cpu=cpu0 time_guest=8022.6,time_system=26145.98,time_user=92512.89 1574317740000000000 cpu,cpu=cpu1 time_guest=8097.88,time_system=25223.35,time_user=96519.58 1574317740000000000 cpu,cpu=cpu2 time_guest=7386.28,time_system=24870.37,time_user=95631.59 1574317740000000000 cpu,cpu=cpu3 time_guest=7434.19,time_system=24843.71,time_user=93753.88 1574317740000000000示例输出(Prometheus 文本格式):
# HELP cpu_time_guest Telegraf collected metric # TYPE cpu_time_guest counter cpu_time_guest{cpu="cpu0"} 9582.54 cpu_time_guest{cpu="cpu1"} 9660.88 cpu_time_guest{cpu="cpu2"} 8946.45 cpu_time_guest{cpu="cpu3"} 9002.31 # HELP cpu_time_system Telegraf collected metric # TYPE cpu_time_system counter cpu_time_system{cpu="cpu0"} 28675.47 cpu_time_system{cpu="cpu1"} 27779.34 cpu_time_system{cpu="cpu2"} 27406.18 cpu_time_system{cpu="cpu3"} 27404.97 # HELP cpu_time_user Telegraf collected metric # TYPE cpu_time_user counter cpu_time_user{cpu="cpu0"} 99551.84 cpu_time_user{cpu="cpu1"} 103468.52 cpu_time_user{cpu="cpu2"} 102591.45 cpu_time_user{cpu="cpu3"} 100717.05注意:
cpu输入产生的字段被标记为 counter 类型,因此输出的# TYPE行为 counter。字段值为time_guest等的数值型字段一一对应输出;带cpu="cpu0"等标签的样本保留了 tag 信息。
名称净化:legacy 与 utf8 两种模式
Prometheus 对指标名与标签名有严格的字符约束。序列化器在输出前会对名称做净化(sanitize),逻辑见 convert.go:
- legacy 模式(默认):指标名首字符只允许
a-zA-Z:和_,后续字符允许a-zA-Z0-9:_;标签名首字符只允许a-zA-Z_,后续允许a-zA-Z0-9_。不合法的 rune 会被替换为下划线,连续下划线会被压缩并去除首尾下划线;若净化后名称为空,该指标/标签会被丢弃。 - utf8 模式:允许 UTF-8 字符出现在指标名与标签名中,适用于需要保留中文等非 ASCII 名称的场景;但对非 UTF-8 的非法输入仍会回退到 legacy 净化规则。
这些行为在 collection_test.go 中有详尽的单元测试:legacy模式下纯 UTF-8 名称(如温度-指标)净化后为空而被丢弃;utf8模式下则原样保留为温度-指标_数值-值与标签主机-名;非法字节(如0xff)在两种模式下都会回退处理。
另外,指标名中的冒号(:)是合法字符且不会被替换(见cpu::xyzzy_time_idle测试用例),而标签名中的冒号会被替换为下划线(host:name→host_name)。
类型系统:untyped、counter、gauge 与显式类型覆盖
序列化时,Telegraf 指标的类型会映射到 Prometheus 的 metric family 类型,映射函数见 convert.go:
| Telegraf 类型 | Prometheus 类型 |
|---|---|
Counter | counter |
Gauge | gauge |
Summary | summary |
Histogram | histogram |
Untyped | untyped(其他类型默认) |
许多输入插件产生的指标类型是untyped。如果你需要强制指定类型,可以使用配置节prometheus_metric_types,通过 glob 规则把匹配的指标名映射为counter或gauge,从而覆盖 Telegraf 指标自身的类型。该映射在 prometheus.go 中实现:MetricTypes.Init()将counter/gauge数组编译为过滤器,DetermineType在Collection.Add阶段按最终指标名匹配覆盖类型。相关测试用例 "untyped forced to counter" 与 "untyped forced to gauge" 验证了该机制(见 prometheus_test.go)。
批量序列化、时间戳与紧凑编码
use_batch_format 与 SerializeBatch
Prometheus 文本格式要求同一 metric family 内的样本聚合输出。序列化器实现了SerializeBatch(见 prometheus.go),将整批指标先收集到Collection中再统一输出。file输出插件通过use_batch_format = true启用批量模式;在批量模式下,来自不同 metric 的样本会按 metric family 归并,例如多个cpu_time_idle样本会输出为同一个 family 下的多个样本行。
批量模式下同一 sample 出现多次时,会保留时间戳更新的那个样本("newer sample" 测试用例验证了这一点)。
时间戳导出
当prometheus_export_timestamp = true时,每个样本行末尾会附加毫秒级时间戳(源码中通过TimestampMs = metric.time.UnixNano() / int64(time.Millisecond)计算)。例如:
cpu_time_idle{host="example.org"} 42 1574279268000紧凑编码
当prometheus_compact_encoding = true时,输出会省略# HELP行(但保留# TYPE行),以减小 payload 体积:
# TYPE cpu_time_idle untyped cpu_time_idle{host="example.org"} 42两种模式下的差异均有对应的测试用例(见 prometheus_test.go)。
Histogram 与 Summary 类型的处理及注意事项
支持方式
prometheus序列化器支持 histogram 与 summary 类型,但其样本是由多个字段组合而成的,需要专门的合并逻辑(见 collection.go):
- Histogram:
<name>_bucket字段(配合letag)构成桶,<name>_sum与<name>_count字段提供总和与计数;输出时指标名会去掉_bucket/_sum/_count后缀(见 convert.go)。同一边界(bound)的桶会合并更新。 - Summary:
<name>_sum/<name>_count字段提供总和与计数,其余字段配合quantiletag 构成分位数样本。
完整的多桶 histogram 与多分位数 summary 序列化输出示例,可参考 prometheus_test.go。
跨批次的历史遗留问题(重要警告)
文档明确警告:当生成 histogram 与 summary 类型时,如果指标跨越多个批次,输出可能不正确。这是因为序列化器内部维护了一个Collection缓存(entries map[metricFamily]entry,每个 entry 内以metricKey索引promMetric),它通过Collection.Add累积样本,并通过Expire(now, age)按添加时间(addTime)清理过期数据(见 collection.go)。
Histogram 和 Summary 的过期时间基于最近一次收到的数据更新:只要某个桶或某个分位数持续更新,整个 metric 就会持续存活;反过来,如果某些桶/分位数停止更新而其他仍上报,则停止更新的桶/分位数会一直保留,不会自动消失。这些行为在 collection_test.go 中有系统性的测试,包括 "update metric expiration"、"histogram bucket updates"、"entire histogram expires"、"summary does not expire because of quantile addtime" 等用例。
文档的建议是:使用 histogram 与 summary 类型时,推荐只使用prometheus_client输出插件(即专为 Prometheus 设计的输出插件),因为该插件按批次采集的语义更适合这类累积型指标;若必须使用其他输出,则尽量启用支持批量写格式(batch format)的输出,以缓解但不完全消除该问题。
与 prometheus 输入的往返(round-trip)配置
如果你用prometheus输入插件采集指标,再通过本序列化器输出,请务必在输入侧设置metric_version = 2:
[[inputs.prometheus]] urls = ["http://example.org/metrics"] metric_version = 2metric_version = 2会保留 Prometheus 指标的类型信息(counter/gauge/histogram/summary),使其以 Telegraf 度量进入流水线后,经本序列化器输出时能够还原为正确的 Prometheus 类型与结构,实现无损往返。该选项的详细说明见 prometheus 输入插件文档。
深入阅读指引
如果想继续研究实现细节,建议阅读以下源码与测试文件:
- prometheus.go:配置结构体
FormatConfig、类型映射MetricTypes、Init校验、Serialize/SerializeBatch入口; - convert.go:指标名/标签名净化、measurement+field 拼接、数值与计数/求和转换;
- collection.go:
Collection缓存、Add合并、Expire过期清理、GetProto输出 dto.MetricFamily; - prometheus_test.go:单条与批量序列化的完整输入输出对照;
- collection_test.go:过期机制、histogram/summary 合并、UTF-8 名称净化等边界行为;
- 输入插件文档:
metric_version的语义与往返配置说明。
整体序列化框架及与其他格式(InfluxDB、JSON、Graphite、Prometheus Remote Write 等)的并列关系,可参考 输出数据格式总览。
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考