Telegraf outputs.exec 输出插件实战:把指标流式写入外部命令 stdin 的配置与源码级原理
2026/9/14 8:13:26 网站建设 项目流程

Telegraf outputs.exec 输出插件实战:把指标流式写入外部命令 stdin 的配置与源码级原理

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

本文基于 Telegraf 仓库中 outputs.exec 插件文档 展开,完整覆盖该插件的全部配置项与默认值,并结合 exec.go 的序列化与进程执行流程、internal/exec_unix.go 的超时终止机制,以及 exec_test.go 的测试断言,系统讲解如何将指标通过stdin投递给外部可执行程序:如何配置commandenvironmenttimeoutuse_batch_format等参数,批量模式与单指标模式的执行差异,命令超时时进程如何被强制终止,以及stderr输出如何进入 Telegraf 日志。

一、插件定位:每次写入都启动一个全新进程

outputs.exec是 Telegraf 的可执行文件输出插件(executable output plugin):它把指标写入一个外部应用程序的stdin。与常驻进程型输出不同,每一次 write 都会执行一次该命令,从而创建一个新进程;指标会以 支持的输出数据格式 之一传递给命令。官方文档同时给出了一条性能提示:如果追求更高性能,应考虑持续运行的 execd 插件(进程只启动一次,指标在其生命周期内持续通过stdin传入)。

关键行为约定(来自插件文档):

  • 可执行文件与各个参数必须以列表形式定义command是一个字符串数组,而不是单个 shell 字符串);
  • 命令输出到stderr的内容会被记录进 Telegraf 日志;
  • 指标格式由data_format指定,可选格式见 输出数据格式文档(InfluxDB Line Protocol、CSV、JSON、Graphite、Prometheus、MessagePack 等 14 种标准序列化器)。

从源码结构看,插件通过 plugins/outputs/all/exec.go 的空白导入完成注册,因此默认构建中开箱可用。

二、完整配置说明(含默认值)

官方示例配置完整继承自 sample.conf,并补齐了 exec.go 中init()注册的默认值:

# Send metrics to command as input over stdin [[outputs.exec]] ## Command to ingest metrics via stdin. ## 注意:可执行文件本身和每个参数都必须是列表中的独立字符串 command = ["tee", "-a", "/dev/null"] ## Environment variables ## 以 "key=value" 键值对数组形式传递的环境变量 ## 例如 "KEY=value", "USERNAME=John Doe", ## "LD_LIBRARY_PATH=/opt/custom/lib64:/usr/local/libs" # environment = [] ## 命令完成执行的超时时间(源码默认值为 5s) # timeout = "5s" ## 命令是逐条指标执行一次,还是按指标批次执行一次。 ## 该值为 true 时,序列化器也会以批量模式运行(源码默认值为 true) # use_batch_format = true ## Data format to output. ## 每种数据格式都有自己独有的配置选项,详见数据格式文档 # data_format = "influx"

2.1 command:命令及其参数列表

command是必填项。源码中它被声明为Command []string(exec.go),运行时通过exec.Command(command[0], command[1:]...)解释:第一个元素是可执行文件路径或名字,其余元素是独立参数。这意味着不要写成command = ["tee -a file"]这种需要 shell 解析的字符串;参数分隔由 Go 的os/exec直接完成,不经过 shell。

2.2 environment:附加环境变量

environmentkey=value字符串数组。从 CommandRunner.Run 的实现看,配置的环境变量会被追加到当前进程环境变量之后

cmd := exec.Command(command[0], command[1:]...) if len(environments) > 0 { cmd.Env = append(os.Environ(), environments...) }

因此子进程继承 Telegraf 进程的全部环境变量,environment中同名键排在后面。是否设置该数组都会创建子进程,只是未配置时不显式赋值cmd.Env

2.3 timeout:命令超时与进程终止策略

timeout的默认值是5sTimeout: config.Duration(time.Second * 5),见 exec.go)。超时的实际处理由通用的 internal.RunTimeout 完成:先c.Start()启动命令,再交给平台相关的WaitTimeout等待。

在非 Windows 平台上(internal/exec_unix.go),超时后的终止流程分两级:

  1. 超时触发后立即向进程组与进程发送SIGTERM,给命令一次“优雅退出”的机会;
  2. 若仍不退出,再等待KillGrace(源码常量定义为 5 秒)后发送SIGKILL强杀。

还有一个细节:如果进程在被终止后返回的错误是“正常退出”(err == nil),WaitTimeout会将其视为成功——这允许子进程在收到SIGTERM后做干净的收尾工作。只有确实被终止信号打断时,才返回超时错误。

2.4 use_batch_format:批量模式 vs 单指标模式

这是该插件对性能影响最大的开关,源码默认值为true。Write 方法中两种路径的分支逻辑:

  • 批量模式use_batch_format = true):调用serializer.SerializeBatch(metrics)把整批指标一次性序列化,然后只执行一次命令,把整个缓冲区写入其stdin。若序列化结果为空(buffer.Len() <= 0),直接返回nil,连命令都不启动;
  • 非批量模式use_batch_format = false):对批次中的每条指标逐一调用serializer.Serialize(metric)每条指标启动一次命令;所有命令的错误通过errors.Join合并后返回。

测试用例精确验证了这两种行为(exec_test.go):TestExternalOutputBatch写入 2 条指标后断言runner.runs == []int{2}(执行一次、一次处理 2 条);TestExternalOutputNoBatch断言runner.runs == []int{1, 1}(执行两次、每次 1 条)。

