package logger import ( "log" "os" "path/filepath" "sync" "time" ) // Logger 全局日志实例 var Logger = log.New(os.Stdout, "", log.LstdFlags) var logFile *os.File var logFileName string var mu sync.Mutex // LoggerManager 日志管理器 type LoggerManager struct { loggers map[string]*log.Logger files map[string]*os.File mu sync.RWMutex } // GlobalLoggerManager 全局日志管理器 var GlobalLoggerManager = &LoggerManager{ loggers: make(map[string]*log.Logger), files: make(map[string]*os.File), } // CreateLogger 创建带有指定路径的日志实例 func (lm *LoggerManager) CreateLogger(name string, logDir string) (*log.Logger, error) { lm.mu.Lock() defer lm.mu.Unlock() // 确保日志目录存在 if err := os.MkdirAll(logDir, 0755); err != nil { return nil, err } // 按天生成日志文件名 logFileName := filepath.Join(logDir, name+"_"+time.Now().Format("20060102")+".log") file, err := os.OpenFile(logFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return nil, err } logger := log.New(file, "", log.LstdFlags) lm.loggers[name] = logger lm.files[name] = file // 每天凌晨检查是否需要切换日志文件 go func() { for { // 每天检查一次(凌晨 00:05 执行) now := time.Now() next := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 5, 0, 0, now.Location()) time.Sleep(time.Until(next)) lm.mu.Lock() newFileName := filepath.Join(logDir, name+"_"+time.Now().Format("20060102")+".log") if newFileName != logFileName { newFile, err := os.OpenFile(newFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Printf("Failed to switch the log file: %v", err) lm.mu.Unlock() continue } file.Close() file = newFile logFileName = newFileName logger = log.New(newFile, "", log.LstdFlags) lm.loggers[name] = logger lm.files[name] = newFile logger.Println("The log file has been switched:", newFileName) } lm.mu.Unlock() } }() return logger, nil } // GetLogger 获取指定名称的日志实例 func (lm *LoggerManager) GetLogger(name string) *log.Logger { lm.mu.RLock() defer lm.mu.RUnlock() return lm.loggers[name] } // CloseLogger 关闭指定名称的日志文件 func (lm *LoggerManager) CloseLogger(name string) { lm.mu.Lock() defer lm.mu.Unlock() if file, exists := lm.files[name]; exists { file.Close() delete(lm.files, name) delete(lm.loggers, name) } } // CloseAllLoggers 关闭所有日志文件 func (lm *LoggerManager) CloseAllLoggers() { lm.mu.Lock() defer lm.mu.Unlock() for name, file := range lm.files { file.Close() delete(lm.files, name) delete(lm.loggers, name) } } // InitLogger 初始化系统日志,创建 /data/logs/system 目录并按天命名文件 func InitLogger() error { mu.Lock() defer mu.Unlock() // 创建 /data/logs/system 目录 logDir := "/data/logs/system" if err := os.MkdirAll(logDir, 0755); err != nil { return err } // 按天生成日志文件名:system_20260102.log logFileName = filepath.Join(logDir, "system_"+time.Now().Format("20060102")+".log") file, err := os.OpenFile(logFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } logFile = file Logger = log.New(file, "", log.LstdFlags) // 每天凌晨检查是否需要切换日志文件 go func() { for { // 每天检查一次(凌晨 00:05 执行) now := time.Now() next := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 5, 0, 0, now.Location()) time.Sleep(time.Until(next)) mu.Lock() newFileName := filepath.Join(logDir, "system_"+time.Now().Format("20060102")+".log") if newFileName != logFileName { newFile, err := os.OpenFile(newFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Printf("Failed to switch the log file: %v", err) mu.Unlock() continue } logFile.Close() logFile = newFile logFileName = newFileName Logger = log.New(newFile, "", log.LstdFlags) Logger.Println("The log file has been switched:", newFileName) } mu.Unlock() } }() return nil } // InitReporterLogger 初始化上报管理器专用日志,创建 /data/logs/reporter 目录并按天命名文件 func InitReporterLogger() error { // 创建上报管理器专用日志 _, err := GlobalLoggerManager.CreateLogger("reporter", "/data/logs/reporter") return err } // InitGPILogger 初始化GPIO监控专用日志,创建 /data/logs/reporter 目录并按天命名文件 func InitGPILogger() error { // 创建GPIO监控专用日志 _, err := GlobalLoggerManager.CreateLogger("gpio", "/data/logs/reporter") return err } // InitLoggerWithPath 初始化日志,使用指定的日志文件路径 func InitLoggerWithPath(logPath string) error { mu.Lock() defer mu.Unlock() // 创建日志目录 logDir := filepath.Dir(logPath) if err := os.MkdirAll(logDir, 0755); err != nil { return err } // 打开指定的日志文件 logFileName = logPath file, err := os.OpenFile(logFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { return err } logFile = file Logger = log.New(file, "", log.LstdFlags) // 每天凌晨检查是否需要切换日志文件 go func() { for { // 每天检查一次(凌晨 00:05 执行) now := time.Now() next := time.Date(now.Year(), now.Month(), now.Day()+1, 0, 5, 0, 0, now.Location()) time.Sleep(time.Until(next)) mu.Lock() // 生成新的日志文件名,保留原有文件名的前缀和添加日期后缀 baseName := filepath.Base(logPath) ext := filepath.Ext(baseName) nameWithoutExt := baseName[:len(baseName)-len(ext)] newFileName := filepath.Join(logDir, nameWithoutExt+"_"+time.Now().Format("20060102")+ext) if newFileName != logFileName { newFile, err := os.OpenFile(newFileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { log.Printf("Failed to switch the log file: %v", err) mu.Unlock() continue } logFile.Close() logFile = newFile logFileName = newFileName Logger = log.New(newFile, "", log.LstdFlags) Logger.Println("The log file has been switched:", newFileName) } mu.Unlock() } }() return nil } // CloseLogger 关闭日志文件 func CloseLogger() { mu.Lock() defer mu.Unlock() if logFile != nil { logFile.Close() logFile = nil } } // CleanupOldLogs 删除超过30天的日志文件 func CleanupOldLogs() { // 清理system目录的日志文件 cleanupLogDirectory("/data/logs/system") // 清理reporter目录的日志文件 cleanupLogDirectory("/data/logs/reporter") } // cleanupLogDirectory 清理指定目录下超过30天的日志文件 func cleanupLogDirectory(logDir string) { files, err := os.ReadDir(logDir) if err != nil { if Logger != nil { Logger.Printf("Read the log directory %s Error: %v", logDir, err) } return } const maxAge = 30 * 24 * time.Hour // 30天 for _, file := range files { if file.IsDir() { continue } info, err := file.Info() if err != nil { if Logger != nil { Logger.Printf("Obtain file information %s Error: %v", file.Name(), err) } continue } if time.Since(info.ModTime()) > maxAge { filePath := filepath.Join(logDir, file.Name()) if err := os.Remove(filePath); err != nil { if Logger != nil { Logger.Printf("Delete the old log files %s Error: %v", filePath, err) } } else { if Logger != nil { Logger.Printf("Delete the old log files %s succeed", filePath) } } } } }