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

282 lines
7.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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