news 2026/9/14 7:50:28

Telegraf Docker Log 输入插件:基于 Docker Engine API 收集容器日志的完整实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Telegraf Docker Log 输入插件:基于 Docker Engine API 收集容器日志的完整实战指南

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] 该插件仅对使用localjson-filejournald日志驱动启动的容器生效。同时,请确保 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 = false

endpoint:连接 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_HOSTDOCKER_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),插件的核心采集流程如下:

  1. 列出容器Gather()调用ContainerList获取当前所有容器(docker_log.go),并设置纳秒级时间精度acc.SetPrecision(time.Nanosecond)
  2. 过滤与去重:跳过已在追踪列表containerList中的容器,然后依次应用名称过滤、状态过滤。
  3. 逐个追踪:对每个新容器创建一个带context.WithCancel的独立 goroutine 持续 tail 日志(docker_log.go),goroutine 结束或Stop()时通过 cancel 函数终止。
  4. 组装基础标签:通过docker.ParseImage(internal/docker/docker.go)将镜像名拆分为container_imagecontainer_version;镜像未打 tag 时版本回退为unknown
  5. 探测 TTYContainerInspect检查容器Config.Tty,决定日志流是单流还是多路复用(docker_log.go)。
  6. 请求日志流:调用ContainerLogs,请求参数固定为ShowStdout=trueShowStderr=trueTimestamps=trueFollow=truefrom_beginning=false时通过Since参数指定从启动时间或上次记录的时间戳开始(docker_log.go)。
  7. 逐行解析并上报:按行解析时间戳与消息内容,调用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标签对应stdoutstderr

源码注释明确说明了两者的差异(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(容器名)
    • streamstdoutstderrtty
    • 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:验证停止插件后状态被正确记录、恢复后从断点续读。

实战要点小结

  • 确认容器使用localjson-filejournald日志驱动,并保证 Telegraf 对 endpoint 有访问权限(本机通常需要 telegraf 用户加入docker组或调整 socket 权限)。
  • 默认只采集running状态容器;需要采集历史日志时设置from_beginning = true并配合状态持久化使用。
  • 容器重名频繁时开启source_tag = true,利用容器 ID 前 12 位唯一标识数据来源。
  • 通过container_name_include/excludedocker_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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 7:48:36

Simulink中强化学习与VR可视化融合实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 7:48:31

国产大模型DeepSeek与Qwen的技术解析与应用实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 7:47:09

Java程序员职业发展路径与核心技术解析

1. Java程序员的职业发展路径解析作为一名从业十年的Java开发者,我见证了太多同行在职业发展中的迷茫与突破。Java程序员的职业发展绝非简单的技术堆砌,而是一个需要系统规划的成长体系。从初级工程师到架构师,每个阶段都有其独特的技术重点和…

作者头像 李华
网站建设 2026/9/14 7:40:15

俄罗斯车牌检测实战:Haar级联与OpenCV调优

简介:一款已针对OpenCV 4.x优化过的Haar级联分类器模型,用于检测俄罗斯车辆的车牌,它借助Haar特征提取图像中的边缘、线条、角点等局部模式,再通过多级联分类器逐层筛选,以低误报率快速定位车牌区域。该模型经过了大量…

作者头像 李华
网站建设 2026/9/14 7:39:39

COMSOL激光熔覆与选区熔融仿真:从建模到收敛控制全攻略

做增材制造仿真这几年,被问最多的一个问题就是:“COMSOL到底能不能算激光熔覆和选区熔融?”我的答案一直是:能,而且很能,但前提是你得把物理模型搭对。很多人一上来就建一个特别精细的三维模型,…

作者头像 李华