go应用日志应先写入本地json文件,再由filebeat或logstash异步采集至elasticsearch;直连es易导致性能下降、日志丢失和集群压力过大。

Go 应用日志怎么发到 Elasticsearch?别直连,走 Filebeat 或 Logstash
直接在 Go 代码里用 elastic/go-elasticsearch 客户端往 ES 写日志是错的:会拖慢请求、丢日志、压垮 ES。生产环境必须解耦——日志先落地文件,再由 Filebeat 或 Logstash 异步采集转发。
- Go 进程只负责写结构化 JSON 到本地文件(比如
/var/log/myapp/app.log),不关心网络、重试、背压 -
Filebeat轻量、低资源占用,适合大多数场景;Logstash功能强但更重,仅当需复杂过滤(如字段拆解、正则清洗)时才上 - 如果硬要用 Go 直连 ES,至少得加缓冲队列 + 异步 goroutine + 重试退避,但维护成本远超收益
logrus/zap 输出 JSON 日志时,哪些字段必须有?
没有固定“必须字段”,但 Kibana 查起来不痛苦的关键是:服务名、时间戳、级别、traceID(如有)、错误堆栈(如有)。否则你搜 status:500 会发现全是空的 message 字段。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 用
logrus.JSONFormatter{TimestampFormat: "2006-01-02T15:04:05.000Z07:00"},避免默认毫秒精度丢失 - zap 推荐用
zapcore.NewJSONEncoder(zapcore.EncoderConfig{...})显式控制字段名,比如把level改成小写"level",和 Logstash 默认解析习惯对齐 - 别依赖
logrus.WithField("error", err)—— err 对象不会被 JSON 序列化,要写成"error": err.Error()或用logrus.WithError(err)
Filebeat 配置里最常配错的三处
filebeat.yml 看似简单,但三个地方一错,日志就进不了 ES:路径没权限、JSON 解析关着、输出目标写错端口。
-
paths必须指向真实可读文件,且filebeat用户(通常是root或filebeat)要有读权限;常见错误是路径写成./logs/*.log,而实际运行目录不是预期位置 - 启用 JSON 解析必须加
json.keys_under_root: true和json.overwrite_keys: true,否则日志内容全塞在message字段里,Kibana 搜不到status字段 -
output.logstash.hosts写["localhost:5044"]前,先确认 Logstash 的beats input确实监听了5044(不是5000或9200);若直连 ES,则改用output.elasticsearch.hosts,注意 ES 默认不开放远程 HTTP(需改network.host)
Logstash pipeline 里 filter 怎么写才不丢字段?
很多人的 filter 区块一加 json { source => "message" } 就发现 host、timestamp 全没了——因为默认会覆盖顶层字段。这不是 bug,是设计。
- 加
remove_field => ["message"]清掉原始字符串,避免冗余 - 用
mutate { rename => { "@timestamp" => "log_timestamp" } }保留下原始时间戳,否则 Kibana 会用 Logstash 接收时间而非日志产生时间 - 如果 Go 日志里有嵌套结构(如
"http": {"method":"GET","path":"/api/user"}),别用dissect,直接json { source => "message" }更稳
filebeat test output 和 logstash -t -f /etc/logstash/conf.d/*.conf 先验配置,比进 Kibana 盲搜快得多。golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










