package logger import ( "fmt" "os" "strings" "sync" "git.listensoft.net/tool/jspkit/config" "git.listensoft.net/tool/jspkit/logger/zapx" amqp "github.com/rabbitmq/amqp091-go" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) var ( logger *zap.Logger mqConn *amqp.Connection // 保存MQ连接 mu sync.Mutex // 用于保护mqConn ) // InitLogger 初始化日志 func InitLogger(config *config.System) error { cfg := config.Logger // 设置默认值 if cfg.MaxSize == 0 { cfg.MaxSize = 100 } if cfg.MaxBackups == 0 { cfg.MaxBackups = 3 } if cfg.MaxAge == 0 { cfg.MaxAge = 28 } // 配置lumberjack hook := &lumberjack.Logger{ Filename: cfg.Filename, MaxSize: cfg.MaxSize, MaxBackups: cfg.MaxBackups, MaxAge: cfg.MaxAge, Compress: cfg.Compress, } // 设置日志级别 level := zap.InfoLevel if cfg.Level != "" { var err error level, err = zapcore.ParseLevel(cfg.Level) if err != nil { return err } } encoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", NameKey: "logger", CallerKey: "caller", MessageKey: "msg", StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.LowercaseLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } cores := []zapcore.Core{} if cfg.ToMq { dsn := fmt.Sprintf("amqp://%s:%s@%s:%d/", cfg.MqSetting.Username, cfg.MqSetting.Password, cfg.MqSetting.Host, cfg.MqSetting.Port) conn, err := amqp.Dial(dsn) if err == nil { mu.Lock() mqConn = conn // 保存连接 mu.Unlock() encoder := zapx.NewEncoder("taxrobot", zapx.CallerTrimmedPath) wsc, _ := zapx.NewWriter(conn) cores = append(cores, zapcore.NewCore(encoder, wsc, zap.InfoLevel)) } } // 创建Core var basecore zapcore.Core fileWriter := zapcore.AddSync(hook) if cfg.Console { // 同时输出到文件和控制台 consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig) fileEncoder := zapcore.NewJSONEncoder(encoderConfig) basecore = zapcore.NewTee( zapcore.NewCore(fileEncoder, fileWriter, level), zapcore.NewCore(consoleEncoder, zapcore.AddSync(os.Stdout), level), ) } else { // 只输出到文件 fileEncoder := zapcore.NewJSONEncoder(encoderConfig) basecore = zapcore.NewCore(fileEncoder, fileWriter, level) } cores = append(cores, basecore) // 创建Logger logger = zap.New(zapcore.NewTee(cores...), zap.AddCaller(), zap.AddCallerSkip(1)) return nil } // GetLogger 获取全局 logger func GetLogger() *zap.Logger { return logger } // Debug 输出Debug级别日志 func Debug(args ...any) { logger.Debug(ContainsArgs(args...)) } // Info 输出Info级别日志 func Info(args ...any) { logger.Info(ContainsArgs(args...)) } // Warn 输出Warn级别日志 func Warn(args ...any) { logger.Warn(ContainsArgs(args...)) } // Error 输出Error级别日志 func Error(args ...any) { logger.Error(ContainsArgs(args...)) } // Fatal 输出Fatal级别日志 func Fatal(args ...any) { logger.Fatal(ContainsArgs(args...)) } // Close 关闭日志相关资源,包括MQ连接 func Close() error { if logger != nil { logger.Sync() } mu.Lock() defer mu.Unlock() if mqConn != nil { err := mqConn.Close() mqConn = nil return err } return nil } // ContainsArgs 格式化参数为字符串 func ContainsArgs(args ...any) string { var arr []string for _, arg := range args { arr = append(arr, fmt.Sprintf("%v", arg)) } return strings.Join(arr, " ") }