package logger import ( "fmt" "log" "os" "strings" "sync" "time" ) type LogLevel int const ( DEBUG LogLevel = iota INFO WARN ERROR ) var ( logLevel LogLevel = INFO logFile *os.File logger *log.Logger mu sync.Mutex maxSize int64 = 10 * 1024 * 1024 // 10MB maxFiles int = 5 basePath string = "logs/licensing-cotton.log" ) func init() { // 创建日志目录 if err := os.MkdirAll("logs", 0755); err != nil { log.Printf("无法创建日志目录: %v\n", err) return } // 打开日志文件 if err := openLogFile(); err != nil { log.Printf("无法打开日志文件: %v\n", err) return } // 创建标准 logger logger = log.New(logFile, "", 0) } // SetLevel 设置日志级别 func SetLevel(level string) { switch strings.ToUpper(level) { case "DEBUG": logLevel = DEBUG case "INFO": logLevel = INFO case "WARN": logLevel = WARN case "ERROR": logLevel = ERROR default: logLevel = INFO } } // SetLogPath 设置日志文件路径 func SetLogPath(path string) { mu.Lock() defer mu.Unlock() basePath = path } // SetMaxSize 设置单个日志文件最大大小(字节) func SetMaxSize(size int64) { mu.Lock() defer mu.Unlock() maxSize = size } // SetMaxFiles 设置保留的日志文件数量 func SetMaxFiles(count int) { mu.Lock() defer mu.Unlock() maxFiles = count } func openLogFile() error { file, err := os.OpenFile(basePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { return err } logFile = file return nil } func rotateLogFile() error { // 关闭当前文件 if logFile != nil { logFile.Close() } // 轮转文件:最新的移动到 .1,.1 移动到 .2,以此类推 for i := maxFiles - 1; i >= 1; i-- { oldPath := fmt.Sprintf("%s.%d", basePath, i) newPath := fmt.Sprintf("%s.%d", basePath, i+1) // 删除最旧的文件 if i == maxFiles-1 { os.Remove(newPath) } // 重命名文件 if _, err := os.Stat(oldPath); err == nil { os.Rename(oldPath, newPath) } } // 将当前日志文件重命名为 .1 rotatedPath := fmt.Sprintf("%s.1", basePath) os.Rename(basePath, rotatedPath) // 打开新文件 return openLogFile() } func checkAndRotate() error { if logFile == nil { return openLogFile() } // 检查文件大小 stat, err := logFile.Stat() if err != nil { return err } if stat.Size() >= maxSize { return rotateLogFile() } return nil } func formatLog(level string, format string, args ...interface{}) string { timestamp := time.Now().Format("2006-01-02 15:04:05") message := fmt.Sprintf(format, args...) return fmt.Sprintf("[%s] [%s] %s\n", timestamp, level, message) } func writeLog(level LogLevel, levelStr string, format string, args ...interface{}) { if level < logLevel { return } mu.Lock() defer mu.Unlock() // 检查并轮转日志文件 if err := checkAndRotate(); err != nil { log.Printf("日志轮转失败: %v\n", err) return } // 写入日志文件 if logger != nil { logger.Printf(formatLog(levelStr, format, args...)) } // 同时输出到标准输出 fmt.Printf(formatLog(levelStr, format, args...)) } func Debug(format string, args ...interface{}) { writeLog(DEBUG, "DEBUG", format, args...) } func Info(format string, args ...interface{}) { writeLog(INFO, "INFO", format, args...) } func Warn(format string, args ...interface{}) { writeLog(WARN, "WARN", format, args...) } func Error(format string, args ...interface{}) { writeLog(ERROR, "ERROR", format, args...) } func Fatal(format string, args ...interface{}) { mu.Lock() defer mu.Unlock() message := formatLog("FATAL", format, args...) if logger != nil { logger.Printf(message) } fmt.Printf(message) os.Exit(1) } // Close 关闭日志文件 func Close() { mu.Lock() defer mu.Unlock() if logFile != nil { logFile.Close() } }