Telegraf Docker Log 输入插件:基于 Docker Engine API 收集容器日志的完整实战指南
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
Docker Log 是 Telegraf 中用于实时读取 Docker 容器 stdout/stderr 日志的输入插件,它通过 Docker Engine API 直接对接 daemon 的日志流,将容器日志转换为docker_log指标并纳入 Telegraf 统一的采集、处理与输出管线。本文基于 plugins/inputs/docker_log/README.md 与其源码实现,完整讲解该插件的配置参数、过滤机制、底层 tail 原理、TTY 多路复用处理与状态持久化能力,帮助读者在真实环境中快速、可靠地采集容器日志。
插件概述
该插件通过 [Docker Engine API][api] 获取运行中容器的日志输出。与直接读取宿主机上的日志文件(如 docker json-file 文件、journald 日志)不同,它调用 Docker daemon 暴露的标准接口,因此无论日志驱动如何落地存储,只要 daemon 支持按流(stdout/stderr)回放日志,Telegraf 就能以统一的方式消费。
从当前仓库源码(plugins/inputs/docker_log/docker_log.go)看,插件被注册为inputs.docker_log,注册时默认设置Timeout为 5 秒:
func init() { inputs.Add("docker_log", func() telegraf.Input { return &DockerLogs{ Timeout: config.Duration(time.Second * 5), } }) }插件属于 Telegraf 的 ServiceInput 类型(实现了Start/Stop),意味着它会为每一个匹配的容器启动常驻的日志追踪 goroutine,持续读取增量日志。
[!NOTE] 该插件仅对使用
local、json-file或journald日志驱动启动的容器生效。同时,请确保 Telegraf 进程对所配置的 endpoint 拥有足够权限(例如读取/var/run/docker.sock或访问远程 Docker TCP/TLS 端点)。
引入版本:⭐ Telegraf v1.12.0 | 标签:containers, logging | 平台:💻 all
配置示例与参数详解
插件的完整配置模板由 plugins/inputs/docker_log/sample.conf 维护,并在插件Init()中通过//go:embed sample.conf嵌入,作为生成示例配置的源头。最小可用配置如下:
# Read logging output from the Docker engine [[inputs.docker_log]] ## Docker Endpoint ## To use TCP, set endpoint = "tcp://[ip]:[port]" ## To use environment variables (ie, docker-machine), set endpoint = "ENV" # endpoint = "unix:///var/run/docker.sock" ## When true, container logs are read from the beginning; otherwise reading ## begins at the end of the log. If state-persistence is enabled for Telegraf, ## the reading continues at the last previously processed timestamp. # from_beginning = false ## Timeout for Docker API calls. # timeout = "5s" ## Containers to include and exclude. Globs accepted. ## Note that an empty array for both will include all containers # container_name_include = [] # container_name_exclude = [] ## Container states to include and exclude. Globs accepted. ## When empty only containers in the "running" state will be captured. # container_state_include = [] # container_state_exclude = [] ## docker labels to include and exclude as tags. Globs accepted. ## Note that an empty array for both will include all labels as tags # docker_label_include = [] # docker_label_exclude = [] ## Set the source tag for the metrics to the container ID hostname, eg first 12 chars source_tag = false ## Optional TLS Config # tls_ca = "/etc/telegraf/ca.pem" # tls_cert = "/etc/telegraf/cert.pem" # tls_key = "/etc/telegraf/key.pem" ## Use TLS but skip chain & host verification # insecure_skip_verify = falseendpoint:连接 Docker daemon
- 默认值为
unix:///var/run/docker.sock(本机 Unix socket)。源码中Init()在Endpoint为空时主动补上该默认值(docker_log.go)。 - 使用 TCP 连接远程 Docker 时,设置为
tcp://[ip]:[port]。 - 使用环境变量(例如 docker-machine 场景)时,设置为
"ENV",插件将调用client.New(client.FromEnv)从 Docker CLI 约定的环境变量(如DOCKER_HOST、DOCKER_TLS_VERIFY等)构造客户端(docker_log.go)。
在非ENV分支下,插件会携带 User-Agentengine-api-cli-1.0创建客户端,并在配置了 TLS 时注入带有 TLS 配置的 HTTP Transport(docker_log.go)。
timeout:Docker API 调用超时
控制所有 Docker API 调用的超时时间,包括列容器、inspect 容器、读取日志流。默认5s。在源码中,每次 Gather 与日志追踪期间涉及 API 调用的上下文(context.WithTimeout)都会使用该值。
from_beginning:从日志开头还是末尾开始读取
false(默认):仅读取从插件启动时刻之后产生的新日志,跳过历史日志。true:从容器日志的最开始读取。- 若 Telegraf 启用了状态持久化(state-persistence),则无论该选项如何,重启后都会从上次最后处理的日志时间戳继续读取,避免重复消费(详见下文"状态持久化"小节)。
容器名称过滤
# container_name_include = [] # container_name_exclude = []- 支持 glob 通配符匹配容器名称。
- 两者均为空数组时,包含所有容器。
- 底层由
filter.NewIncludeExcludeFilter构造 include/exclude 过滤器(docker_log.go),容器的名称取自容器Names列表中首个不带嵌套路径的名字(parseContainerName,见 util.go)。
容器状态过滤
# container_state_include = [] # container_state_exclude = []- 支持 glob 匹配容器状态。
- 关键默认行为:当 include 与 exclude 均为空时,仅采集
running状态的容器——源码中会显式将ContainerStateInclude置为[]string{"running"}(docker_log.go)。如需采集已退出容器的历史日志,可通过 include 显式加入exited等状态。
Docker label 过滤与标签注入
# docker_label_include = [] # docker_label_exclude = []- 将匹配的容器 label 作为指标的额外 tag 注入。
- 两者均为空时,所有 label 都会作为 tag 注入。
- 匹配基于 label 的 key 进行 glob 过滤(docker_log.go)。
TLS 配置
连接启用 TLS 的远程 Docker daemon 时,可配置:
tls_ca:CA 证书路径tls_cert:客户端证书路径tls_key:客户端私钥路径insecure_skip_verify:跳过证书链与主机名校验(不推荐生产使用)
全局配置
所有 Telegraf 插件还支持全局与插件级的通用配置,例如指标/标签/字段修改、别名、插件执行顺序等,详见 docs/CONFIGURATION.md。
source tag:解决容器重名的指标溯源问题
当环境中存在大量同名容器时(例如通过编排工具重复创建名称相同的工作负载),仅凭container_name无法区分数据来源。插件提供source_tag选项解决此问题:
source_tag = true开启后,所有数据点会额外带上source标签,其值为容器 ID 的前 12 个字符。这是 Docker 对未显式设置 hostname 的容器所采用的默认主机名前缀(即常见的主机名形式),因此既保证唯一性又贴近容器实际的主机标识。底层实现见hostnameFromID(util.go):
func hostnameFromID(id string) string { if len(id) > 12 { return id[0:12] } return id }工作流程与底层原理
结合源码(docker_log.go),插件的核心采集流程如下:
- 列出容器:
Gather()调用ContainerList获取当前所有容器(docker_log.go),并设置纳秒级时间精度acc.SetPrecision(time.Nanosecond)。 - 过滤与去重:跳过已在追踪列表
containerList中的容器,然后依次应用名称过滤、状态过滤。 - 逐个追踪:对每个新容器创建一个带
context.WithCancel的独立 goroutine 持续 tail 日志(docker_log.go),goroutine 结束或Stop()时通过 cancel 函数终止。 - 组装基础标签:通过
docker.ParseImage(internal/docker/docker.go)将镜像名拆分为container_image与container_version;镜像未打 tag 时版本回退为unknown。 - 探测 TTY:
ContainerInspect检查容器Config.Tty,决定日志流是单流还是多路复用(docker_log.go)。 - 请求日志流:调用
ContainerLogs,请求参数固定为ShowStdout=true、ShowStderr=true、Timestamps=true、Follow=true;from_beginning=false时通过Since参数指定从启动时间或上次记录的时间戳开始(docker_log.go)。 - 逐行解析并上报:按行解析时间戳与消息内容,调用
acc.AddFields("docker_log", ...)写入指标(util.go)。
TTY 与非 TTY:日志流的两种读取模式
- 容器启用了 TTY:只有单一的 stdout 流,日志直接按行读取,
stream标签固定为tty。 - 容器未启用 TTY:stdout 与 stderr 在 Docker 日志协议中被多路复用,插件使用
stdcopy.StdCopy将复合流分离为独立的 stdout/stderr 两个管道,分别 tail(tailMultiplexed,util.go),stream标签对应stdout或stderr。
源码注释明确说明了两者的差异(docker_log.go),这也是 Docker 日志 API 的标准行为,理解它能帮助排查"日志看起来缺了一半"或 stream 标签不准确的问题。
日志行解析细节
parseLine(util.go)将每行按首个空格拆分为 RFC3339Nano 时间戳与消息体:保留消息前导空格(避免破坏缩进/堆栈信息),同时去除行尾空白字符,与 syslog 等日志插件的处理方式保持一致。若某一行时间戳解析失败,会通过acc.AddError上报而不会中断整体采集。
状态持久化:重启后不重不漏地续读
插件实现了StatefulPlugin接口(GetState/SetState),以容器 ID → 最后处理日志时间戳的映射作为持久化状态(docker_log.go)。相关机制参见 docs/developers/STATE_PERSISTENCE.md:
- 每次处理完日志行都会更新
lastRecord[容器ID]为最新时间戳(多个流取较晚者)。 - Telegraf 关闭时调用
GetState()汇总状态,仅当agent配置节设置了statefile时才写入磁盘。 - 下次启动时,
SetState()在Init()之后被调用,恢复各容器的时间戳;后续 tail 时通过Since参数从该时间戳继续,从而避免重复采集历史日志。
这也解释了配置注释中的表述:开启状态持久化后,读取会从上次最后处理的时间戳继续。测试用例 TestStatePersistence 与TestStatePersistenceMux分别验证了 TTY 单流与非 TTY 多路复用两种模式下的状态保存与恢复;TestGatherConcurrentState则以 64 个容器并发追踪验证共享状态映射的并发安全性。
指标结构与示例输出
每次采集产生一条docker_log指标:
- tags:
container_image(镜像名,不含 tag)container_version(镜像 tag,无 tag 时为unknown)container_name(容器名)stream(stdout、stderr或tty)source(仅当source_tag = true时存在,取容器 ID 前 12 字符)- 以及命中的 Docker label(作为附加 tag)
- fields:
container_id(完整容器 ID)message(日志行内容)
时间戳为日志行自带的时间戳(纳秒精度)。示例输出如下:
docker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id="371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023",message="2019-06-19T03:11:11Z I! [agent] Config: Interval:10s, Quiet:false, Hostname:\"371ee5d3e587\", Flush Interval:10s" 1560913872000000000 docker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id="371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023",message="2019-06-19T03:11:11Z I! Tags enabled: host=371ee5d3e587" 1560913872000000000 docker_log,container_image=telegraf,container_name=sharp_bell,container_version=alpine,stream=stderr container_id="371ee5d3e58726112f499be62cddef800138ca72bbba635ed2015fbf475b1023",message="2019-06-19T03:11:11Z I! Loaded outputs: file" 1560913872000000000测试与验证
仓库中的测试(docker_log_test.go)通过 mock Docker daemon 覆盖了核心行为,可作配置与排查参考:
TestGather:验证"无容器"、"TTY 单流容器"、"非 TTY 多路复用容器"三种场景下的指标结构与内容。TestGatherConcurrentState:64 个容器并发追踪,校验并发安全。TestStatePersistence/TestStatePersistenceMux:验证停止插件后状态被正确记录、恢复后从断点续读。
实战要点小结
- 确认容器使用
local、json-file或journald日志驱动,并保证 Telegraf 对 endpoint 有访问权限(本机通常需要 telegraf 用户加入docker组或调整 socket 权限)。 - 默认只采集
running状态容器;需要采集历史日志时设置from_beginning = true并配合状态持久化使用。 - 容器重名频繁时开启
source_tag = true,利用容器 ID 前 12 位唯一标识数据来源。 - 通过
container_name_include/exclude、docker_label_include/exclude控制采集范围与标签维度,避免无关容器日志与标签爆炸。 - 远程连接务必配置好 TLS 参数;对 docker-machine 等环境可直接使用
endpoint = "ENV"。
【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考