package log import ( "fmt" "github.com/natefinch/lumberjack" "go.uber.org/zap" "go.uber.org/zap/zapcore" "os" "runtime" "time" ) var ( logger *zap.Logger file *os.File ) const ( DebugL = zapcore.DebugLevel InfoL = zapcore.InfoLevel WarnL = zapcore.WarnLevel ErrorL = zapcore.ErrorLevel ) func Open(filepath string, level zapcore.Level) { if level < DebugL || level > ErrorL { level = DebugL } // 自定义时间编码器,不显示时区 customTimeEncoder := func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { enc.AppendString(t.Format("2006-01-02 15:04:05.000")) // 使用不含时区的格式 } // 配置lumberjack file := &lumberjack.Logger{ Filename: filepath, // 日志文件的位置 MaxSize: 100, // 每个日志文件保存的最大尺寸 单位:MB MaxBackups: 3, // 日志文件最多保存多少个备份 MaxAge: 28, // 文件最多保存多少天 Compress: true, // 是否压缩/归档旧文件 } // var err error // // 打开日志文件 // file, err = os.OpenFile(filepath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) // if err != nil { // zap.L().Fatal("无法打开日志文件", zap.Error(err)) // } // 设置编码器配置 encoderConfig := zapcore.EncoderConfig{ TimeKey: "time", LevelKey: "level", NameKey: "logger", CallerKey: "caller", MessageKey: "msg", StacktraceKey: "stacktrace", LineEnding: zapcore.DefaultLineEnding, EncodeLevel: zapcore.LowercaseLevelEncoder, EncodeTime: customTimeEncoder, EncodeDuration: zapcore.SecondsDurationEncoder, EncodeCaller: zapcore.ShortCallerEncoder, } // 创建控制台输出 consoleEncoder := zapcore.NewConsoleEncoder(encoderConfig) consoleWriter := zapcore.AddSync(os.Stdout) consoleCore := zapcore.NewCore(consoleEncoder, consoleWriter, zap.NewAtomicLevelAt(zap.DebugLevel)) // 创建文件输出 fileEncoder := zapcore.NewJSONEncoder(encoderConfig) fileWriter := zapcore.AddSync(file) fileCore := zapcore.NewCore(fileEncoder, fileWriter, zap.NewAtomicLevelAt(level)) // 将两个 Core 组合成一个 MultiWriteSyncer core := zapcore.NewTee(consoleCore, fileCore) // 创建logger对象 logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1)) // Info = logger.Info // Debug = logger.Debug // Warn = logger.Warn // Error = logger.Error // Fatal = logger.Fatal } func Close() { if logger != nil { _ = logger.Sync() logger = nil } if file != nil { _ = file.Close() file = nil } } func StackTrace() string { var pcs [32]uintptr n := runtime.Callers(3, pcs[:]) // 跳过前3个栈帧,即printStackTrace, caller, 和runtime.Callers本身 frames := runtime.CallersFrames(pcs[:n]) s := "" for { frame, more := frames.Next() s += fmt.Sprintf("%+v\n", frame) if !more { break } } return s } func InfoF(format string, args ...any) { logger.Info(fmt.Sprintf(format, args...)) } func Info(msg string, fields ...zap.Field) { logger.Info(msg, fields...) } func Debug(msg string, fields ...zap.Field) { logger.Debug(msg, fields...) } func DebugF(format string, args ...any) { logger.Debug(fmt.Sprintf(format, args...)) } func Warn(msg string, fields ...zap.Field) { logger.Warn(msg, fields...) } func WarnF(format string, args ...any) { logger.Info(fmt.Sprintf(format, args...)) } func Error(msg string, fields ...zap.Field) { logger.Error(msg, fields...) } func ErrorF(format string, args ...any) { logger.Error(fmt.Sprintf(format, args...)) } func Fatal(msg string, fields ...zap.Field) { logger.Fatal(msg, fields...) } func FatalF(format string, args ...any) { logger.Fatal(fmt.Sprintf(format, args...)) } // 提供logger,方便其它库打印正确的日志调用点 func GetLogger() *zap.Logger { return logger }