因为zap本身不提供文件轮转能力,仅负责日志格式化与写入io.writer;自动归档需依赖lumberjack等外部writer实现切割、压缩与清理,zap不感知也不干预该过程。

为什么直接用 zap.NewProduction() 无法自动归档
因为 zap 官方库本身不提供文件轮转或归档能力——它只负责日志格式化和写入 io.Writer。所谓“自动归档”,实际依赖外部 writer(如 lumberjack.Logger)实现切割与压缩,Zap 只是把日志“倒进去”。常见错误是以为调用 zap.NewProduction() 就能按天切文件、自动删旧,结果跑一周发现日志全堆在同一个大文件里。
实操建议:
- 必须显式构造一个带轮转逻辑的
io.Writer,再传给zapcore.NewCore() - 不要复用
zap.NewDevelopment()或zap.NewProduction()的返回值,它们内部用的是os.Stdout和固定编码器,绕不开 writer 层 - 归档行为(如压缩、删除)由底层 writer 控制,Zap 不感知也不干预 —— 比如
lumberjack的MaxBackups是它自己删,不是 Zap 触发的
用 lumberjack.Logger 接入 Zap 的关键参数怎么设
这是最常出错的一环:参数名看似直观,但含义和生效条件容易误解。比如 MaxSize 单位是 MB,但只有当日志写满才触发切割;MaxAge 是“文件最老存活天数”,不是“按天归档”——如果某天没写日志,就不会生成当天文件,MaxAge 也就无从计算。
实操建议:
-
Filename必须是绝对路径,相对路径在 daemon 模式下极易写到根目录或不可写位置 -
MaxSize: 100(MB)比1024更稳妥:太大导致单文件臃肿,太小引发频繁 IO 切割 -
MaxAge: 7配合MaxBackups: 30是较平衡组合:保留最近 7 天内生成的所有备份,但最多存 30 个文件(防止突发日志暴涨) - 务必设置
LocalTime: true,否则lumberjack用 UTC 时间命名文件,在中国区服务器上会导致归档时间错乱
如何让 Zap 自动按 level 分文件(error.log / info.log)
Zap 本身支持多 core,但“按 level 分写”不是开个开关就行——必须为每个 level 构造独立 zapcore.Core,并绑定不同 writer 和 encoder。难点在于:error 日志要进 error.log,但 info 日志不能漏掉 error 级别(否则 debug 时找不到上下文),所以得用 zapcore.LevelEnablerFunc 精确拦截。
实操建议:
- 定义两个 writer:
infoWriter和errorWriter,都基于lumberjack.Logger,但Filename不同 - info core 的 level 函数应返回
level ,error core 返回 <code>level >= zapcore.ErrorLevel - 最终 logger 用
zap.Combine合并多个 core,而非只取一个——否则低 level 日志会丢失 - 避免在 error core 里写
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder,这会影响 info core 的输出格式;应为每个 core 单独配 encoder
Go 进程重启时日志归档中断怎么办
典型现象:服务用 systemd 管理,每天凌晨 reload 一次,结果发现 app-2024-05-20_00-00-00.log 文件大小异常小,且后续日志没进新文件。这是因为 lumberjack 在进程退出时不会主动 close 当前文件句柄,OS 回收资源后,新进程启动时虽然文件名一样,但 lumberjack 不知道该“续写”还是“新建”,默认走新建逻辑,旧文件就卡在半归档状态。
实操建议:
- 在
main()退出前显式调用logger.Sync()(Zap 提供) +lumberjack实例的Close()(需自己保存引用) - systemd 配置中加
ExecStop=/bin/sh -c 'kill -SIGTERM $MAINPID; sleep 0.5',留出 Sync 时间 - 更稳的做法是:用
os.Signal监听os.Interrupt和syscall.SIGTERM,收到后先Sync再os.Exit(0)
真正麻烦的不是配置,而是归档逻辑散落在 writer、core、signal 处理三处,少一处就断链。上线前务必用 kill -15 模拟一次重启,检查文件是否连续、大小是否合理、旧备份是否被清理。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











