lumberjack.Logger是最直接可用的日志切割方案,它作为满足io.WriteSyncer接口的轮转包装器,需配合log/slog/zap等日志库使用;安装必须用go get gopkg.in/natefinch/lumberjack.v2,Filename须为绝对路径,MaxSize单位为MB,且需显式设置Mode和LocalTime以确保权限与时间判定正确。

lumberjack.Logger 是最直接可用的日志切割方案
Go 标准库 log 和 slog 本身不支持日志切割,Zap 也只管序列化、不管轮转——想切日志,必须靠 lumberjack.Logger 这类满足 io.WriteSyncer 接口的写入器。它不是替代日志库,而是“套在日志输出后面”的轮转包装器。
常见错误现象:go get github.com/natefinch/lumberjack 编译失败(正确路径是 gopkg.in/natefinch/lumberjack.v2);Filename 写成相对路径,进程工作目录一变,日志就消失;MaxSize: 100 被误以为是字节,实际单位是 MB。
- 安装命令必须是:
go get gopkg.in/natefinch/lumberjack.v2 -
Filename必须用绝对路径,例如/var/log/myapp/app.log -
MaxSize单位是 MB,设 50 就是 50MB;若需精确控制字节,写成50 * 1024 * 1024 - 务必显式设置
Mode: 0644,否则新日志文件默认权限为0600,运维查不到
按大小切割是最稳的线上配置
按天命名(如 app-2026-07-14.log)看着直观,但 lumberjack 并不原生支持——它只做大小/数量/时间清理,不重命名当前文件。强行拼日期 + 切文件,要自己加锁、关旧、开新,容易丢日志或触发 write: bad file descriptor。
真正稳定的做法是用 MaxSize + MaxBackups 控制单文件体积和总磁盘占用,再配 MaxAge 做兜底清理。这比依赖系统时钟更可靠,尤其对长期运行的 daemon。
立即学习“go语言免费学习笔记(深入)”;
-
MaxBackups: 7和MaxAge: 28是“或”关系:任一条件满足即清理旧备份 -
Compress: true会阻塞写入,高吞吐服务慎开;压缩失败也不会报错,只静默跳过 - 别设
MaxSize: 1—— 频繁切割导致小文件爆炸、inode 耗尽、IO 毛刺上升 - 如果用 systemd,记得在 service 文件里加
ReadWritePaths=/var/log/myapp,否则切分静默失败
权限和路径问题比代码更容易卡住上线
80% 的“日志切不动”不是代码写错了,而是 Linux 权限链断了。CentOS 上 SELinux 默认拦截非标准路径写入,Docker 容器里挂载目录没加 :z 或 :Z 标签也会失败。
典型错误信息:open /var/log/myapp/app.log: permission denied,但程序不 panic,日志直接消失,只在 stderr 留一行 error——很容易漏看。
- 确保运行用户对
Filename所在目录有写权限:ls -ld /var/log/myapp - 创建目录后执行:
sudo chown myuser:myuser /var/log/myapp - SELinux 下临时验证:先
sudo setenforce 0,确认能切再配策略 - 已有日志文件权限不会被
lumberjack自动修正,上线前手动chmod 0644 *.log*
Zap 或 slog 都得手动接 lumberjack
Zap 要求底层是 zapcore.WriteSyncer,slog 要求 io.Writer,而 lumberjack.Logger 同时实现了这两个接口。所以无论你用哪个日志库,只要把 &lumberjack.Logger{...} 塞进去就行,不用改日志打点逻辑。
注意:Zap 默认不主动 Sync(),但 lumberjack 的切割判断依赖每次写入前的 Stat() 调用——这个动作由 lumberjack.Write() 内部完成,只要它被正常调用,切割就会触发。不需要额外加 zap.AddSync() 包裹,除非你手动构造了非同步写入器。
- Zap 示例关键行:
zapcore.AddSync(&lumberjack.Logger{...}) - slog 示例关键行:
slog.NewTextHandler(&lumberjack.Logger{...}, &slog.HandlerOptions{...}) - log 标准库最简单:
log.SetOutput(&lumberjack.Logger{...}) - 所有场景都必须在程序退出前调用
lumberjackLogger.Close(),否则最后几条日志可能丢失
实际落地时,最容易被忽略的是 Mode 和 LocalTime:前者决定日志文件能不能被其他账号读取,后者影响 MaxAge 清理是否按本地时区判断——设错会导致备份文件莫名被删或一直堆积。


















