lumberjack的LocalTime必须设为true,否则用UTC时间生成文件名(如app.log.2024-03-15T00-00-00Z),导致北京时间8点才切割,日志日期与实际错位;设为true后使用本地时间,确保文件名如app.log.2024-03-16与业务日期一致。

为什么 lumberjack 的 LocalTime 必须设为 true 才能按天切割
默认 LocalTime: false 时,lumberjack 用 UTC 时间生成文件名(如 app.log.2024-03-15T00-00-00Z),即使你本地是东八区,切割也会在 UTC 零点(即北京时间上午 8 点)触发,导致日志文件日期和实际日期错位。设为 true 后,它才用 time.Now().Local() 获取本地时间,确保 app.log.2024-03-16 这类文件名与你的业务日期一致。
常见错误现象:app.log.2024-03-15 里混着 3 月 16 日 00:00–07:59 的日志,或者每天切割时间飘忽不定。
-
LocalTime: true是按「日历日」切割的前提,不是可选项 - 若服务部署在 Docker 容器中,需确认容器时区已同步宿主机(例如启动时加
-v /etc/localtime:/etc/localtime:ro) - 不要依赖系统环境变量
TZ,lumberjack 不读它
MaxSize、MaxAge、MaxBackups 三者怎么配才不丢日志又不爆磁盘
MaxSize 控制单个日志文件大小(单位字节),MaxAge 控制归档文件保留天数(单位天),MaxBackups 控制最多保留几个归档文件——三者共同生效,但优先级不同:轮转先看 MaxSize 是否超限,再看是否到新一天(靠 LocalTime + rotation check),最后清理时按 MaxAge 和 MaxBackups 中更严格的那个删旧文件。
- 想纯按天切割?把
MaxSize设得足够大(比如100 * 1024 * 1024即 100MB),避免中途因体积触发非预期切割 -
MaxAge: 7且MaxBackups: 30时,最终保留的是「最近 7 天内产生的、最多 30 个」文件;如果某天日志量大产生 5 个文件,它们全被保留;如果连续 10 天没日志,那一个都不留 - 注意:
MaxAge判断依据是文件名里的日期(不是文件 mtime),所以必须确保文件名含准确日期(lumberjack 默认满足)
如何让 zap 或 logrus 无缝接入 lumberjack 实现按天切
lumberjack 本身只提供 io.WriteCloser,不绑定任何日志库。你要把它塞进日志库的输出目标里,而不是“配置 lumberjack”。
以 zap 为例:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
lw := &lumberjack.Logger{
Filename: "/var/log/myapp/app.log",
MaxSize: 100 * 1024 * 1024,
MaxBackups: 30,
MaxAge: 7,
LocalTime: true,
Compress: true,
}
core := zapcore.NewCore(
zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()),
zapcore.AddSync(lw),
zap.InfoLevel,
)
logger := zap.New(core)
logrus 类似,只需替换 logrus.SetOutput:
lw := &lumberjack.Logger{ /* 同上 */ }
logrus.SetOutput(lw)
- 别直接用
os.Stdout或os.Stderr包裹 lumberjack,它自己已实现并发安全写入 - zap 的
zapcore.AddSync是必需的,否则 panic:lumberjack 不是io.Writer而是io.WriteCloser - logrus v1.9+ 支持
io.Writer,但 lumberjack 的Write方法返回(int, error),完全兼容;无需额外 wrapper
为什么程序重启后第一天日志没进新文件,而是续写旧文件
这是 lumberjack 的设计行为:它只在当前日志文件「写满」或「跨天」时才触发轮转,不关心进程启停。只要上次关闭前没跨天,重启后仍往 app.log 写,直到零点或超限。
如果你需要每次启动都强制新建当日文件(比如调试时想快速定位某次运行的日志),不能靠 lumberjack 自身解决,得手动干预:
- 启动时检查
app.log最后修改时间是否早于今天凌晨,若是,先 rename 它(如加.old后缀),再初始化 lumberjack - 或者改用
app.log.YYYY-MM-DD格式 + 每次启动 new 一个 lumberjack 实例(但会丢失MaxBackups等自动管理能力) - 更稳妥的做法是接受默认行为——生产环境本就不该依赖“每次启动必新文件”,而应靠文件名日期 + 行内时间戳定位
真正容易被忽略的是:lumberjack 不监听系统时间跳变(如 NTP 校正回拨),若服务器时间倒退,可能导致当天日志被误判为“过期”而提前删除。线上务必保证 chrony/ntpd 稳定运行,且避免大幅手动调时。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










