github.com/whoyao/protocol@v0.0.0-20230519045905-2d8ace718ca5/logger/logger.go (about) 1 package logger 2 3 import ( 4 "time" 5 6 "github.com/go-logr/logr" 7 "go.uber.org/zap" 8 "go.uber.org/zap/zapcore" 9 ) 10 11 var ( 12 discardLogger = logr.Discard() 13 defaultLogger Logger = LogRLogger(discardLogger) 14 pkgLogger Logger = LogRLogger(discardLogger) 15 ) 16 17 // InitFromConfig initializes a Zap-based logger 18 func InitFromConfig(conf Config, name string) { 19 l, err := NewZapLogger(&conf) 20 if err == nil { 21 SetLogger(l, name) 22 } 23 } 24 25 // GetLogger returns the logger that was set with SetLogger with an extra depth of 1 26 func GetLogger() Logger { 27 return defaultLogger 28 } 29 30 // SetLogger lets you use a custom logger. Pass in a logr.Logger with default depth 31 func SetLogger(l Logger, name string) { 32 defaultLogger = l.WithCallDepth(1).WithName(name) 33 // pkg wrapper needs to drop two levels of depth 34 pkgLogger = l.WithCallDepth(2).WithName(name) 35 } 36 37 func Debugw(msg string, keysAndValues ...interface{}) { 38 pkgLogger.Debugw(msg, keysAndValues...) 39 } 40 41 func Infow(msg string, keysAndValues ...interface{}) { 42 pkgLogger.Infow(msg, keysAndValues...) 43 } 44 45 func Warnw(msg string, err error, keysAndValues ...interface{}) { 46 pkgLogger.Warnw(msg, err, keysAndValues...) 47 } 48 49 func Errorw(msg string, err error, keysAndValues ...interface{}) { 50 pkgLogger.Errorw(msg, err, keysAndValues...) 51 } 52 53 func ParseZapLevel(level string) zapcore.Level { 54 lvl := zapcore.InfoLevel 55 if level != "" { 56 _ = lvl.UnmarshalText([]byte(level)) 57 } 58 return lvl 59 } 60 61 type Logger interface { 62 Debugw(msg string, keysAndValues ...interface{}) 63 Infow(msg string, keysAndValues ...interface{}) 64 Warnw(msg string, err error, keysAndValues ...interface{}) 65 Errorw(msg string, err error, keysAndValues ...interface{}) 66 WithValues(keysAndValues ...interface{}) Logger 67 WithName(name string) Logger 68 WithCallDepth(depth int) Logger 69 WithItemSampler() Logger 70 // WithoutSampler returns the original logger without sampling 71 WithoutSampler() Logger 72 } 73 74 type ZapLogger struct { 75 zap *zap.SugaredLogger 76 // store original logger without sampling to avoid multiple samplers 77 unsampled *zap.SugaredLogger 78 SampleDuration time.Duration 79 SampleInitial int 80 SampleInterval int 81 } 82 83 func NewZapLogger(conf *Config) (*ZapLogger, error) { 84 lvl := ParseZapLevel(conf.Level) 85 zapConfig := zap.Config{ 86 Level: zap.NewAtomicLevelAt(lvl), 87 Development: false, 88 Encoding: "console", 89 EncoderConfig: zap.NewDevelopmentEncoderConfig(), 90 OutputPaths: []string{"stderr"}, 91 ErrorOutputPaths: []string{"stderr"}, 92 } 93 if conf.JSON { 94 zapConfig.Encoding = "json" 95 zapConfig.EncoderConfig = zap.NewProductionEncoderConfig() 96 } 97 l, err := zapConfig.Build() 98 if err != nil { 99 return nil, err 100 } 101 zl := &ZapLogger{ 102 unsampled: l.Sugar(), 103 SampleDuration: time.Duration(conf.ItemSampleSeconds) * time.Second, 104 SampleInitial: conf.ItemSampleInitial, 105 SampleInterval: conf.ItemSampleInterval, 106 } 107 108 if conf.Sample { 109 // use a sampling logger for the main logger 110 samplingConf := &zap.SamplingConfig{ 111 Initial: conf.SampleInitial, 112 Thereafter: conf.SampleInterval, 113 } 114 // sane defaults 115 if samplingConf.Initial == 0 { 116 samplingConf.Initial = 20 117 } 118 if samplingConf.Thereafter == 0 { 119 samplingConf.Thereafter = 100 120 } 121 zl.zap = l.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { 122 return zapcore.NewSamplerWithOptions( 123 core, 124 time.Second, 125 samplingConf.Initial, 126 samplingConf.Thereafter, 127 ) 128 })).Sugar() 129 } else { 130 zl.zap = zl.unsampled 131 } 132 return zl, nil 133 } 134 135 func (l *ZapLogger) ToZap() *zap.SugaredLogger { 136 return l.zap 137 } 138 139 func (l *ZapLogger) Debugw(msg string, keysAndValues ...interface{}) { 140 l.zap.Debugw(msg, keysAndValues...) 141 } 142 143 func (l *ZapLogger) Infow(msg string, keysAndValues ...interface{}) { 144 l.zap.Infow(msg, keysAndValues...) 145 } 146 147 func (l *ZapLogger) Warnw(msg string, err error, keysAndValues ...interface{}) { 148 if err != nil { 149 keysAndValues = append(keysAndValues, "error", err) 150 } 151 l.zap.Warnw(msg, keysAndValues...) 152 } 153 154 func (l *ZapLogger) Errorw(msg string, err error, keysAndValues ...interface{}) { 155 if err != nil { 156 keysAndValues = append(keysAndValues, "error", err) 157 } 158 l.zap.Errorw(msg, keysAndValues...) 159 } 160 161 func (l *ZapLogger) WithValues(keysAndValues ...interface{}) Logger { 162 dup := *l 163 dup.zap = l.zap.With(keysAndValues...) 164 // mirror unsampled logger too 165 if l.unsampled == l.zap { 166 dup.unsampled = dup.zap 167 } else { 168 dup.unsampled = l.unsampled.With(keysAndValues...) 169 } 170 return &dup 171 } 172 173 func (l *ZapLogger) WithName(name string) Logger { 174 dup := *l 175 dup.zap = l.zap.Named(name) 176 if l.unsampled == l.zap { 177 dup.unsampled = dup.zap 178 } else { 179 dup.unsampled = l.unsampled.Named(name) 180 } 181 return &dup 182 } 183 184 func (l *ZapLogger) WithCallDepth(depth int) Logger { 185 dup := *l 186 dup.zap = l.zap.WithOptions(zap.AddCallerSkip(depth)) 187 if l.unsampled == l.zap { 188 dup.unsampled = dup.zap 189 } else { 190 dup.unsampled = l.unsampled.WithOptions(zap.AddCallerSkip(depth)) 191 } 192 return &dup 193 } 194 195 func (l *ZapLogger) WithItemSampler() Logger { 196 if l.SampleDuration == 0 { 197 return l 198 } 199 dup := *l 200 dup.zap = l.unsampled.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { 201 return zapcore.NewSamplerWithOptions( 202 core, 203 l.SampleDuration, 204 l.SampleInitial, 205 l.SampleInterval, 206 ) 207 })) 208 return &dup 209 } 210 211 func (l *ZapLogger) WithoutSampler() Logger { 212 if l.SampleDuration == 0 { 213 return l 214 } 215 dup := *l 216 dup.zap = l.unsampled 217 return &dup 218 } 219 220 type LogRLogger logr.Logger 221 222 func (l LogRLogger) toLogr() logr.Logger { 223 if logr.Logger(l).GetSink() == nil { 224 return discardLogger 225 } 226 return logr.Logger(l) 227 } 228 229 func (l LogRLogger) Debugw(msg string, keysAndValues ...interface{}) { 230 l.toLogr().V(1).Info(msg, keysAndValues...) 231 } 232 233 func (l LogRLogger) Infow(msg string, keysAndValues ...interface{}) { 234 l.toLogr().Info(msg, keysAndValues...) 235 } 236 237 func (l LogRLogger) Warnw(msg string, err error, keysAndValues ...interface{}) { 238 if err != nil { 239 keysAndValues = append(keysAndValues, "error", err) 240 } 241 l.toLogr().Info(msg, keysAndValues...) 242 } 243 244 func (l LogRLogger) Errorw(msg string, err error, keysAndValues ...interface{}) { 245 l.toLogr().Error(err, msg, keysAndValues...) 246 } 247 248 func (l LogRLogger) WithValues(keysAndValues ...interface{}) Logger { 249 return LogRLogger(l.toLogr().WithValues(keysAndValues...)) 250 } 251 252 func (l LogRLogger) WithName(name string) Logger { 253 return LogRLogger(l.toLogr().WithName(name)) 254 } 255 256 func (l LogRLogger) WithCallDepth(depth int) Logger { 257 return LogRLogger(l.toLogr().WithCallDepth(depth)) 258 } 259 260 func (l LogRLogger) WithItemSampler() Logger { 261 // logr does not support sampling 262 return l 263 } 264 265 func (l LogRLogger) WithoutSampler() Logger { 266 return l 267 }