Beego需将日志转为单行JSON格式并配置Filebeat解析:禁用默认日志器,自定义Adapter实现json.Marshal输出,含time(ISO8601/UnixMs)、level等字段;Filebeat须设json.keys_under_root:true、time_key/time_format匹配;禁用Beego异步日志;panic需通过RecoverFunc捕获并JSON化。

Beego 本身不内置 Beats 支持,直接“整合 Beats”实际是指:让 Beego 应用输出符合 Filebeat 或 Metricbeat 可采集格式的日志(如 JSON 行格式),再由 Beats 端配置对应输入/解析规则。硬连、SDK 调用或中间件注入方式均非官方路径,也无成熟封装。
Beego 日志输出必须转为 JSON 行格式(否则 Filebeat 无法结构化解析)
Beego 默认使用 logs.BeeLogger,其输出是纯文本(如 [INFO] 2024/05/10 10:23:41 handler.go:123] user login success),Filebeat 的 json 解码器会直接失败并丢弃日志。
- 必须禁用 Beego 默认日志器的彩色/格式化输出,改用自定义
logs.Adapter或替换为logrus/zerolog等支持 JSON 的 logger - 推荐在
main.go初始化阶段替换全局 logger:logs.SetLogger(logs.AdapterConsole, `{"level":"info","format":"json"}`)—— 但注意 Beego 1.x 的consoleadapter 不真正支持format: json,该配置无效;需自行实现logs.Adapter接口,WriteMsg中调用json.Marshal输出单行 JSON - 关键字段建议包含:
time(ISO8601)、level、msg、file、line、trace_id(如有链路追踪)
Filebeat 配置需显式启用 JSON 解析并指定时间字段
若日志已为每行一个 JSON 对象,但 Filebeat 仍解析失败,大概率是未开启 json 解码器或时间字段不匹配。
- 在
filebeat.inputs中必须设置:input_type: log paths: - /var/log/myapp/*.log json.keys_under_root: true json.overwrite_keys: true json.time_key: "time" json.time_format: "ISO8601"
-
json.keys_under_root: true是关键,否则所有字段会被包在json.*下,Kibana 中查不到level或msg - 若 Beego 日志中
time字段是毫秒级 Unix 时间戳(如1715336621123),需改用json.time_format: "UnixMs",否则 Filebeat 会报invalid time format
避免用 Beego 的 logs.Async 模式对接 Beats
Beego 开启异步日志(logs.SetLogger(..., `{"async":true}`))后,日志写入会经 channel 缓存,导致:
- 进程退出时未 flush 的日志丢失,Filebeat 尾部读取(tail)不到最后几条
- JSON 行可能被截断(如大日志体 + 异步 buffer 边界错位),造成 Filebeat 解析出错并跳过整行
- 高并发下 timestamp 字段可能严重滞后于真实发生时间,影响排查时效性
生产环境应关闭异步:logs.SetLogger(logs.AdapterFile, `{"filename":"/var/log/myapp/app.log","async":false}`),再由 Filebeat 负责可靠采集与重试。
Beats 不处理 Beego 的 panic 堆栈,需额外捕获
Beego 的 recover 机制默认将 panic 打印到标准错误(stderr),而 Beego 日志器通常只接管 stdout 和文件。这意味着:
- panic 日志不会进入你配置的 JSON 日志文件,Filebeat 无法采集
- 除非重定向 stderr 到同一文件(不推荐,混入非 JSON 内容会导致解析失败)
- 正确做法是在
app.conf中启用RecoverPanic = true,并在init()或main()中替换beego.RecoverFunc,把 panic 信息格式化为 JSON 后写入日志文件
例如:
beego.RecoverFunc = func(c *context.Context, err interface{}) {
logEntry := map[string]interface{}{
"level": "fatal",
"msg": "panic recovered",
"error": fmt.Sprintf("%v", err),
"stack": debug.Stack(),
"time": time.Now().Format(time.RFC3339),
}
b, _ := json.Marshal(logEntry)
logs.GetBeeLogger().Output(0, string(b))
}
最易被忽略的是时间字段格式与 Filebeat json.time_format 的严格匹配——差一个字母(比如写成 ISO8601 但实际输出带毫秒或时区偏移不全),Filebeat 就静默跳过整行,且默认不报错。建议先用 filebeat test input 验证单行日志解析结果。


















