Go-Zero 项目开发43:基于 Filebeat 收集各个服务的日志信息

纲要

  • 背景与动机:为什么在 go-zero 微服务架构中需要轻量级日志采集器
  • 认识 Filebeat:与 Logstash 的对比及其优势
  • Filebeat 核心工作过程:HarvesterInput 与状态持久化
  • go-zero 项目中输出结构化日志
  • Filebeat 安装与基础采集配置
  • Filebeat 与 ELK 集成配置
    • Logstash 侧配置 beats 输入
    • Filebeat 侧输出到 Logstash
    • 自定义字段与管道处理
  • 全链路验证:通过 APISIX 产生流量并观察 Kibana 结果
  • 排错思路与调试技巧

为什么需要 Filebeat

在微服务架构中,日志分散在各个服务节点上。Logstash 虽然具备强大的日志采集、过滤和转发能力,但它由 Java 实现,启动速度较慢,运行时内存占用较高。如果让 Logstash 和业务服务部署在同一台机器上,很容易与业务进程争抢 CPU 和内存资源,影响核心服务的稳定性。

因此在每个服务节点上,我们需要一个更轻量级的采集器,将原始日志高效地推送给远端的 Logstash 或直接写入 ElasticsearchBeats 系列中的 Filebeat 正是这样一款轻量级工具,采用 Go 语言编写,资源开销极小,专注于"采集并转发"这一核心任务,数据处理逻辑则交给后端的 Logstash 完成。

Filebeat 核心工作方式

Filebeat 内部由两个关键组件配合工作:

  • Input:负责管理所有需要读取的文件路径,并为每个文件启动一个 Harvester
  • Harvester:逐行读取文件内容,并将新产生的事件发送到配置的输出目标。

Filebeat 还会在本地磁盘维护一个 registry 文件,记录每个日志文件的读取偏移量。即使进程重启,也能从上次中断的位置继续采集,避免重复发送或遗漏数据。

下面的流程图描述了整个采集与转发过程:
#mermaid-svg-oJxZZBr8Dia7pQWm{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-oJxZZBr8Dia7pQWm .error-icon{fill:#552222;}#mermaid-svg-oJxZZBr8Dia7pQWm .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-oJxZZBr8Dia7pQWm .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-oJxZZBr8Dia7pQWm .marker{fill:#333333;stroke:#333333;}#mermaid-svg-oJxZZBr8Dia7pQWm .marker.cross{stroke:#333333;}#mermaid-svg-oJxZZBr8Dia7pQWm svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-oJxZZBr8Dia7pQWm p{margin:0;}#mermaid-svg-oJxZZBr8Dia7pQWm .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm .cluster-label text{fill:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm .cluster-label span{color:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm .cluster-label span p{background-color:transparent;}#mermaid-svg-oJxZZBr8Dia7pQWm .label text,#mermaid-svg-oJxZZBr8Dia7pQWm span{fill:#333;color:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm .node rect,#mermaid-svg-oJxZZBr8Dia7pQWm .node circle,#mermaid-svg-oJxZZBr8Dia7pQWm .node ellipse,#mermaid-svg-oJxZZBr8Dia7pQWm .node polygon,#mermaid-svg-oJxZZBr8Dia7pQWm .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-oJxZZBr8Dia7pQWm .rough-node .label text,#mermaid-svg-oJxZZBr8Dia7pQWm .node .label text,#mermaid-svg-oJxZZBr8Dia7pQWm .image-shape .label,#mermaid-svg-oJxZZBr8Dia7pQWm .icon-shape .label{text-anchor:middle;}#mermaid-svg-oJxZZBr8Dia7pQWm .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-oJxZZBr8Dia7pQWm .rough-node .label,#mermaid-svg-oJxZZBr8Dia7pQWm .node .label,#mermaid-svg-oJxZZBr8Dia7pQWm .image-shape .label,#mermaid-svg-oJxZZBr8Dia7pQWm .icon-shape .label{text-align:center;}#mermaid-svg-oJxZZBr8Dia7pQWm .node.clickable{cursor:pointer;}#mermaid-svg-oJxZZBr8Dia7pQWm .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-oJxZZBr8Dia7pQWm .arrowheadPath{fill:#333333;}#mermaid-svg-oJxZZBr8Dia7pQWm .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-oJxZZBr8Dia7pQWm .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-oJxZZBr8Dia7pQWm .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oJxZZBr8Dia7pQWm .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-oJxZZBr8Dia7pQWm .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oJxZZBr8Dia7pQWm .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-oJxZZBr8Dia7pQWm .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-oJxZZBr8Dia7pQWm .cluster text{fill:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm .cluster span{color:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-oJxZZBr8Dia7pQWm .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-oJxZZBr8Dia7pQWm rect.text{fill:none;stroke-width:0;}#mermaid-svg-oJxZZBr8Dia7pQWm .icon-shape,#mermaid-svg-oJxZZBr8Dia7pQWm .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-oJxZZBr8Dia7pQWm .icon-shape p,#mermaid-svg-oJxZZBr8Dia7pQWm .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-oJxZZBr8Dia7pQWm .icon-shape .label rect,#mermaid-svg-oJxZZBr8Dia7pQWm .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-oJxZZBr8Dia7pQWm .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-oJxZZBr8Dia7pQWm .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-oJxZZBr8Dia7pQWm :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 日志文件A
Harvester1
日志文件B
Harvester2
Input Manager
Registry 磁盘
Output: Logstash / ES / Console

