229 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package logger
 | ||
| 
 | ||
| import (
 | ||
| 	"context"
 | ||
| 	"path/filepath"
 | ||
| 	"time"
 | ||
| 
 | ||
| 	"go.uber.org/zap"
 | ||
| 	"go.uber.org/zap/zapcore"
 | ||
| 	"gopkg.in/natefinch/lumberjack.v2"
 | ||
| )
 | ||
| 
 | ||
| // LevelLogger 级别分文件日志器 - 基于 Zap 官方推荐
 | ||
| type LevelLogger struct {
 | ||
| 	logger        *zap.Logger
 | ||
| 	levelLoggers  map[zapcore.Level]*zap.Logger
 | ||
| 	config        LevelLoggerConfig
 | ||
| }
 | ||
| 
 | ||
| // LevelLoggerConfig 级别分文件日志器配置
 | ||
| type LevelLoggerConfig struct {
 | ||
| 	BaseConfig            Config
 | ||
| 	EnableLevelSeparation bool
 | ||
| 	LevelConfigs          map[zapcore.Level]LevelFileConfig
 | ||
| }
 | ||
| 
 | ||
| // LevelFileConfig 单个级别文件配置
 | ||
| type LevelFileConfig struct {
 | ||
| 	MaxSize    int  `mapstructure:"max_size"`
 | ||
| 	MaxBackups int  `mapstructure:"max_backups"`
 | ||
| 	MaxAge     int  `mapstructure:"max_age"`
 | ||
| 	Compress   bool `mapstructure:"compress"`
 | ||
| }
 | ||
| 
 | ||
| // NewLevelLogger 创建级别分文件日志器
 | ||
| func NewLevelLogger(config LevelLoggerConfig) (Logger, error) {
 | ||
| 	// 根据环境创建基础日志器
 | ||
| 	var baseLogger *zap.Logger
 | ||
| 	var err error
 | ||
| 
 | ||
| 	if config.BaseConfig.Development {
 | ||
| 		baseLogger, err = zap.NewDevelopment(
 | ||
| 			zap.AddCaller(),
 | ||
| 			zap.AddCallerSkip(1),
 | ||
| 			zap.AddStacktrace(zapcore.ErrorLevel),
 | ||
| 		)
 | ||
| 	} else {
 | ||
| 		baseLogger, err = zap.NewProduction(
 | ||
| 			zap.AddCaller(),
 | ||
| 			zap.AddCallerSkip(1),
 | ||
| 			zap.AddStacktrace(zapcore.ErrorLevel),
 | ||
| 		)
 | ||
| 	}
 | ||
| 
 | ||
| 	if err != nil {
 | ||
| 		return nil, err
 | ||
| 	}
 | ||
| 
 | ||
| 	// 创建级别分文件的日志器
 | ||
| 	levelLogger := &LevelLogger{
 | ||
| 		logger:       baseLogger,
 | ||
| 		levelLoggers: make(map[zapcore.Level]*zap.Logger),
 | ||
| 		config:       config,
 | ||
| 	}
 | ||
| 
 | ||
| 	// 为每个级别创建专门的日志器
 | ||
| 	if config.EnableLevelSeparation {
 | ||
| 		levelLogger.createLevelLoggers()
 | ||
| 	}
 | ||
| 
 | ||
| 	return levelLogger, nil
 | ||
| }
 | ||
| 
 | ||
| // createLevelLoggers 创建各级别的日志器
 | ||
