Golang开发中的日志收集环境配置 Go语言ELK基础环境搭建

3次阅读

go程序需用logrus/zerolog输出json日志,logstash用tcp/beats输入并配置json+date过滤器对齐时间戳,直连es须复用client实例且用docker服务名通信。

Golang开发中的日志收集环境配置 Go语言ELK基础环境搭建

Go 程序怎么把日志发到 Logstash 或直接写入 elasticsearch

Go 本身不内置日志转发能力,log 包只支持输出到 os.Stdout、文件或自定义 io.Writer。想进 elk,得自己搭桥——要么用 Logstash 做中间接收(推荐初试),要么用客户端库直连 ES(适合结构化日志多、吞吐要求高的场景)。

常见错误是直接把 log.printf 的输出重定向到文件,再指望 Filebeat 自动解析 JSON;结果日志没结构化,Filebeat 拿到的全是纯文本,Kibana 里字段全丢,@timestamp 也没法对齐。

  • logruszerolog 替代原生 log,强制输出 JSON 格式(字段名别用中文,ES 不友好)
  • Logstash 推荐用 tcpbeats input 插件接收,别用 file input 读 Go 的日志文件——时序错乱、权限、轮转都会出问题
  • 直连 ES 用 elastic/go-elasticsearch 客户端时,别在每个 http 请求里新建 *elasticsearch.Client,复用实例,否则 fd 耗尽报 too many open files

Logstash 配置里最常写错的 Filter 和 output 设置

Logstash 的 filter 不是万能解析器,尤其面对 Go 输出的嵌套 JSON 日志,json 过滤器默认只解一层,深层字段如 req.user.id 会变成字符串字面量,不是真正嵌套对象

错误现象:Kibana 里看到 message 字段里塞着一整段 JSON 字符串,而不是展开的字段树。

立即学习go语言免费学习笔记(深入)”;

  • 确保 json 过滤器加 source => "message",且 Go 日志输出前已把整个日志对象序列化为单行 JSON(zerolog.NewConsoleWriter() 默认带换行,要关掉)
  • output { elasticsearch { hosts => ["http://es:9200"] } } 必须显式指定 hosts,不能只写 host(旧版参数,v8+ 已废弃,会静默失败)
  • 如果用了 if [type] == "go-app" 做条件路由,注意 Logstash v7.0+ 默认禁用 type 字段,得在 input 里手动加 type => "go-app"

Go 日志时间戳和 ES @timestamp 对不上怎么办

Go 默认用 time.Now().UTC() 打时间戳,但 Logstash 默认用它自己收到事件的时间设 @timestamp,两者差几毫秒到几秒都算正常;真要对齐,必须让 Go 日志自带精确时间,并让 Logstash 用那个字段覆盖 @timestamp

典型表现:Kibana 折线图里请求延迟尖刺总比监控指标晚一秒出现,排查半天发现是时间源不一致。

  • Go 里用 zerolog.TimeFieldFormat = time.RFC3339Nano,确保时间格式兼容 ES(别用 UnixMilli() 直接打数字,Logstash date 过滤器不认)
  • Logstash filter 里加:date { match => ["time", "ISO8601"] target => "@timestamp" },其中 time 是 Go 日志里你写的字段名(比如 zerolog.TimestampFieldName = "time"
  • ES 索引模板里别设 "@timestamp": {"type": "date_nanos"}——ES v8.0+ 不支持该类型,会拒绝写入,用 "date" 就够,纳秒精度 Logstash 会自动截断

Docker Compose 里 ELK + Go 服务网络连不通的几个硬坑

本地跑通不代表上线没问题,Docker 网络里最常卡在三处:Logstash 听不到 Go 容器的 IP、ES 的 discovery.type=single-node 没生效、Go 客户端连 ES 时用了 localhost

错误信息示例:Failed to connect to http://localhost:9200: dial tcp 127.0.0.1:9200: connect: connection refused —— 这是因为 Go 容器里的 localhost 指向自己,不是宿主机。

  • Go 代码里所有 http://localhost:9200localhost:5044 全部换成 Docker 内网服务名,比如 http://elasticsearch:9200logstash:5044
  • Logstash 的 input { beats { port => 5044 } } 默认只监听 127.0.0.1,必须加 host => "0.0.0.0" 才能收其他容器来的流量
  • ES 的 docker-compose.yml 里除了 environment: - discovery.type=single-node,还得加 - xpack.security.enabled=false(否则 Go 客户端连不上,报 401 Unauthorized

时间戳对齐、网络地址、JSON 层级——这三个点没调对,ELK 看起来在跑,实际查不到日志,或者字段全是空的。调的时候别信“应该可以”,每个环节都抓包或打日志验证一下。

text=ZqhQzanResources