Telegraf Datadog Output 插件实战:配置详解、指标转换规则与 rate_interval 原理
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
本篇围绕 Telegraf 的outputs.datadog插件展开,系统讲解如何通过 Datadog Metrics API(v1)将 Telegraf 采集的指标写入 Datadog:从完整的 TOML 配置项逐一解析(apikey、timeout、url、代理、压缩、rate_interval),到源码级的指标命名、类型映射与数值转换规则,再到rate_interval将 statsd 计数器转换为 rate 的底层实现与测试验证。读完后你可以独立完成该插件的配置、排错,并能准确预判每个 Telegraf 字段在 Datadog 侧最终呈现的指标名与指标类型。
插件定位:面向 Datadog Metrics API v1 的输出插件
Datadog Output 插件将 Telegraf 指标写入 Datadog Metrics API,前提是持有一个有效的apikey(在 Datadog 账户设置中获取)。插件文档(plugins/outputs/datadog/README.md)明确注明了版本适用边界:
This plugin supports the v1 API.
这一限制在源码中同样得到印证。datadog.go 定义了默认写入端点:
const datadogAPI = "https://app.datadoghq.com/api/v1/series"而在插件注册时(init 函数)设置了两个关键默认值:
func init() { outputs.Add("datadog", func() telegraf.Output { return &Datadog{ URL: datadogAPI, Compression: "none", } }) }即:默认请求https://app.datadoghq.com/api/v1/series,默认不做压缩。认证方式是把apikey作为查询参数拼在 URL 上(见下文“认证机制”一节),这也是文档注释中“由于认证方式限制,目前只支持 v1 API”的原因。
完整配置项详解
以下为插件的官方示例配置,完整保留自 sample.conf:
# Configuration for DataDog API to send metrics to. [[outputs.datadog]] ## Datadog API key apikey = "my-secret-key" ## Connection timeout. # timeout = "5s" ## Write URL override; useful for debugging. ## This plugin only supports the v1 API currently due to the authentication ## method used. # url = "https://app.datadoghq.com/api/v1/series" ## Set http_proxy # use_system_proxy = false # http_proxy_url = "http://localhost:8888" ## Override the default (none) compression used to send data. ## Supports: "zlib", "none" # compression = "none" ## When non-zero, converts count metrics submitted by inputs.statsd ## into rate, while dividing the metric value by this number. ## Note that in order for metrics to be submitted simultaneously alongside ## a Datadog agent, rate_interval has to match the interval used by the ## agent - which defaults to 10s # rate_interval = 0s下面逐项说明各配置的含义、默认值与源码中的作用位置(对应 Datadog 结构体 中的字段):
apikey(必填)
Datadog 的 API 密钥,是唯一的强制配置。Connect 方法 在插件启动连接时会做显式校验:
func (d *Datadog) Connect() error { if d.Apikey == "" { return errors.New("apikey is a required field for datadog output") } ... }未配置apikey时插件会直接报错,不会静默启动。
timeout
连接超时,TOML 时长格式(如"5s")。它对应config.Duration类型(定义见 config/types.go),解析时兼容整数秒、浮点秒以及"3s"这类时长字符串。Connect时它被设为http.Client的Timeout,控制单次写请求的最大耗时。
url(调试用 URL 覆盖)
默认指向https://app.datadoghq.com/api/v1/series,可覆盖为任意地址,典型用途是把请求打到本地 mock 服务做调试。测试 TestUriOverride 正是利用httptest.NewServer起了一个本地假服务,把url指向它来验证覆盖生效、请求能成功发出并收到 200。
代理配置:use_system_proxy / http_proxy_url
这两个选项来自 Telegraf 公共代理组件 plugins/common/proxy/proxy.go,其HTTPProxy结构体被内嵌进Datadog:
use_system_proxy = true:使用环境变量(http.ProxyFromEnvironment,即HTTP_PROXY/HTTPS_PROXY等);http_proxy_url:显式指定代理地址,会做 URL 解析校验,非法地址在Connect阶段报错;- 两者都不设置时不走代理。
compression:zlib 或 none
覆盖默认(none)的压缩方式,仅支持"zlib"与"none"两个取值。Write 方法 中的处理逻辑:
compression = "zlib":通过 internal/content_coding.go 的NewContentEncoder创建 zlib 编码器压缩 JSON 负载,并设置请求头Content-Encoding: deflate;compression = "none"(或任何其他值,走default分支):直接发送原始 JSON。
注意请求的Content-Type始终为application/json,压缩只作用于请求体传输编码。TestCompressionOverride 验证了 zlib 模式下请求可被本地服务正常接收。
rate_interval:把 count 指标转换为 rate
这是本插件最有技术含量的一项配置,后文专门展开。
此外,与 Telegraf 其他 output 一样,[[outputs.datadog]]还支持全局的插件级过滤配置(如namepass/nameprefix/tagpass、字段过滤等),详见 docs/CONFIGURATION.md 的 Plugins 章节。
数据流与请求格式:从 Telegraf Metric 到 Datadog Series
理解该插件最快的方式是看它发送给 Datadog 的 JSON 结构。datadog.go 定义了完整的序列化模型:
type TimeSeries struct { Series []*Metric `json:"series"` } type Metric struct { Metric string `json:"metric"` Points [1]Point `json:"points"` Host string `json:"host"` Type string `json:"type,omitempty"` Tags []string `json:"tags,omitempty"` Interval int64 `json:"interval"` } type Point [2]float64即整个批次包成一个{"series": [...]},每条Metric只携带一个数据点Point(二元数组:[时间戳(秒), 值]),并带有指标名、host、类型、标签与 interval。
Write 方法 的完整流程:
- 调用
convertToDatadogMetric把整批[]telegraf.Metric转换为[]*Metric;若结果为空(例如所有字段都是非法值被跳过),直接返回 nil,不发请求; json.Marshal序列化,失败则返回unable to marshal TimeSeries错误;- 按
compression决定是否 zlib 压缩; - 向
authenticatedURL()发起POST; - 校验响应状态码,仅
200–209视为成功,否则读取响应体并返回received bad status code, <code>: <body>。
TestBadStatusCode 用 500 响应验证了错误信息会携带 Datadog 返回的原始错误 JSON,例如{"errors": ["Something bad happened to the server."]}。
认证机制与 API Key 防泄漏
apikey不走 Header,而是作为查询参数附加在 URL 上:
func (d *Datadog) authenticatedURL() string { q := url.Values{ "api_key": []string{d.Apikey}, } return fmt.Sprintf("%s?%s", d.URL, q.Encode()) }TestAuthenticatedUrl 断言其输出为<url>?api_key=<key>。
值得注意的是插件对密钥泄漏的防护:构造请求失败或发送失败时,错误信息中会出现的密钥会被替换为****************:
redactedAPIKey := "****************" ... return fmt.Errorf("unable to create http.Request, %s", strings.ReplaceAll(err.Error(), d.Apikey, redactedAPIKey))这保证即使url或网络错误把带密钥的 URL 带入日志,日志里也不会留下明文 key。
指标命名规则:metric + "." + field
Datadog 指标名的生成规则(与 README 一致,实现于 convertToDatadogMetric):
- 一般地,指标名 =
Telegraf 指标名 + "." + 字段名,例如指标cpu的字段usage_user会变成cpu.usage_user; - 特例:字段名恰好是
value时不再追加后缀,直接使用指标名(源码注释adding .value seems redundant here)。这与 statsd 输入产生的value字段天然契合。
标签(tags)与 host 的处理:
- 所有 Telegraf tag 按
key:value格式拼接为 Datadog tags 数组,见 buildTags 与 TestBuildTags(例如 tagone=two→"one:two"); - 名为
host的 tag 被单独取出,填充到 JSON 的host字段(host, _ := m.GetTag("host")),它同时也会出现在 tags 中。
字段值与指标类型转换规则
数值类型转换:一切皆 float
Datadog v1 API 只接受浮点数值,因此 setValue 负责把 Telegraf 字段值统一转为float64:
int64/uint64/float64:直接转换;bool:false → 0.0,true → 1.0;- 其他类型(如字符串):返回
undeterminable field type错误,整个指标会被记录日志并跳过(Unable to build Metric for %s ... skipping)。
字符串在更前置的 verifyValue 就被判定为非法:
func verifyValue(v interface{}) bool { switch v := v.(type) { case string: return false case float64: // The payload will be encoded as JSON, which does not allow NaN or Inf. return !math.IsNaN(v) && !math.IsInf(v, 0) } return true }也就是说:
- 字符串字段被忽略(TestVerifyValue 验证
"11234.5"字符串被判为无效); NaN/Inf这类无法用 JSON 表示的浮点值被忽略(TestNaNIsSkipped 与 TestInfIsSkipped 验证了仅含此类字段时整个指标不会触发任何网络请求)。
buildMetrics 逐字段执行“校验 → 转 float → 填充时间戳”,时间戳取m.Time().Unix()(秒级),TestBuildPoint 覆盖了 float、int32/int64、uint64、bool 等各类输入的预期输出。
指标类型映射(type 字段)
Datadog 的type与 Telegraf 的 metric type 对应关系在 convertToDatadogMetric 中:
| Telegraf 类型 | 未设置 rate_interval | 设置 rate_interval 且可 rate 化 |
|---|---|---|
gauge | gauge | gauge(不转换) |
counter | count | rate(值除以 interval,见下) |
untyped | 空(不输出 type) | rate(仅 statsd 的 count 字段) |
| 其他 | 空 | 空 |
同时interval字段:默认1;被 rate 化时取rate_interval的秒数(源码注释:interval is expected to be in seconds)。
rate_interval 深入:与 Datadog Agent 对表的关键配置
README 对rate_interval的说明是:
When non-zero, converts count metrics submitted by inputs.statsd into rate, while dividing the metric value by this number. Note that in order for metrics to be submitted simultaneously alongside a Datadog agent, rate_interval has to match the interval used by the agent - which defaults to 10s
其设计目标是:让 Telegraf 可以和 Datadog Agent 并存上报同一业务指标的 rate 值(Datadog Agent 默认按10s计算 rate)。转换逻辑集中在两个函数:
转换条件——isRateable 依赖inputs.statsd写入的metric_typetag(该 tag 由 plugins/inputs/statsd/statsd.go 在解析 statsd 报文时按gauge|set|counter|timing|histogram|distribution设置):
metric_type = "counter":整个指标可 rate 化;metric_type = "timing"或"histogram":只有名为count的字段可 rate 化(mean/median/sum 等统计量字段保持原样);- 其他情况:不转换。
这正是文档强调“只支持经由inputs.statsd摄入的指标”的原因——没有metric_typetag 就无法判定是否可 rate 化。
转换动作(datadog.go):
if d.RateInterval > 0 && isRateable(statsDMetricType, fieldName) { // interval is expected to be in seconds rateIntervalSeconds := time.Duration(d.RateInterval).Seconds() interval = int64(rateIntervalSeconds) dogM[1] = dogM[1] / rateIntervalSeconds tname = "rate" }即值除以rate_interval的秒数、interval取该秒数、type置为rate。
单元测试 TestNonZeroRateIntervalConvertsRatesToCount 与 TestZeroRateIntervalConvertsRatesToCount 提供了精确的预期值:
rate_interval = 10s时,counter 指标value=100→10,type="rate"、Interval=10;metric_type="timing"/"histogram"时,count=1→0.1且指标名为<name>.count,而lower/mean/median/stddev/sum/upper等字段保持原值、type为空、Interval=1;rate_interval = 0(默认)时,counter 保持type="count"、原值100、Interval=1,timing/histogram 的 count 字段也不转换。
因此实践建议是:只有当你需要 Telegraf 的 statsd 数据与 Datadog Agent 的 rate 曲线叠加展示时,才把rate_interval设为与 Datadog Agent 相同的 interval(通常10s);否则保持默认0s,让 counter 以count类型原值上报。
错误处理与可观测性小结
汇总该插件的失败模式,便于排障:
| 现象 | 触发点 | 源码位置 |
|---|---|---|
apikey is a required field for datadog output | 未配置 apikey,Connect 阶段 | Connect |
error parsing proxy url ... | http_proxy_url非法 | proxy.go |
Unable to build Metric for <name> ... skipping | 字段类型无法转 float(如字符串混入),单条跳过并记 Info 日志 | convertToDatadogMetric |
unable to marshal TimeSeries: ... | JSON 序列化失败 | Write |
received bad status code, <code>: <body> | 响应码不在 200–209,返回 Datadog 响应体原文 | Write |
error POSTing metrics, ...(密钥已打码) | 网络/超时等请求失败 | Write |
快速上手清单
- 在
telegraf.conf中添加[[outputs.datadog]]并填入apikey(可参考 sample.conf); - 内网环境按需配置
use_system_proxy/http_proxy_url; - 需要压缩传输时设
compression = "zlib"(请求头为Content-Encoding: deflate); - 用
url指向本地 mock(或临时抓包代理)验证负载格式与命名规则是否符合预期,再改回默认端点; - 若与 Datadog Agent 并存上报 statsd 指标,设
rate_interval = "10s"(须与 Agent 的 rate interval 一致)。
相关代码与测试入口:插件实现、单元测试、公共代理组件、内容压缩组件、statsd 输入的 metric_type tag 来源、插件通用配置文档。
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考