| func (l *LevelLogger) createLevelLoggers() {
 | ||
| 	levels := []zapcore.Level{
 | ||
| 		zapcore.DebugLevel,
 | ||
| 		zapcore.InfoLevel,
 | ||
| 		zapcore.WarnLevel,
 | ||
| 		zapcore.ErrorLevel,
 | ||
| 		zapcore.FatalLevel,
 | ||
| 		zapcore.PanicLevel,
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, level := range levels {
 | ||
| 		// 获取该级别的配置
 | ||
| 		levelConfig, exists := l.config.LevelConfigs[level]
 | ||
| 		if !exists {
 | ||
| 			// 如果没有配置,使用默认配置
 | ||
| 			levelConfig = LevelFileConfig{
 | ||
| 				MaxSize:    100,
 | ||
| 				MaxBackups: 5,
 | ||
| 				MaxAge:     30,
 | ||
| 				Compress:   true,
 | ||
| 			}
 | ||
| 		}
 | ||
| 
 | ||
| 		// 创建该级别的文件输出
 | ||
| 		writeSyncer := l.createLevelWriteSyncer(level, levelConfig)
 | ||
| 		
 | ||
| 		// 创建编码器
 | ||
| 		encoder := getEncoder(l.config.BaseConfig.Format, l.config.BaseConfig)
 | ||
| 		
 | ||
| 		// 创建 Core
 | ||
| 		core := zapcore.NewCore(encoder, writeSyncer, level)
 | ||
| 		
 | ||
| 		// 创建该级别的日志器
 | ||
| 		levelLogger := zap.New(core,
 | ||
| 			zap.AddCaller(),
 | ||
| 			zap.AddCallerSkip(1),
 | ||
| 			zap.AddStacktrace(zapcore.ErrorLevel),
 | ||
| 		)
 | ||
| 
 | ||
| 		l.levelLoggers[level] = levelLogger
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // createLevelWriteSyncer 创建级别特定的文件输出同步器
 | ||
| func (l *LevelLogger) createLevelWriteSyncer(level zapcore.Level, config LevelFileConfig) zapcore.WriteSyncer {
 | ||
| 	// 构建文件路径
 | ||
| 	var logFilePath string
 | ||
| 	if l.config.BaseConfig.UseDaily {
 | ||
| 		// 按日期分包:logs/2024-01-01/debug.log
 | ||
| 		date := time.Now().Format("2006-01-02")
 | ||
| 		levelName := level.String()
 | ||
| 		logFilePath = filepath.Join(l.config.BaseConfig.LogDir, date, levelName+".log")
 | ||
| 	} else {
 | ||
| 		// 传统方式:logs/debug.log
 | ||
| 		levelName := level.String()
 | ||
| 		logFilePath = filepath.Join(l.config.BaseConfig.LogDir, levelName+".log")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 创建 lumberjack 日志轮转器
 | ||
| 	rotator := &lumberjack.Logger{
 | ||
| 		Filename:   logFilePath,
 | ||
| 		MaxSize:    config.MaxSize,
 | ||
| 		MaxBackups: config.MaxBackups,
 | ||
| 		MaxAge:     config.MaxAge,
 | ||
| 		Compress:   config.Compress,
 | ||
| 	}
 | ||
| 
 | ||
| 	return zapcore.AddSync(rotator)
 | ||
| }
 | ||
| 
 | ||
| // GetLevelLogger 获取指定级别的日志器
 | ||
| func (l *LevelLogger) GetLevelLogger(level zapcore.Level) *zap.Logger {
 | ||
| 	if logger, exists := l.levelLoggers[level]; exists {
 | ||
| 		return logger
 | ||
| 	}
 | ||
| 	return l.logger
 | ||
| }
 | ||
| 
 | ||
| // 实现 Logger 接口
 | ||
| func (l *LevelLogger) Debug(msg string, fields ...zapcore.Field) {
 | ||
| 	if logger := l.GetLevelLogger(zapcore.DebugLevel); logger != nil {
 | ||
| 		logger.Debug(msg, fields...)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Info(msg string, fields ...zapcore.Field) {
 | ||
| 	if logger := l.GetLevelLogger(zapcore.InfoLevel); logger != nil {
 | ||
| 		logger.Info(msg, fields...)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Warn(msg string, fields ...zapcore.Field) {
 | ||
| 	if logger := l.GetLevelLogger(zapcore.WarnLevel); logger != nil {
 | ||
| 		logger.Warn(msg, fields...)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Error(msg string, fields ...zapcore.Field) {
 | ||
| 	if logger := l.GetLevelLogger(zapcore.ErrorLevel); logger != nil {
 | ||
| 		logger.Error(msg, fields...)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Fatal(msg string, fields ...zapcore.Field) {
 | ||
| 	if logger := l.GetLevelLogger(zapcore.FatalLevel); logger != nil {
 | ||
| 		logger.Fatal(msg, fields...)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Panic(msg string, fields ...zapcore.Field) {
 | ||
| 	if logger := l.GetLevelLogger(zapcore.PanicLevel); logger != nil {
 | ||
| 		logger.Panic(msg, fields...)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) With(fields ...zapcore.Field) Logger {
 | ||
| 	// 为所有级别添加字段
 | ||
| 	for level, logger := range l.levelLoggers {
 | ||
| 		l.levelLoggers[level] = logger.With(fields...)
 | ||
| 	}
 | ||
| 	return l
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) WithContext(ctx context.Context) Logger {
 | ||
| 	// 从上下文提取字段
 | ||
| 	fields := extractFieldsFromContext(ctx)
 | ||
| 	return l.With(fields...)
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Named(name string) Logger {
 | ||
| 	// 为所有级别添加名称
 | ||
| 	for level, logger := range l.levelLoggers {
 | ||
| 		l.levelLoggers[level] = logger.Named(name)
 | ||
| 	}
 | ||
| 	return l
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Sync() error {
 | ||
| 	// 同步所有级别的日志器
 | ||
| 	for _, logger := range l.levelLoggers {
 | ||
| 		if err := logger.Sync(); err != nil {
 | ||
| 			return err
 | ||
| 		}
 | ||
| 	}
 | ||
| 	return l.logger.Sync()
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) Core() zapcore.Core {
 | ||
| 	return l.logger.Core()
 | ||
| }
 | ||
| 
 | ||
| func (l *LevelLogger) GetZapLogger() *zap.Logger {
 | ||
| 	return l.logger
 | ||
| }
 |