chatgpt:编写日志rotate框架
场景
我们的网关服务等为了持久化日志以供排查问题,往往将日志输出到文件,此时如果文件太大,可能导致磁盘被写满,此时就需要对日志文件进行rotate,以保存最新的日志
实现
package mainimport ("fmt""io/ioutil""os""path/filepath""sort""strconv""strings""time"
)type rollingFileManager struct {basePath stringfilename stringext stringmaxSize int64maxFiles int
}func newRollingFileManager(basePath string, maxSize int64, maxFiles int) *rollingFileManager {return &rollingFileManager{basePath: basePath,filename: "log",ext: ".txt",maxSize: maxSize,maxFiles: maxFiles,}
}func (fm *rollingFileManager) getCurrentFilename() string {return filepath.Join(fm.basePath, fm.filename+fm.ext)
}func (fm *rollingFileManager) getNewFilename() string {timestamp := strconv.FormatInt(time.Now().Unix(), 10)counter := 0filename := fmt.Sprintf("%s_%s_%d%s", fm.filename, timestamp, counter, fm.ext)for {if _, err := os.Stat(filepath.Join(fm.basePath, filename)); os.IsNotExist(err) {break}counter++filename = fmt.Sprintf("%s_%s_%d%s", fm.filename, timestamp, counter, fm.ext)}return filepath.Join(fm.basePath, filename)
}func (fm *rollingFileManager) rollFile() error {path := fm.getNewFilename()err := os.Rename(fm.getCurrentFilename(), path)if err != nil {return err}fmt.Println("Rolled file:", path)// Check and remove oldest filereturn fm.removeOldestFile()
}func (fm *rollingFileManager) removeOldestFile() error {files, err := ioutil.ReadDir(fm.basePath)if err != nil {return err}type logFile struct {name stringtime time.Time}var logFiles []logFilefor _, file := range files {if strings.HasPrefix(file.Name(), fm.filename+"_") && strings.HasSuffix(file.Name(), fm.ext) {logFiles = append(logFiles, logFile{file.Name(), file.ModTime()})}}if len(logFiles) > fm.maxFiles {sort.Slice(logFiles, func(i, j int) bool {return logFiles[i].time.Before(logFiles[j].time)})err := os.Remove(filepath.Join(fm.basePath, logFiles[0].name))if err != nil {return err}fmt.Println("Removed oldest file:", logFiles[0].name)}return nil
}func (fm *rollingFileManager) checkAndRoll() error {fileInfo, err := os.Stat(fm.getCurrentFilename())if err != nil {return err}if fileInfo.Size() >= fm.maxSize {return fm.rollFile()}return nil
}func main() {// 设置滚动更新管理器(指定文件大小上限,例如:100KB,和最大文件个数,例如:5)fm := newRollingFileManager(".", 100*1024, 5)// 每隔 5 秒检查文件大小并执行滚动操作ticker := time.NewTicker(5 * time.Second)quit := make(chan struct{})defer close(quit)go func() {for {select {case <-ticker.C:err := fm.checkAndRoll()if err != nil {log.Println("Error rolling:", err)}case <-quit:ticker.Stop()return}}}()// 模拟程序运行,让文件管理器有机会执行滚动操作time.Sleep(10 * time.Minute)
}