选型建议:批量模式显著减少进程创建次数,是绝大多数场景的合理默认;只有在下游程序要求“一条指标一次调用”(例如每条指标触发一次独立处理)时才关闭它。若下游是常驻程序,则应改用 execd 输出插件,进程只启动一次。

2.5 data_format:指标序列化格式

data_format决定指标写入stdin之前的编码方式。示例配置默认使用"influx"(InfluxDB Line Protocol),完整可选项及各自独有配置参数见 docs/DATA_FORMATS_OUTPUT.md。任何带data_format配置项的输出插件都可以参考该文档;例如输出 CSV 时配置data_format = "csv",下游命令就可以按列解析指标。

2.6 全局配置选项

作为输出插件,outputs.exec还继承 Telegraf 插件体系的全局配置能力,如指标/标签/字段的过滤修改、插件别名、插件执行顺序等,详见 CONFIGURATION.md 的 Plugins 章节。

三、源码级执行链路:一次 Write 的完整过程

3.1 Runner 抽象与真实执行

插件把“执行命令”抽象为Runner接口(Run(timeout, command, environments, buffer) error),生产实现是CommandRunner,测试中则替换为MockRunner(用 influx 流式解析器 统计收到的指标数),这使得批处理行为可以在不启动真实进程的前提下被断言验证。

真实执行的核心步骤(CommandRunner.Run):

  1. exec.Command构建命令,按需合并环境变量;
  2. cmd.Stdin = buffer—— 序列化后的指标字节流成为命令的标准输入;
  3. cmd.Stderr指向内存缓冲区,捕获命令的标准错误输出;
  4. 交给 internal.RunTimeout 启动并带超时等待(终止策略见 2.3 节)。

3.2 错误信息的分级呈现

命令失败时,错误信息按以下优先级组装并返回给输出管线(exec.go):

失败类型返回错误信息
超时被终止"%q timed out and was killed"
有退出码"%q exited %d with %w"internal.ExitStatus提取状态码)
其他"%q failed with %w"

stderr的处理比文档描述更精细。文档层面写的是“stderr 会被记录进日志”,而源码中它先经过 truncate 处理:先按maxStderrBytes(源码常量 512 字节)截断,再裁到第一个换行符为止,若发生截断则追加...。随后按日志级别输出:

  • 当前日志级别低于debug时:以Errorf记录截断后的 stderr(一行、至多 512 字节);
  • 日志级别为debug时:以Debugf记录完整stderr。

也就是说,日常排查时能在错误日志中直接看到命令失败的第一行原因;需要全量诊断输出时把 Telegraf 日志调到 debug 即可。truncate的行为有专门的单元测试覆盖(TestTruncate:超长输出截到 512 字节加...,多行输出只保留首行)。

另外在 Windows 上(removeWindowsCarriageReturns),记录日志前会剥离\r,避免 CRLF 造成日志行错乱。

3.3 生命周期方法

ConnectClose均为空实现(exec.go)——插件无持久连接或资源需要管理,这也印证了它“无状态、随写随启动进程”的设计。Init仅负责把执行器初始化为CommandRunner

四、实战配置示例

基于插件的语义(stdin 接收指标文本),以下是几种典型用法,均为在telegraf.conf中追加[[outputs.exec]]段即可生效的配置:

# 1) 把 Line Protocol 追加落盘(插件示例同款用法) [[outputs.exec]] command = ["tee", "-a", "/var/log/metrics.ln"] use_batch_format = true # 2) 用 awk 只透传特定测量名 [[outputs.exec]] command = ["awk", "/^cpu /"] data_format = "influx" # 3) 以 JSON 行输出给消费脚本,并通过 environment 传递接收端信息 [[outputs.exec]] command = ["my-metric-consumer"] data_format = "json" environment = ["SINK_HOST=localhost", "SINK_PORT=9192"] timeout = "10s"

使用注意:

  • command[0]若为相对名,按 Telegraf 进程的PATH查找;子进程继承 Telegraf 的系统环境;
  • 命令不读取stdout(源码中Stdout未接管),下游程序应把结果写到文件、网络或stderr
  • 由于每次 write 都 fork 新进程,高频指标批次下timeout不宜过小,否则可能出现“timed out and was killed”;反过来超时过长会让慢命令拖住输出缓冲区,需结合输出插件的buffer_*配置权衡。

五、outputs.exec 与 outputs.execd 的取舍

仓库中两个插件的文档形成明确对照:

  • exec:每次 write 创建新进程;无restart_delayuse_batch_format默认开启;适合“把一批指标当作一次性输入喂给工具命令”的场景(管道、转换、落盘);
  • execd:命令只执行一次并作为常驻守护进程,指标在其生命周期内通过stdin持续传入;提供restart_delay(进程意外退出后的重启延迟,示例默认10s)等守护参数;适合长生命周期的接收端程序。

文档明确建议:“为了更好的性能,考虑持续运行的 execd”。

六、小结

outputs.exec是 Telegraf 中把指标“投递给外部程序”最直接的通道:command列表 +stdin数据流 +data_format决定内容,use_batch_format决定进程创建频率,timeout通过SIGTERM → SIGKILL两级终止保护输出链路不被慢命令拖死,stderr则按日志级别被完整或截断地写入 Telegraf 日志。源码层面的关键实现集中在 plugins/outputs/exec/exec.go(序列化与错误处理)、internal/exec.go 与 internal/exec_unix.go(超时终止),行为断言见 plugins/outputs/exec/exec_test.go,可据此进一步深入。

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

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

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

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

立即咨询