lumberjack.Logger 是最可靠选择,但需显式配置 MaxAge 和 LocalTime 才能按天切分,且仅在写入时检查 ModTime,不保证零点精确切分;MaxAge 是清理策略而非触发器,LocalTime 必须为 true,MaxSize 建议设为 0。

lumberjack.Logger 是目前最可靠的选择,但它不会“自动按天切割”——你必须显式配置 MaxAge 和 LocalTime,并接受它只在写入时检查、不保证零点精确切分的事实。
为什么 lumberjack.SetOutput 后日志还是跨天不切
常见错误现象:app.log 从 10 月 9 日下午一直写到 10 月 10 日上午,文件名没变,内容混在一起;或者你设了 MaxAge: 24 * time.Hour,但第二天日志仍在往老文件里写,只是旧备份被删了。
根本原因:lumberjack 的 MaxAge 是清理策略,不是切割触发器。它只在每次 Write() 前检查当前文件的 ModTime() 是否超过 MaxAge,若超则重命名归档、新建空文件。没有写入,就不会触发检查。
-
LocalTime: true必须设为true,否则ModTime()是 UTC 时间,和本地零点对不上 -
MaxSize建议设为0(禁用大小轮转),避免大小和时间逻辑冲突 - 首次启动时,lumberjack 会读取已有
Filename文件的ModTime()判断是否该切——所以系统时间不准会导致首日就误切或漏切
logrus + lumberjack 按天切分的最小可行配置
logrus 本身不支持时间轮转,必须靠 lumberjack 配合。但直接传 lumberjack.Logger 给 logrus.SetOutput() 有风险:它内部缓冲未 flush 完就关闭句柄,进程退出时可能丢最后几条日志。
立即学习“go语言免费学习笔记(深入)”;
正确做法是封装一层,确保 Write() 稳定,并在退出前显式 Close():
lw := &lumberjack.Logger{
Filename: "./logs/app.log",
MaxSize: 0,
MaxAge: 24 * time.Hour,
MaxBackups: 30,
LocalTime: true,
Compress: false,
}
logger := logrus.New()
logger.SetOutput(lw)
// 退出前显式关闭
defer func() {
if lw != nil {
lw.Close()
}
}()- 文件名始终是
app.log,归档后才变成app.log.2026-10-09—— 这是 lumberjack 默认行为,无法改 - 不要用
io.MultiWriter包裹多个lumberjack.Logger,容易因 write 性能差异导致阻塞 - 如果同时要控制台输出,建议用
logrus.AddHook而非io.MultiWriter
想严格零点切分?别依赖 lumberjack 自动检查
如果你的业务要求“每天 00:00:00 精确新建文件”,比如审计合规场景,lumberjack 的被动检查机制不可靠——低频服务当天无日志,就不会触发 Write(),也就不会切。
替代方案是起一个独立 goroutine,用 time.Ticker 每分钟检查一次日期是否变更,然后调用 lumberjack.Rotate():
- 必须加锁或通过 channel 串行化调用,
Rotate()并发调用会 panic - 判断逻辑用
t.Day() != lastDay,而不是格式化字符串比较,避免时区误差 - 第一次初始化 logger 时,需手动设置
lastDay = time.Now().Day() - 注意:Rotate() 不会阻塞,但新文件创建和旧文件 rename 是原子操作,不影响写入可用性
自定义 Writer 实现按天切分(无第三方依赖)
如果你不能引入 lumberjack,自己实现 io.Writer 是可行的,但关键不在“怎么写文件”,而在“什么时候切”和“怎么切得安全”:
- 每次
Write()前比对当前日期与上次写入日期,不一致则关旧、开新、加锁 - 不能裸用
os.OpenFile+log.SetOutput(),那不是原子操作,多 goroutine 下必丢日志 - 必须用
sync.Mutex或sync.RWMutex保护文件句柄切换过程 - 文件名建议用
time.Now().Format("2006-01-02"),避免拼接错误
真正难的不是代码量,而是竞态控制和进程生命周期管理——比如程序崩溃时旧文件句柄是否泄漏、重启后日期状态是否丢失。这些细节一旦忽略,线上就可能出现静默丢日志或文件句柄耗尽。


















