beego v2 不支持直接 json 日志输出,因 beelogger 私有 formatter 且无 setformatter 方法;需手动创建 logs.logger 实例并设置自定义 json formatter,同时禁用 color 和 daily 配置以保证 json 完整性。

Beego 默认日志格式不支持直接 JSON 化输出,必须通过自定义 Formatter 实现;且 v2 版本中 logs.BeeLogger 不再暴露底层 SetFormatter 方法,需绕过封装或改用底层 logs.Logger 实例。
beego v2 中无法直接 SetFormatter 的原因
Beego v2 将日志模块解耦为独立包 github.com/beego/beego/v2/core/logs,但全局 beego.BeeLogger 是一个已初始化的 *logs.Logger 实例,其内部 formatter 字段是私有(小写)且无公开 setter。调用 beego.SetLogger 或 beego.BeeLogger.SetLogger 只能切换 adapter,不能修改序列化逻辑。
常见错误现象:beego.BeeLogger.SetFormatter 报错 undefined,或自定义 formatter 被忽略 —— 这不是配置遗漏,而是 API 本身未开放。
- 必须放弃
beego.*日志快捷函数(如beego.Info),改用自己构造的*logs.Logger - 若坚持用
beego.*,只能接受默认格式(含时间、文件、级别缩写等),无法 JSON 化 - v1 版本(
github.com/astaxie/beego)虽有SetFormatter,但已停止维护,不建议新项目使用
手动构造 Logger 并设置 JSON Formatter
要输出结构化 JSON 日志,需跳过 beego.BeeLogger,直接使用 logs.NewLogger 创建实例,并传入自定义 Formatter 函数。该函数接收 *logs.LogMsg,返回字符串 —— 你在此处控制 JSON 序列化逻辑。
示例关键步骤:
<pre class="brush:php;toolbar:false;">import (
"encoding/json"
"github.com/beego/beego/v2/core/logs"
)
type JSONFormatter struct{}
func (f JSONFormatter) Format(msg *logs.LogMsg) string {
data := map[string]interface{}{
"time": msg.Time.Format("2006-01-02T15:04:05.000Z07:00"),
"level": logs.Levels[msg.Level],
"msg": msg.Msg,
"file": msg.File,
"line": msg.Line,
"func": msg.Func,
"request_id": msg.Ctx["request_id"], // 若已注入上下文
}
b, _ := json.Marshal(data)
return string(b) + "\n"
}
func main() {
logger := logs.NewLogger(10000)
logger.SetLogger(logs.AdapterConsole)
logger.SetFormatter(JSONFormatter{})
logger.EnableFuncCallDepth(true) // 否则 File/Line 为空
logger.Debug("hello world")
}
logs.LogMsg 包含完整元数据:时间、级别、消息体、调用位置、上下文(<code>msg.Ctx)-
logs.Levels是内置映射,可将数字级别转为字符串(如"debug") - 注意:JSON 字段名需与下游日志系统(如 Loki、ELK)约定一致,避免字段名大小写混用
文件输出时 JSON 格式需禁用 color 和 daily 拆分
当使用 AdapterFile 输出 JSON 日志时,两个配置项会破坏 JSON 结构完整性:
将一个或多个视频上传至YouTube。当用户想“上传到YouTube”“发YouTube”“批量上传”“upload to YouTube”“post videos to YouTube”或发布到YouTube时使用此技能。
-
"color": true:插入 ANSI 转义字符,导致 JSON 解析失败 -
"daily": true:按天轮转会截断正在写入的 JSON 行(尤其异步模式下),造成半条 JSON
正确配置示例:
<pre class="brush:php;toolbar:false;">logger.SetLogger(logs.AdapterFile, `{
"filename": "logs/app.json",
"maxlines": 0,
"maxsize": 0,
"daily": false,
"maxdays": 0,
"color": false,
"level": 7
}`)
若需轮转,应启用 "maxlines"
"maxsize",并确保每条日志是独立、完整的一行 JSON(即不换行、不嵌套多行对象)。
beego.Controller 中注入 request_id 并透传到日志
要在 JSON 日志中携带 trace ID,不能依赖中间件自动注入到 beego.BeeLogger(它不支持 ctx 透传),而应在每个 handler 内显式构造带上下文的日志实例,或使用 log.WithContext 模式(需自行封装)。
推荐做法:在 Controller.Prepare() 中提取或生成 request_id,存入 this.Data 或局部变量,再调用自定义 logger 的 DebugWithContext 类方法:
<pre class="brush:php;toolbar:false;">func (c *MainController) Prepare() {
rid := c.Ctx.Input.Header("X-Request-ID")
if rid == "" {
rid = uuid.New().String()
}
c.Data["request_id"] = rid
}
func (c *MainController) Get() {
rid := c.Data["request_id"].(string)
// 使用带 context 的 logger
logger.DebugWithContext(map[string]interface{}{"request_id": rid}, "handling GET /")
}
注意:标准 logs.Logger
DebugWithContext,需自行包装一个支持 map[string]interface{} 作为额外字段的 wrapper 函数 —— 这是 JSON 日志真正可用的关键,否则所有日志都丢失请求维度。










