Golang项目如何实现按天日志轮转?logrus按日切割方案咨询
Golang logrus按天日志轮转实现方案
下面是三个可在项目代码层级完成配置、无需依赖系统额外配置的可行方案:
方案1:使用file-rotatelogs钩子直接实现按天轮转
这是目前生态中最常用的方案,不需要修改原有logrus调用逻辑,仅需在初始化时配置输出Writer即可。
- 支持按自定义时间间隔(可精确到天/小时/分钟等)轮转
- 可配置历史日志保留时长、自动清理过期日志
- 支持自定义日志文件名格式
示例初始化代码:
package main import ( "github.com/sirupsen/logrus" rotatelogs "github.com/lestrrat-go/file-rotatelogs" "time" ) func initLog() error { // 配置轮转规则 writer, err := rotatelogs.New( // 日志文件名格式,%Y%m%d代表年月日 "./app.log.%Y%m%d", // 指明日志软链接,始终指向最新日志文件 rotatelogs.WithLinkName("./app.log"), // 配置历史日志保留7天 rotatelogs.WithMaxAge(7 * 24 * time.Hour), // 配置按天轮转(24小时间隔) rotatelogs.WithRotationTime(24 * time.Hour), ) if err != nil { return err } // 为logrus设置输出Writer logrus.SetOutput(writer) return nil }
方案2:对原生lumberjack封装扩展实现按天+按大小双重轮转
如果需要同时保留按大小轮转的能力,可以在lumberjack外层加一层日期判断,跨天时主动触发lumberjack的轮转逻辑。
- 兼顾按天轮转和按大小切割的需求
- 复用lumberjack成熟的文件操作、压缩逻辑
示例封装代码:
type DailyRotator struct { lumberjack.Logger lastDate string } func (d *DailyRotator) Write(p []byte) (n int, err error) { currentDate := time.Now().Format("20060102") // 日期发生变化时触发轮转 if currentDate != d.lastDate { d.Logger.Rotate() d.lastDate = currentDate } return d.Logger.Write(p) } // 初始化用法 func initLog() { rotator := &DailyRotator{ Logger: lumberjack.Logger{ Filename: "./app.log", MaxSize: 100, // 单文件最大100M MaxBackups: 30, // 最多保留30个备份 Compress: true, // 启用压缩 }, lastDate: time.Now().Format("20060102"), } logrus.SetOutput(rotator) }
方案3:自研极简按天轮转Writer
如果不想引入额外第三方依赖,可以自己实现一个满足io.Writer接口的轻量轮转组件,仅做日期判断和文件切换逻辑,代码量很小可控。
- 无额外依赖,灵活性最高,可根据业务需求自定义规则
- 性能开销极低,仅在跨天的时候做一次文件切换操作
示例实现代码:
type SimpleDailyWriter struct { filename string file *os.File lastDate string mu sync.Mutex } func NewSimpleDailyWriter(filename string) (*SimpleDailyWriter, error) { w := &SimpleDailyWriter{filename: filename} if err := w.rotate(); err != nil { return nil, err } return w, nil } func (w *SimpleDailyWriter) Write(p []byte) (n int, err error) { w.mu.Lock() defer w.mu.Unlock() currentDate := time.Now().Format("20060102") if currentDate != w.lastDate { if err := w.rotate(); err != nil { return 0, err } } return w.file.Write(p) } func (w *SimpleDailyWriter) rotate() error { date := time.Now().Format("20060102") // 关闭旧文件 if w.file != nil { w.file.Close() } // 打开新文件,文件名带日期后缀 newFile, err := os.OpenFile(w.filename+"."+date, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { return err } w.file = newFile w.lastDate = date return nil }
内容的提问来源于stack exchange,提问作者Sumit Bopche
相关产品推荐
相关产品推荐

