package logger import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" "gopkg.in/natefinch/lumberjack.v2" ) var ( // appLogger 应用日志记录器 appLogger *zap.Logger // accessLogger 访问日志记录器 accessLogger *zap.Logger ) // InitLoggers 初始化应用和访问日志记录器 func InitLoggers( level string, development bool, appLogConfig LogRotationConfig, accessLogConfig LogRotationConfig, ) error { // 解析日志级别 zapLevel := parseLevel(level) // 创建编码器配置 encoderConfig := zapcore.EncoderConfig{ TimeKey: "timestamp", LevelKey: "level", NameKey: "logger", CallerKey: "caller", MessageKey: "message", StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.LowercaseLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, // RFC3339 格式 EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } // 选择编码器(开发模式使用控制台,生产使用 JSON) var encoder zapcore.Encoder if development { encoder = zapcore.NewConsoleEncoder(encoderConfig) } else { encoder = zapcore.NewJSONEncoder(encoderConfig) } // 创建应用日志核心 appCore := zapcore.NewCore( encoder, zapcore.AddSync(newLumberjackLogger(appLogConfig)), zapLevel, ) // 创建访问日志核心(始终使用 JSON) accessCore := zapcore.NewCore( zapcore.NewJSONEncoder(encoderConfig), zapcore.AddSync(newLumberjackLogger(accessLogConfig)), zapcore.InfoLevel, // 访问日志始终使用 info 级别 ) // 构建日志记录器 if development { // 开发模式:添加调用者信息和堆栈跟踪 appLogger = zap.New(appCore, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel), zap.Development()) } else { // 生产模式:添加调用者信息,仅在 error 时添加堆栈跟踪 appLogger = zap.New(appCore, zap.AddCaller(), zap.AddStacktrace(zapcore.ErrorLevel)) } // 访问日志不需要调用者信息 accessLogger = zap.New(accessCore) return nil } // GetAppLogger 返回应用日志记录器 func GetAppLogger() *zap.Logger { if appLogger == nil { // 如果未初始化,返回 nop logger return zap.NewNop() } return appLogger } // GetAccessLogger 返回访问日志记录器 func GetAccessLogger() *zap.Logger { if accessLogger == nil { // 如果未初始化,返回 nop logger return zap.NewNop() } return accessLogger } // Sync 刷新所有日志缓冲区 func Sync() error { if appLogger != nil { if err := appLogger.Sync(); err != nil { return err } } if accessLogger != nil { if err := accessLogger.Sync(); err != nil { return err } } return nil } // parseLevel 解析日志级别字符串 func parseLevel(level string) zapcore.Level { switch level { case "debug": return zapcore.DebugLevel case "info": return zapcore.InfoLevel case "warn": return zapcore.WarnLevel case "error": return zapcore.ErrorLevel default: return zapcore.InfoLevel } } // newLumberjackLogger 创建 Lumberjack 日志轮转器 func newLumberjackLogger(config LogRotationConfig) *lumberjack.Logger { return &lumberjack.Logger{ Filename: config.Filename, MaxSize: config.MaxSize, MaxBackups: config.MaxBackups, MaxAge: config.MaxAge, Compress: config.Compress, LocalTime: true, // 使用本地时间 } } // LogRotationConfig 日志轮转配置(从 config 包复制以避免循环依赖) type LogRotationConfig struct { Filename string MaxSize int MaxBackups int MaxAge int Compress bool }