228 lines
5.5 KiB
Go
228 lines
5.5 KiB
Go
package utils
|
||
|
||
import (
|
||
"fmt"
|
||
"os"
|
||
"path/filepath"
|
||
"sync"
|
||
"time"
|
||
|
||
"github.com/evil7/hostsync/config"
|
||
"go.uber.org/zap"
|
||
"go.uber.org/zap/zapcore"
|
||
)
|
||
|
||
var (
|
||
fileLogger *zap.Logger
|
||
fileSugar *zap.SugaredLogger
|
||
consoleLogger *zap.Logger
|
||
consoleSugar *zap.SugaredLogger
|
||
debugMode bool
|
||
logMutex sync.Mutex
|
||
)
|
||
|
||
// InitLogger 初始化日志系统
|
||
func InitLogger() error {
|
||
if config.AppConfig == nil {
|
||
return nil
|
||
}
|
||
|
||
// 根据配置设置日志级别
|
||
level := zapcore.InfoLevel
|
||
if config.AppConfig.LogLevel != "" {
|
||
switch config.AppConfig.LogLevel {
|
||
case "debug":
|
||
level = zapcore.DebugLevel
|
||
case "info":
|
||
level = zapcore.InfoLevel
|
||
case "warning", "warn":
|
||
level = zapcore.WarnLevel
|
||
case "error":
|
||
level = zapcore.ErrorLevel
|
||
case "silent":
|
||
level = zapcore.ErrorLevel + 1 // 静默模式,不记录任何日志
|
||
}
|
||
}
|
||
|
||
// 创建控制台logger配置(只用于错误输出)
|
||
consoleConfig := zap.Config{
|
||
Level: zap.NewAtomicLevelAt(zapcore.ErrorLevel), // 只显示错误
|
||
Development: false,
|
||
Encoding: "console",
|
||
EncoderConfig: zapcore.EncoderConfig{
|
||
MessageKey: "msg",
|
||
LineEnding: zapcore.DefaultLineEnding,
|
||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||
},
|
||
OutputPaths: []string{"stderr"},
|
||
ErrorOutputPaths: []string{"stderr"},
|
||
}
|
||
|
||
var err error
|
||
consoleLogger, err = consoleConfig.Build(zap.AddStacktrace(zapcore.DPanicLevel))
|
||
if err != nil {
|
||
return fmt.Errorf("创建控制台logger失败: %v", err)
|
||
}
|
||
consoleSugar = consoleLogger.Sugar()
|
||
|
||
// 如果配置了文件路径,创建文件logger
|
||
if config.AppConfig.LogPath != "" {
|
||
// 确保日志目录存在
|
||
if err := os.MkdirAll(config.AppConfig.LogPath, 0755); err != nil {
|
||
return fmt.Errorf("创建日志目录失败: %v", err)
|
||
}
|
||
|
||
logFileName := filepath.Join(config.AppConfig.LogPath, "hostsync.log")
|
||
|
||
// 检查并轮转日志文件
|
||
if err := rotateLogIfNeeded(logFileName); err != nil {
|
||
return fmt.Errorf("轮转日志文件失败: %v", err)
|
||
}
|
||
|
||
// 创建文件logger配置
|
||
fileConfig := zap.Config{
|
||
Level: zap.NewAtomicLevelAt(level),
|
||
Development: false,
|
||
Encoding: "console",
|
||
EncoderConfig: zapcore.EncoderConfig{
|
||
TimeKey: "time",
|
||
LevelKey: "level",
|
||
MessageKey: "msg",
|
||
LineEnding: zapcore.DefaultLineEnding,
|
||
EncodeLevel: zapcore.CapitalLevelEncoder,
|
||
EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||
enc.AppendString(t.Format("2006-01-02 15:04:05"))
|
||
},
|
||
},
|
||
OutputPaths: []string{logFileName},
|
||
ErrorOutputPaths: []string{logFileName},
|
||
}
|
||
|
||
fileLogger, err = fileConfig.Build(zap.AddStacktrace(zapcore.DPanicLevel))
|
||
if err != nil {
|
||
return fmt.Errorf("创建文件logger失败: %v", err)
|
||
}
|
||
fileSugar = fileLogger.Sugar()
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// rotateLogIfNeeded 检查并轮转日志文件
|
||
func rotateLogIfNeeded(logFileName string) error {
|
||
info, err := os.Stat(logFileName)
|
||
if os.IsNotExist(err) {
|
||
return nil
|
||
}
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
// 检查文件大小是否超过10MB
|
||
if info.Size() < 10*1024*1024 {
|
||
return nil
|
||
}
|
||
|
||
// 轮转日志文件
|
||
backupName := fmt.Sprintf("%s.%s", logFileName, time.Now().Format("20060102_150405"))
|
||
if err := os.Rename(logFileName, backupName); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 异步清理旧日志文件
|
||
go cleanOldLogs(filepath.Dir(logFileName))
|
||
return nil
|
||
}
|
||
|
||
// cleanOldLogs 清理旧的日志备份文件,保留最近5个
|
||
func cleanOldLogs(logDir string) {
|
||
files, err := filepath.Glob(filepath.Join(logDir, "hostsync.log.*"))
|
||
if err != nil || len(files) <= 5 {
|
||
return
|
||
}
|
||
|
||
// 删除最旧的文件
|
||
for i := 0; i < len(files)-5; i++ {
|
||
os.Remove(files[i])
|
||
}
|
||
}
|
||
|
||
// SetDebugMode 设置调试模式
|
||
func SetDebugMode(debug bool) {
|
||
debugMode = debug
|
||
}
|
||
|
||
// CloseLogger 关闭日志系统
|
||
func CloseLogger() {
|
||
if fileLogger != nil {
|
||
fileLogger.Sync()
|
||
}
|
||
if consoleLogger != nil {
|
||
consoleLogger.Sync()
|
||
}
|
||
}
|
||
|
||
// LogInfo 记录信息日志(只记录到文件)
|
||
func LogInfo(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Infof(format, args...)
|
||
}
|
||
}
|
||
|
||
// LogError 记录错误日志(记录到文件和控制台)
|
||
func LogError(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Errorf(format, args...)
|
||
}
|
||
if consoleSugar != nil {
|
||
consoleSugar.Errorf(format, args...)
|
||
} else {
|
||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||
}
|
||
}
|
||
|
||
// LogDebug 记录调试日志(只记录到文件)
|
||
func LogDebug(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Debugf(format, args...)
|
||
} else if debugMode {
|
||
fmt.Printf("DEBUG: "+format+"\n", args...)
|
||
}
|
||
}
|
||
|
||
// LogWarning 记录警告日志(只记录到文件)
|
||
func LogWarning(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Warnf(format, args...)
|
||
}
|
||
}
|
||
|
||
// LogSuccess 记录成功日志(只记录到文件)
|
||
func LogSuccess(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Infof(format, args...)
|
||
}
|
||
}
|
||
|
||
// LogFatal 记录致命错误并退出(记录到文件和控制台)
|
||
func LogFatal(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Fatalf(format, args...)
|
||
} else {
|
||
fmt.Fprintf(os.Stderr, format+"\n", args...)
|
||
os.Exit(1)
|
||
}
|
||
}
|
||
|
||
// LogFileOnly 只记录到文件,不显示在控制台
|
||
func LogFileOnly(format string, args ...interface{}) {
|
||
if fileSugar != nil {
|
||
fileSugar.Infof(format, args...)
|
||
}
|
||
}
|
||
|
||
// LogResult 用户界面结果输出(直接输出,不使用日志系统)
|
||
func LogResult(format string, args ...interface{}) {
|
||
fmt.Printf(format, args...)
|
||
}
|