Go服务日志必须经Filebeat等采集器中转,输出标准JSON到stdout/文件,禁用拼接字符串;需用zerolog/logrus/slog,规范时间格式与字段名;Filebeat须配multiline防panic堆栈错位;Logstash需date filter校准时间戳并预建index template统一映射。

Go 服务不能“直接对接 ELK”,必须走采集器(Filebeat / Logstash / Fluent Bit)中转;否则大概率丢日志、卡 goroutine、时间戳错乱、ES 拒绝写入。
Go 日志必须输出标准 JSON 到 stdout 或文件
ELK 无法解析 log.Printf("user %d login", uid) 这类拼接字符串——整行会被塞进 message 字段,Kibana 里根本没法按 user_id 过滤或聚合。Logstash 的 json codec 也会因格式非法直接报 json parse error。
- 用
zerolog、logrus或slog替代标准log包 -
zerolog.TimeFieldFormat = time.RFC3339Nano,确保时间字段可被 Logstash 的datefilter 识别 - 字段名禁用中文、空格、@ 开头(如
@timestamp),ES 7+ 会拦截;改用timestamp或ts - 容器环境一律
SetOutput(os.Stdout);宿主机部署才考虑os.OpenFile写文件
Filebeat 配置要避开轮转丢日志和 multiline 错位
Go panic 堆栈是多行的,不配 multiline,Filebeat 会把每行当一条日志切开,trace_id 和错误上下文就散了;但配错又容易吞掉首行或错位合并。
- 在
filebeat.yml中启用multiline,匹配 Go panic 起始行:pattern: '^[[:space:]]*panic:',negate: true,match: after - 若用
lumberjack轮转日志,Filebeat 必须设force_close_files: true,否则 logrotate 切文件瞬间可能漏几行 - 路径配置要精准,避免通配符误扫旧日志文件(如
/var/log/app/*.log可能读到已归档的app.log.1.gz) - 别用
fileinput 插件直读文件——这是反模式:多实例竞争句柄、时序错乱、v7.0+ 默认关闭type字段导致旧过滤规则失效
Logstash filter 必须校准时间戳并处理字段类型冲突
Go 输出的 "time":"2026-05-22T12:42:33.123Z" 是字符串,ES 存的是 @timestamp 字段;不显式转换,Kibana 时间轴就全乱,且无法按分钟聚合。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- filter 段必加:
date { match => ["time", "ISO8601"] target => "@timestamp" }(假设日志里时间字段叫time) - 首次写入 ES 前,预建
index template,用dynamic_templates统一将字符串字段映射为keyword,避免text分词干扰user_id精确匹配 - 字段值类型必须一致:别第一次写
"duration": 123(int),后面又写"duration": "123ms"(string),ES 会拒掉整条 - 开发环境可用
tcpinput 测试:input { tcp { port => 5000 codec => json } };生产环境优先beatsinput,更轻量可靠
直连 Elasticsearch 要绕过三个硬坑
用 elastic/go-elasticsearch/v8 直发日志可行,但只适合强控场景;多数项目因连接管理不当导致 OOM、连接泄漏或 bulk 失败静默丢数据。
- ES 地址必须带协议,如
http://elasticsearch:9200,漏掉http://会静默失败 - 单次写入禁用
Index()逐条调用,改用BulkIndexer批量提交(500–1000 条/次),否则 ES 写入压力飙升 - bulk 请求体每行必须是合法 JSON,操作行(
{"index":{}})和文档行严格交替;多一个逗号、少一个换行,整个 batch 就失败 - 遇到
429 Too Many Requests,别无脑重试——加指数退避,或降级写本地文件暂存
最常被忽略的是字段类型冲突和时间戳校准:哪怕日志 JSON 格式完全正确,只要 duration 类型变过一次,或 @timestamp 没从原始字段解析出来,Kibana 查询就会失灵。

