在 go-zero 项目中输出结构化日志

为了更好地配合 Filebeat 进行过滤和解析,建议业务服务输出结构化日志。以 go-zero 为例,我们可以基于 logx 配置让日志同时写入文件,并使用 json 格式。

首先,使用 go-zero 脚手架生成一个最简 API 服务(基于 go-zero@latest):

bash 复制代码
go install github.com/zeromicro/go-zero/tools/goctl@latest
goctl api new demo
cd demo

修改 demo/etc/demo-api.yaml,增加日志文件输出与 JSON 格式配置:

yaml 复制代码
Name: demo-api
Host: 0.0.0.0
Port: 8888

Log:
  ServiceName: demo-api
  Mode: file
  Path: logs
  Level: info
  Encoding: json

demo/internal/svc/servicecontext.go 中无需额外修改,go-zero 会根据配置文件自动初始化 logx。启动服务后,会在 logs/ 目录下产生类似 demo-api.log 的文件,内容为 JSON 行:

json 复制代码
{"@timestamp":"2026-07-09T10:00:00.123+08:00","level":"info","content":"starting server at 0.0.0.0:8888"}

这样 Filebeat 可以直接按 JSON 解析日志,提取字段。

Filebeat 安装与基础采集测试

在日志所在服务器上下载并安装 Filebeat(示例为 Linux amd64):

bash 复制代码
curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-8.12.0-linux-x86_64.tar.gz
tar xzf filebeat-8.12.0-linux-x86_64.tar.gz
cd filebeat-8.12.0-linux-x86_64

安装目录下自带 filebeat.yml,内容繁杂。为快速验证,我们准备一份精简配置 demo-filebeat.yml,仅采集 go-zero 服务日志并输出到控制台:

