Files
2026-07-03 20:55:15 +08:00

282 lines
7.4 KiB
Go

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)
}
}
}
}
}