package logger import ( "context" "fmt" "os" "path/filepath" "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) // LevelLoggerConfig 按级别分文件的日志配置 type LevelLoggerConfig struct { BaseConfig Config // 是否启用按级别分文件 EnableLevelSeparation bool // 各级别日志文件配置 LevelConfigs map[zapcore.Level]LevelFileConfig } // LevelFileConfig 单个级别文件配置 type LevelFileConfig struct { MaxSize int // 单个文件最大大小(MB) MaxBackups int // 最大备份文件数 MaxAge int // 最大保留天数 Compress bool // 是否压缩 } // LevelLogger 按级别分文件的日志器 type LevelLogger struct { loggers map[zapcore.Level]*zap.Logger config LevelLoggerConfig } // NewLevelLogger 创建按级别分文件的日志器 func NewLevelLogger(config LevelLoggerConfig) (*LevelLogger, error) { if !config.EnableLevelSeparation { // 如果不启用按级别分文件,使用普通日志器 normalLogger, err := NewLogger(config.BaseConfig) if err != nil { return nil, err } // 转换为LevelLogger格式 zapLogger := normalLogger.(*ZapLogger).GetZapLogger() return &LevelLogger{ loggers: map[zapcore.Level]*zap.Logger{ zapcore.DebugLevel: zapLogger, zapcore.InfoLevel: zapLogger, zapcore.WarnLevel: zapLogger, zapcore.ErrorLevel: zapLogger, zapcore.FatalLevel: zapLogger, zapcore.PanicLevel: zapLogger, }, config: config, }, nil } // 设置默认级别配置 if config.LevelConfigs == nil { config.LevelConfigs = getDefaultLevelConfigs() } // 确保日志目录存在 if err := os.MkdirAll(config.BaseConfig.LogDir, 0755); err != nil { return nil, fmt.Errorf("创建日志目录失败: %w", err) } // 为每个级别创建独立的日志器 loggers := make(map[zapcore.Level]*zap.Logger) for level := range config.LevelConfigs { logger, err := createLevelLogger(level, config) if err != nil { return nil, fmt.Errorf("创建级别日志器失败 [%s]: %w", level.String(), err) } loggers[level] = logger } return &LevelLogger{ loggers: loggers, config: config, }, nil } // getDefaultLevelConfigs 获取默认级别配置 func getDefaultLevelConfigs() map[zapcore.Level]LevelFileConfig { return map[zapcore.Level]LevelFileConfig{ zapcore.DebugLevel: { MaxSize: 50, // 50MB MaxBackups: 3, MaxAge: 7, // 7天 Compress: true, }, zapcore.InfoLevel: { MaxSize: 100, // 100MB MaxBackups: 5, MaxAge: 30, // 30天 Compress: true, }, zapcore.WarnLevel: { MaxSize: 100, // 100MB MaxBackups: 5, MaxAge: 30, // 30天 Compress: true, }, zapcore.ErrorLevel: { MaxSize: 200, // 200MB MaxBackups: 10, MaxAge: 90, // 90天 Compress: true, }, zapcore.FatalLevel: { MaxSize: 100, // 100MB MaxBackups: 10, MaxAge: 365, // 1年 Compress: true, }, zapcore.PanicLevel: { MaxSize: 100, // 100MB MaxBackups: 10, MaxAge: 365, // 1年 Compress: true, }, } } // createLevelLogger 为单个级别创建日志器 func createLevelLogger(level zapcore.Level, config LevelLoggerConfig) (*zap.Logger, error) { levelConfig := config.LevelConfigs[level] // 创建编码器 encoderConfig := getEncoderConfig() var encoder zapcore.Encoder if config.BaseConfig.Format == "json" { encoder = zapcore.NewJSONEncoder(encoderConfig) } else { encoder = zapcore.NewConsoleEncoder(encoderConfig) } // 创建文件输出 writeSyncer, err := createLevelFileWriteSyncer(level, config.BaseConfig, levelConfig) if err != nil { return nil, err } // 创建核心 core := zapcore.NewCore(encoder, writeSyncer, level) // 创建日志器 logger := zap.New(core, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) return logger, nil } // createLevelFileWriteSyncer 创建级别文件输出同步器 func createLevelFileWriteSyncer(level zapcore.Level, baseConfig Config, levelConfig LevelFileConfig) (zapcore.WriteSyncer, error) { // 构建日志文件路径 var logFilePath string if baseConfig.UseDaily { // 按日分包:logs/2024-01-01/error.log today := time.Now().Format("2006-01-02") dailyDir := filepath.Join(baseConfig.LogDir, today) if err := os.MkdirAll(dailyDir, 0755); err != nil { return nil, fmt.Errorf("创建日期目录失败: %w", err) } logFilePath = filepath.Join(dailyDir, fmt.Sprintf("%s.log", level.String())) } else { // 传统方式:logs/error.log logFilePath = filepath.Join(baseConfig.LogDir, fmt.Sprintf("%s.log", level.String())) } // 创建lumberjack日志轮转器 lumberJackLogger := &lumberjack.Logger{ Filename: logFilePath, MaxSize: levelConfig.MaxSize, MaxBackups: levelConfig.MaxBackups, MaxAge: levelConfig.MaxAge, Compress: levelConfig.Compress, } return zapcore.AddSync(lumberJackLogger), nil } // Debug 调试日志 func (l *LevelLogger) Debug(msg string, fields ...zapcore.Field) { if logger, exists := l.loggers[zapcore.DebugLevel]; exists { logger.Debug(msg, fields...) } } // Info 信息日志 func (l *LevelLogger) Info(msg string, fields ...zapcore.Field) { if logger, exists := l.loggers[zapcore.InfoLevel]; exists { logger.Info(msg, fields...) } } // Warn 警告日志 func (l *LevelLogger) Warn(msg string, fields ...zapcore.Field) { if logger, exists := l.loggers[zapcore.WarnLevel]; exists { logger.Warn(msg, fields...) } } // Error 错误日志 func (l *LevelLogger) Error(msg string, fields ...zapcore.Field) { if logger, exists := l.loggers[zapcore.ErrorLevel]; exists { logger.Error(msg, fields...) } } // Fatal 致命错误日志 func (l *LevelLogger) Fatal(msg string, fields ...zapcore.Field) { if logger, exists := l.loggers[zapcore.FatalLevel]; exists { logger.Fatal(msg, fields...) } } // Panic 恐慌日志 func (l *LevelLogger) Panic(msg string, fields ...zapcore.Field) { if logger, exists := l.loggers[zapcore.PanicLevel]; exists { logger.Panic(msg, fields...) } } // With 添加字段 func (l *LevelLogger) With(fields ...zapcore.Field) Logger { // 为每个级别创建带字段的日志器 newLoggers := make(map[zapcore.Level]*zap.Logger) for level, logger := range l.loggers { newLoggers[level] = logger.With(fields...) } return &LevelLogger{ loggers: newLoggers, config: l.config, } } // WithContext 从上下文添加字段 func (l *LevelLogger) WithContext(ctx context.Context) Logger { // 从上下文中提取常用字段 fields := []zapcore.Field{} if traceID := getTraceIDFromContextLevel(ctx); traceID != "" { fields = append(fields, zap.String("trace_id", traceID)) } if userID := getUserIDFromContextLevel(ctx); userID != "" { fields = append(fields, zap.String("user_id", userID)) } if requestID := getRequestIDFromContextLevel(ctx); requestID != "" { fields = append(fields, zap.String("request_id", requestID)) } return l.With(fields...) } // Sync 同步日志 func (l *LevelLogger) Sync() error { var lastErr error for _, logger := range l.loggers { if err := logger.Sync(); err != nil { lastErr = err } } return lastErr } // GetLevelLogger 获取指定级别的日志器 func (l *LevelLogger) GetLevelLogger(level zapcore.Level) *zap.Logger { if logger, exists := l.loggers[level]; exists { return logger } return nil } // GetLoggers 获取所有级别的日志器 func (l *LevelLogger) GetLoggers() map[zapcore.Level]*zap.Logger { return l.loggers } // 辅助函数(从logger.go复制) func getTraceIDFromContextLevel(ctx context.Context) string { if traceID := ctx.Value("trace_id"); traceID != nil { if id, ok := traceID.(string); ok { return id } } return "" } func getUserIDFromContextLevel(ctx context.Context) string { if userID := ctx.Value("user_id"); userID != nil { if id, ok := userID.(string); ok { return id } } return "" } func getRequestIDFromContextLevel(ctx context.Context) string { if requestID := ctx.Value("request_id"); requestID != nil { if id, ok := requestID.(string); ok { return id } } return "" }