Beego v2 日志系统必须使用 github.com/beego/beego/v2/core/logs,初始化 log := logs.NewLogger(10000) 后,需显式调用 log.SetLogger(logs.AdapterConsole, ...) 和 log.SetLogger(logs.AdapterFile, ...) 启用双输出;默认不显示文件名和行号,须调用 logs.EnableFuncCallDepth(true) 并根据封装层级设 SetLogFuncCallDepth;异步模式需 log.Async() 且程序退出前调用 log.Close() 或 log.Flush() 防丢日志。

Beego v2 的日志系统已完全模块化,github.com/beego/beego/v2/core/logs 是唯一推荐路径;v1 的 beego.BeeLogger 已停止维护,生产环境务必避免混用。
如何初始化并添加 console 和 file 双输出引擎
直接调用 logs.NewLogger() 创建实例后,必须显式调用 SetLogger() 才能启用输出。同一 logger 可叠加多个引擎,比如同时输出到终端和文件:
-
log := logs.NewLogger(10000)—— 缓存大小设为 10000 条,过小会导致异步丢日志 -
log.SetLogger(logs.AdapterConsole, `{"level":4}`)—— 控制台只输出Warn及以上(数值 4 对应LevelWarn) -
log.SetLogger(logs.AdapterFile, `{"filename":"app.log","daily":true,"maxdays":30}`)—— 文件按天切割,保留 30 天
注意:第二个参数是 JSON 字符串,不是 Go map;键名必须小写(如 filename,非 Filename),否则配置被忽略且无报错。
为什么日志里不显示文件名和行号
默认关闭调用栈定位,即使你写了 log.Debug("msg"),也不会自动补上 main.go:42 这类信息。要开启需两步:
- 全局启用:
logs.EnableFuncCallDepth(true) - 若封装了日志调用(比如写了个
MyLog.Info()包一层),必须额外调用log.SetLogFuncCallDepth(3)—— 数值代表跳过几层函数帧,默认是 2(即跳过log.Info自身和它的直接调用者),封装一层就加 1
漏掉第二步会导致所有日志都显示为封装函数所在行,而非真实业务代码位置。
异步日志为何有时不输出或丢失最后几条
log.Async() 会启动 goroutine 异步刷日志,但程序退出时若未主动 flush,缓存中的日志会被丢弃。常见于命令行工具或短生命周期服务:
- 在
main()结尾加defer log.Close()或log.Flush() - 不要依赖
os.Exit()前的 defer —— 它不会执行 - 缓存大小(
NewLogger(n)的n)太小(如 100)在高并发下容易触发丢弃,建议至少 10000
另外,Async() 后不能再调用 SetLogger(),否则 panic:异步模式下引擎不可变更。
Beego v1 与 v2 日志包的 import 路径和行为差异
v1 使用 github.com/astaxie/beego/logs,v2 必须用 github.com/beego/beego/v2/core/logs。二者不兼容:
- v1 的
logs.SetLogger("file", ...)第一个参数是字符串,v2 的SetLogger()第一个参数是常量logs.AdapterFile - v2 不再支持 smtp 引擎(已移除),如需邮件告警,得自己基于
conn或外部库实现 - v2 的
GetLogger("ORM")返回的是独立 logger 实例,不再共享级别和引擎,适合模块隔离
最易踩的坑是:项目里同时 import 两个版本,Go 模块 resolver 可能静默选错,导致 SetLogger 调用无效却无任何提示 —— 检查 go.mod 中是否残留 v1 依赖。


















