github.com/binbinly/pkg@v0.0.11-0.20240321014439-f4fbf666eb0f/logger/zap.go (about) 1 package logger 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 8 "go.uber.org/zap" 9 "go.uber.org/zap/zapcore" 10 "gopkg.in/natefinch/lumberjack.v2" 11 ) 12 13 type zapLogger struct { 14 zap *zap.Logger 15 opts Options 16 } 17 18 func (l *zapLogger) Init(opts ...Option) error { 19 for _, o := range opts { 20 o(&l.opts) 21 } 22 23 stdout := zapcore.Lock(os.Stdout) // lock for concurrent safe 24 stderr := zapcore.Lock(os.Stderr) // lock for concurrent safe 25 26 infoEnabler := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 27 return lvl >= getZapLevel(l.opts.Level) && lvl < zapcore.WarnLevel 28 }) 29 warnEnabler := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool { 30 return lvl >= zapcore.WarnLevel 31 }) 32 33 encoderCfg := zap.NewProductionEncoderConfig() 34 if l.opts.Debug { 35 encoderCfg = zap.NewDevelopmentEncoderConfig() 36 } 37 38 encoder := zapcore.NewConsoleEncoder(encoderCfg) 39 if l.opts.JsonEncoding { 40 encoder = zapcore.NewJSONEncoder(encoderCfg) 41 } 42 43 var cores []zapcore.Core 44 if !l.opts.DisableConsole { 45 consoleCore := zapcore.NewCore( 46 encoder, 47 zapcore.NewMultiWriteSyncer(stdout), 48 infoEnabler, 49 ) 50 errorCore := zapcore.NewCore( 51 encoder, 52 zapcore.NewMultiWriteSyncer(stderr), 53 warnEnabler, 54 ) 55 cores = append(cores, consoleCore, errorCore) 56 } 57 58 if l.opts.LogDir != "" { 59 if err := os.MkdirAll(l.opts.LogDir, 0766); err != nil { 60 return err 61 } 62 infoFile := zapcore.AddSync(l.fileSizeRotation(l.opts.LogDir + "info.log")) 63 warnFile := zapcore.AddSync(l.fileSizeRotation(l.opts.LogDir + "warn.log")) 64 infoCore := zapcore.NewCore( 65 encoder, zapcore.NewMultiWriteSyncer(infoFile), 66 infoEnabler, 67 ) 68 warnCore := zapcore.NewCore( 69 encoder, zapcore.NewMultiWriteSyncer(warnFile), 70 warnEnabler, 71 ) 72 cores = append(cores, infoCore, warnCore) 73 } 74 75 // 构造日志 76 l.zap = zap.New( 77 zapcore.NewTee(cores...), 78 zap.AddCaller(), 79 zap.AddCallerSkip(l.opts.CallerSkipCount), 80 zap.AddStacktrace(zapcore.ErrorLevel), // 记录当前日志级别的堆栈信息 81 zap.ErrorOutput(stderr), 82 ) 83 84 if l.opts.Fields != nil { 85 fields := make([]zap.Field, 0, len(l.opts.Fields)) 86 for k, v := range l.opts.Fields { 87 fields = append(fields, zap.Any(k, v)) 88 } 89 l.zap = l.zap.With(fields...) 90 } 91 return nil 92 } 93 94 func (l *zapLogger) Fields(fields map[string]any) Logger { 95 data := make([]zap.Field, 0, len(fields)) 96 for k, v := range fields { 97 data = append(data, zap.Any(k, v)) 98 } 99 100 zl := &zapLogger{ 101 zap: l.zap.With(data...), 102 opts: l.opts, 103 } 104 105 return zl 106 } 107 108 func (l *zapLogger) Log(level string, v ...any) { 109 l.zap.Log(getZapLevel(level), fmt.Sprint(v...)) 110 } 111 112 func (l *zapLogger) Logf(level string, format string, v ...any) { 113 l.zap.Log(getZapLevel(level), fmt.Sprintf(format, v...)) 114 } 115 116 func (l *zapLogger) fileSizeRotation(file string) io.Writer { 117 return &lumberjack.Logger{ 118 Filename: file, 119 MaxSize: l.opts.Rotation.MaxSize, 120 MaxBackups: l.opts.Rotation.MaxBackups, 121 MaxAge: l.opts.Rotation.MaxAge, 122 LocalTime: l.opts.Rotation.LocalTime, 123 Compress: l.opts.Rotation.Compress, 124 } 125 } 126 127 // NewExampleLogger builds a Logger that's designed for use in zap's testable 128 func NewExampleLogger() Logger { 129 return &zapLogger{ 130 zap: zap.NewExample(), 131 } 132 } 133 134 // NewLogger New builds a new logger based on options. 135 func NewLogger(opts ...Option) Logger { 136 l := &zapLogger{opts: _defOptions} 137 if err := l.Init(opts...); err != nil { 138 return nil 139 } 140 141 return l 142 } 143 144 // InitLogger init customize logger 145 func InitLogger(opts ...Option) { 146 l := &zapLogger{opts: _defOptions} 147 if err := l.Init(opts...); err != nil { 148 panic(err) 149 } 150 151 logger = l 152 }