beego日志默认输出到控制台,需调用logs.reset()后用logs.setlogger(logs.adapterfile,配置)切换至文件;若需按日期切分,应改用logs.adaptermultifile并指定datefmt;还需分别设置beego.accesslogs、beego.loglevel和logs.setlevel以避免级别冲突;自定义json格式须用logs.setformatter且注意转义。

Beego 日志输出到文件而不是控制台
默认情况下,beego.Run() 会把日志输出到 os.Stdout,也就是终端。想存成文件,关键不是改日志内容,而是替换掉默认的 Logger 实例。
Beego 的日志模块(logs)底层用的是 logs.BeeLogger,它支持多通道写入(console、file、conn 等)。要关掉控制台、只留文件,得先清空默认输出器,再加一个 logs.FileLogWriter:
logs.Reset()
logs.SetLogger(logs.AdapterFile, `{"filename":"logs/app.log","level":7}`)
beego.SetLogger(logs.GetBeeLogger())
注意两点:level 值是整数(7 = DebugLevel),不是字符串;logs.GetBeeLogger() 必须在 beego.Run() 之前调用,否则会被 Beego 自动覆盖。
按日期自动切分日志文件(beego 2.x)
Beego 自带的 FileLogWriter 不支持按天滚动,直接写 "filename": "logs/app.log" 会导致单文件无限增长。解决办法是换用 logs.AdapterMultiFile —— 它专为时间切分设计,但文档极少,容易配错。
配置要点:
-
filename是基础路径,如"logs/app"(不带后缀) -
datefmt控制切分粒度,"2006-01-02"按天,"2006-01-02 15"按小时 -
maxlines和maxsize仍生效,作为二级切分条件
logs.Reset()
logs.SetLogger(logs.AdapterMultiFile, `{
"filename": "logs/app",
"datefmt": "2006-01-02",
"maxlines": 1000000,
"maxsize": 104857600
}`)
beego.SetLogger(logs.GetBeeLogger())
生成的文件名形如 app.2024-06-15.log。别漏掉 Reset(),否则旧的 console writer 还在,日志会重复输出。
日志级别与 Beego 全局 debug 设置冲突
Beego 有个全局开关 beego.BeeApp.RunMode == "dev" 会强制开启 AccessLogs 和更详细的错误堆栈,和你用 logs.SetLevel() 配的级别可能打架。比如你设了 logs.LevelWarning,但 Beego 仍会把所有 HTTP 请求行打出来。
真正起效的控制点有三个:
-
beego.AccessLogs = false:关掉访问日志(不影响业务日志) -
beego.LogLevel = beego.LevelWarning:影响 Beego 内部组件(router、config 加载等)的日志级别 -
logs.SetLevel(logs.LevelWarning):影响你用logs.Info()、logs.Error()写的日志
三者独立,必须分别设置。尤其 AccessLogs 默认 true,生产环境务必显式关掉。
自定义日志格式(避免 JSON 字段被转义)
Beego 默认日志格式固定(时间+级别+模块+消息),没法直接加 trace_id 或用户 ID。想结构化输出(比如输出 JSON),不能靠修改格式字符串,得用 logs.SetFormatter() 注入自定义函数。
常见陷阱:直接拼 JSON 字符串,结果双引号被日志器二次转义。正确做法是让 formatter 返回已格式化的完整字符串,并确保字段值已安全处理:
logs.SetFormatter(func(b *logs.LogMsg) string {
return fmt.Sprintf(`{"time":"%s","level":"%s","msg":"%s"}`,
b.Created.Format("2006-01-02T15:04:05Z"),
b.LevelName(),
strings.ReplaceAll(b.Msg, `"`, `\"`))
})
注意:SetFormatter 必须在 SetLogger 之后调用,否则无效;且 Beego 的 beego.Error() 等快捷函数底层仍走 logs,所以这个 formatter 对它们也生效。
多通道场景下(比如同时写文件和 stdout),formatter 会被每个 writer 各调用一次,别在里面做耗时操作。











