beego v2 正确初始化 core/logs 需:log := logs.newlogger(10000) 创建带缓冲实例,log.setlogger(logs.adapterfile, {"filename":"logs/app.log","daily":true,"maxdays":7,"level":3}) 指定文件输出,log.setlevel(logs.levelerror) 设置级别,log.enablefunccalldepth(true) 开启文件行号,且必须调用 log.close() 避免日志丢失。

Beego 的日志模块(core/logs)不是“开箱即用就全好”的配置,尤其在生产环境,必须显式设置输出目标、级别和调用栈信息,否则日志会丢失关键上下文或根本写不到文件;panic 捕获也不能依赖全局开关,得在每个控制器方法里手动加 defer recover(),否则 500 页面背后什么都没记录。
如何正确初始化并配置 core/logs 输出到文件
Beego v2 的日志已拆出为独立模块 github.com/beego/beego/v2/core/logs,不能再用旧版 beego.SetLogger。直接 new 一个 logger 并 set,否则默认只走 console 且无缓冲,高并发下容易丢日志。
- 必须传入缓冲大小(如
10000),否则logs.NewLogger()创建的是无缓冲 logger,Flush()无效,日志可能滞留在内存中不落盘 - 文件路径需确保目录存在,
"filename": "logs/app.log"要求logs/目录已手动创建,否则静默失败(无报错,但文件不生成) -
SetLogger第二个参数是 JSON 字符串,字段名必须小写(如"daily"、"maxdays"),大写(如"Daily")会导致解析失败,日志引擎注册失败 - 若同时需要 console 和 file,要分别调用两次
SetLogger;若只要 file,记得先DelLogger("console"),否则开发机上日志重复刷屏
log := logs.NewLogger(10000)
log.SetLogger(logs.AdapterFile, `{"filename":"logs/app.log","daily":true,"maxdays":7,"level":3}`)
log.SetLogger(logs.AdapterConsole) // 可选:保留控制台输出
log.SetLevel(logs.LevelError) // 只记录 Error 及以上
log.EnableFuncCallDepth(true) // 开启文件名+行号
为什么 beego.SetLogFuncCall(true) 不生效
这个函数属于旧版 beego 主包的全局 logger(beego.BeeLogger),而 v2 中你用的是 core/logs 独立实例,两者完全无关。对独立 logger 生效的是 EnableFuncCallDepth(true),且它默认跳过 2 层调用栈——如果你封装了日志函数(比如写了 MyLog.Debug()),就得调用 SetLogFuncCallDepth(3) 才能打到真实调用处。
- 错误写法:
beego.SetLogFuncCall(true)→ 对core/logs实例无效 - 正确写法:
log.EnableFuncCallDepth(true)或log.SetLogFuncCallDepth(3) - 不设深度时,日志里显示的是
logs/logger.go:xxx,不是你的业务代码行号 - 如果用了
logs.GetLogger("ORM")这类带前缀的 logger,也要单独对它调用EnableFuncCallDepth
控制器内 panic 捕获为何总漏掉堆栈信息
Beego 默认的 recoverpanic = true 只做最简恢复(返回 500 HTML 页面),不记录 panic 原因、不打印堆栈,也不触发你自己的告警逻辑。想拿到完整上下文,必须在每个 controller 方法开头手动加 defer,且 recover() 后要立刻用 debug.Stack() 提取原始堆栈。
- 不能只在
main()里 defer —— main 的 goroutine 捕不到 HTTP 请求 goroutine 的 panic - 不能只
log.Error(r)——r是 panic 值,不是堆栈;要log.Error(string(debug.Stack())) - 别忘了
http.Error(c.Ctx.ResponseWriter, "Internal Server Error", http.StatusInternalServerError),否则客户端收不到 500 响应 - 如果用了
logs.GetLogger("API")分类记录,这里也要用同一个 logger 实例,避免日志分散
func (c *UserController) Post() {
defer func() {
if r := recover(); r != nil {
log.Error("PANIC in UserController.Post: ", r)
log.Error(string(debug.Stack()))
// 发送告警、上报监控等可在此扩展
http.Error(c.Ctx.ResponseWriter, "Internal Server Error", http.StatusInternalServerError)
}
}()
// 你的业务逻辑
}
日志级别设置后为什么某些日志还是没输出
日志级别是「当前级别及更高级别」才输出,不是「当前级别及更低级别」。比如设了 LevelError(数值 3),只有 Emergency(0)、Alert(1)、Critical(2)、Error(3)这四级会输出,Warning(4)及以下全部过滤掉。另外,logger 实例和 Beego 全局 logger 的级别是分开管理的,改 beego.SetLevel 不影响你 logs.NewLogger() 创建的实例。
- 确认你调用的是目标 logger 的
SetLevel,不是beego.SetLevel - 检查是否在
SetLevel之后又调用了SetLogger—— 某些旧文档示例顺序颠倒,会导致级别被重置为默认(LevelDebug) - 如果用
logs.Debug()这类顶层函数,它们走的是全局 logger,不是你新建的实例,需统一用实例方法(log.Debug()) - 级别数值:0=Emergency,1=Alert,2=Critical,3=Error,4=Warning,5=Notice,6=Informational,7=Debug;设 4 就只输出 Warning 及以上
最易忽略的一点:logs.NewLogger(10000) 创建的 logger 不会自动 flush,必须在进程退出前调用 log.Close() 或定期 log.Flush(),否则最后几条日志永远卡在缓冲区里。线上服务常因没 close 导致 crash 前的关键日志全丢。