yaml 复制代码
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /path/to/demo/logs/*.log
  fields:
    app: demo-api
    env: dev
  fields_under_root: true

output.console:
  pretty: true

测试运行:

bash 复制代码
./filebeat -e -c demo-filebeat.yml

-e 表示关闭 Filebeat 自身的系统日志输出,-c 指定配置文件。启动后,若配置正确,控制台会打印出采集到的 JSON 日志事件。

Filebeat 与 ELK 集成

生产环境中,通常将 Filebeat 作为 Logstash 的前置采集器,再由 Logstash 过滤后写入 Elasticsearch

Logstash 配置

Logstashpipeline 配置中,添加 beats 输入插件,监听默认的 5044 端口:

ruby 复制代码
input {
  beats {
    port => 5044
  }
}

filter {
  # 可在此处对 JSON 日志做进一步处理
  json {
    source => "message"
  }
}

output {
  elasticsearch {
    hosts => ["http://elasticsearch:9200"]
    index => "demo-api-%{+YYYY.MM.dd}"
  }
  stdout { codec => rubydebug }
}

Filebeat 输出到 Logstash

修改 Filebeat 配置,指定输出为 logstash 并增加 type 字段以便区分数据来源:

yaml 复制代码
filebeat.inputs:
- type: log
  enabled: true
  paths:
    - /path/to/demo/logs/*.log
  fields:
    app: demo-api
    env: dev
    type: go-zero-log
  fields_under_root: true

output.logstash:
  hosts: ["logstash:5044"]

重启 Logstash 后,再启动 Filebeat,即可将日志推送到 ELK 管道。

APISIX 网关日志采集(可选扩展)

文中原始案例使用了 APISIX 的访问日志。在实际 go-zero 项目中,网关往往也部署在同一节点,可以将 APISIX 日志一并采集。只需在 filebeat.inputs 中增加一条路径:

yaml 复制代码
- type: log
  enabled: true
  paths:
    - /usr/local/apisix/logs/access.log
  fields:
    app: apisix-gateway
    type: apisix-access
  fields_under_root: true

APISIX 日志也是 JSON 格式,后续在 Logstash 中可统一清洗。

全链路验证

  1. 启动 ElasticsearchKibana
  2. 启动 Logstash,确认监听 5044 端口。
  3. 启动 Filebeat,观察日志是否有输出。
  4. go-zero 服务发送几次请求:
bash 复制代码
curl http://localhost:8888/from/you
  1. KibanaDiscover 界面创建索引模式 demo-api-*,即可看到带有 app: demo-api 的日志。
  2. 若同时配置了 APISIX,也可查看网关访问日志。

常见问题与调试思路

  • Kibana 中看不到自定义字段

    检查 fields_under_root 是否为 true,确保字段在事件顶层。若字段缺失,可先用 output.console 验证 Filebeat 输出是否正确。

  • Logstash 未收到数据

    确认 Logstash 防火墙已放行 5044 端口,且 beats 输入插件未被注释。可以先让 Filebeat 输出到控制台,确认采集端正常,再逐步排查传输链路。

  • 采集重复或遗漏

    检查 registry 文件是否可写。Filebeat 会在数据目录下维护该文件,若因权限问题无法写入,则每次重启都会从头读取。

  • 日志文件轮转

    Filebeat 通过 inode 跟踪文件,能够正确应对 logrotate 等场景,无需特殊配置。

总结

本文从 go-zero 微服务的日志输出切入,介绍了如何使用 Filebeat 作为轻量级采集器替代同机部署的 Logstash,完成日志的采集、字段增强,并最终送入 ELK 栈。

通过精简的配置和清晰的调用链,开发同学可以快速为自己的 go-zero 项目搭建一套稳定、低开销的日志收集系统。

相关推荐
丈剑走天涯2 小时前
JDK 17 正式特性
java·开发语言
秋田君2 小时前
QT_QFontDialog类字体对话框
开发语言·qt
圣光SG2 小时前
Java操作题练习(七)
java·开发语言·算法
麻瓜老宋4 小时前
AI开发C语言应用按步走,表达式计算器calc的第二十三步,多行输入、进制输出、错误恢复、常量折叠、配置加载等
c语言·开发语言·atomcode
q567315234 小时前
企业级 HTTP 代理采购选型:技术评估清单 15 项
开发语言·网络·爬虫·网络协议·http·隧道ip·代理ip
天天进步20155 小时前
Python全栈项目--智能办公自动化系统
开发语言·python
cm04Z9c915 小时前
C#摸鱼实录——IoC与DI案例详解
开发语言·c#
long3166 小时前
Java 新手入门与实战开发指南
java·开发语言
摩西蒙6 小时前
计算机网络
开发语言·计算机网络·php