在 Debian 上运行用 Go (Golang) 写的服务时,“日志轮转(log rotation)”通常不是在 Go 代码里硬写,而是交给系统工具处理。下面是几种常见、推荐的做法。
Debian 自带 logrotate,几乎适合所有场景。
/var/log/myapp/app.log
sudo vim /etc/logrotate.d/myapp
示例配置:
/var/log/myapp/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
copytruncate
}
copytruncate:非常重要,适合不支持信号重开日志的 Go 程序daily / weekly:轮转频率rotate 14:保留 14 份compress:压缩旧日志sudo logrotate -d /etc/logrotate.d/myapp
sudo logrotate -f /etc/logrotate.d/myapp
✅ 优点:简单、稳定、无需改代码
❌ 缺点:依赖 copytruncate(有极少量日志丢失风险)
如果你的 Go 程序能监听信号重新打开日志文件:
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGHUP)
go func() {
for range sigChan {
logFile.Close()
logFile, _ = os.OpenFile("/var/log/myapp/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
log.SetOutput(logFile)
}
}()
/var/log/myapp/*.log {
daily
rotate 14
compress
postrotate
systemctl kill -s HUP myapp.service
endscript
}
✅ 优点:无日志丢失
❌ 缺点:需要改代码
如果不想依赖系统工具,可以用 Go 库:
import "gopkg.in/natefinch/lumberjack.v2"
log.SetOutput(&lumberjack.Logger{
Filename: "/var/log/myapp/app.log",
MaxSize: 10, // MB
MaxBackups: 14,
MaxAge: 28, // days
Compress: true,
})
✅ 优点:代码可控
❌ 缺点:日志命名不是 app.log.1 标准格式
如果日志直接输出到 stdout:
# /etc/systemd/system/myapp.service
[Service]
ExecStart=/opt/myapp/myapp
StandardOutput=journal
查看日志:
journalctl -u myapp
systemd 会自动轮转 journal。
| 场景 | 推荐 |
|---|---|
| 不想改代码 | logrotate + copytruncate |
| 可接受改代码 | logrotate + SIGHUP |
| 容器 / 云原生 | stdout + 外部采集 |
| 纯 Go 项目 | lumberjack |
如果你愿意,可以告诉我:
我可以给你一份可直接用的配置。