Graylog不支持直接接收Go应用stdout日志,必须通过Filebeat等中间采集器转发;其HTTP API仅用于管理操作,日志接入需依赖GELF或Beats Input,且Go端须输出结构化JSON并配置Filebeat正确解析与转发。

Graylog 本身不直接接收 Go 应用 stdout 日志,必须通过中间采集器(如 Filebeat、Fluent Bit 或 GELF 客户端)转发。裸用 log.Printf 或未结构化的 zap 输出,Graylog 收不到可解析字段,等于白搭。
为什么不能让 Go 直连 Graylog 的 HTTP API?
Graylog 的 REST API(/api/system/logs 等)不接受原始日志 POST,它只用于管理操作;真正接收日志的是 Inputs(如 GELF UDP/TCP、Beats HTTP 端口)。直接 HTTP POST 日志到 Graylog 会返回 404 或 405 错误,不是设计用途。
- Go 应用若想“直发”,必须实现 GELF 协议(UDP/TCP),但生产环境不推荐:UDP 易丢包、TCP 需维护连接、无重试/缓冲/背压控制
- 官方明确推荐路径是:Go 输出结构化 JSON → 容器或主机上部署 Filebeat → Filebeat 配置为 Beats input → Graylog 接收
- 用
gelf第三方库(如mpdroog/gelf)虽可行,但丢失了 Filebeat 的 registry 持久化、文件断点续传、多路复用等关键能力
Filebeat 配置要点:确保 Go 日志能被正确识别和解析
Go 微服务通常将结构化日志输出到 os.Stdout(Docker/K8s 场景),Filebeat 必须从容器日志文件或 Docker socket 读取,并打上 service 标签。常见错误是 paths 写错或未启用 json.keys_under_root。
- 确认 Filebeat 启用了 JSON 解析:
json.keys_under_root: true,否则所有字段会嵌套在json.下,Graylog 提取器无法命中 -
paths要匹配实际容器日志位置:Docker 默认是/var/lib/docker/containers/*/*.log;K8s 中常用/var/log/pods/*/*/log - 必须加
fields.service_name: user-service(值从环境变量注入更灵活),否则所有日志混在一起,无法按服务过滤 - 如果 Go 日志含
trace_id字段,Filebeat 不需额外配置,Graylog 后续可用提取器或 Pipeline 直接引用该字段
Graylog Input 选 Beats 还是 GELF?
选 Beats。GELF 虽轻量,但要求 Go 端主动构造协议头、压缩、分块,出错难排查;Beats 是事实标准,且 Filebeat 已内置对 Go JSON 日志的友好支持(自动识别 level、ts、message)。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 创建 Input 时,Type 选
Beats,Bind address 建议用0.0.0.0,Port 设为5044(Filebeat 默认) - 不要开启 TLS 初期调试;若后期需加密,Filebeat 配置
ssl.certificate_authorities+ Graylog Input 开 TLS 即可 - 避免同时开多个 Beats Input 端口——Filebeat 可批量推送至单个端点,多端口反而增加运维复杂度
- Graylog Web 界面中,System → Inputs → Launch new input → Beats,填完保存后,记下 Generated ID,后续 Sidecar 关联要用
Go 端 zap 初始化必须带 time 和 level 字段
Graylog 默认按 timestamp 字段排序和索引,若 Go 日志没输出时间戳或格式非 ISO8601,日志会出现在错误时间线,甚至被丢弃(取决于 Elasticsearch index template)。
- 禁用
zap.NewDevelopment():它输出 console 格式,非 JSON,Filebeat 无法解析 - 必须用
zap.NewProduction()或自定义EncoderConfig,确保TimeKey: "timestamp"且EncodeTime: zapcore.ISO8601TimeEncoder - 手动注入必要字段:
logger = logger.With(zap.String("service_name", os.Getenv("SERVICE_NAME"))),别依赖注释或 magic string - 若用 K8s,建议通过 Downward API 注入
metadata.name作为service_name,比硬编码更可靠
最易被忽略的一点:Filebeat 的 json.add_error_key: true 必须开启。当某行日志不是合法 JSON(比如 panic 堆栈混了纯文本),Filebeat 会把整行塞进 error.message 字段并继续处理,否则该行直接被丢弃——而 Go 的 recover 日志、第三方库 debug 输出,恰恰最容易破环 JSON 结构。

















