trpc.group/trpc-go/trpc-go@v1.0.2/log/zaplogger.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package log 15 16 import ( 17 "fmt" 18 "os" 19 "strconv" 20 "time" 21 22 "trpc.group/trpc-go/trpc-go/internal/report" 23 "trpc.group/trpc-go/trpc-go/log/rollwriter" 24 25 "go.uber.org/zap" 26 "go.uber.org/zap/zapcore" 27 ) 28 29 var defaultConfig = []OutputConfig{ 30 { 31 Writer: "console", 32 Level: "debug", 33 Formatter: "console", 34 }, 35 } 36 37 // Some ZapCore constants. 38 const ( 39 ConsoleZapCore = "console" 40 FileZapCore = "file" 41 ) 42 43 // Levels is the map from string to zapcore.Level. 44 var Levels = map[string]zapcore.Level{ 45 "": zapcore.DebugLevel, 46 "trace": zapcore.DebugLevel, 47 "debug": zapcore.DebugLevel, 48 "info": zapcore.InfoLevel, 49 "warn": zapcore.WarnLevel, 50 "error": zapcore.ErrorLevel, 51 "fatal": zapcore.FatalLevel, 52 } 53 54 var levelToZapLevel = map[Level]zapcore.Level{ 55 LevelTrace: zapcore.DebugLevel, 56 LevelDebug: zapcore.DebugLevel, 57 LevelInfo: zapcore.InfoLevel, 58 LevelWarn: zapcore.WarnLevel, 59 LevelError: zapcore.ErrorLevel, 60 LevelFatal: zapcore.FatalLevel, 61 } 62 63 var zapLevelToLevel = map[zapcore.Level]Level{ 64 zapcore.DebugLevel: LevelDebug, 65 zapcore.InfoLevel: LevelInfo, 66 zapcore.WarnLevel: LevelWarn, 67 zapcore.ErrorLevel: LevelError, 68 zapcore.FatalLevel: LevelFatal, 69 } 70 71 // NewZapLog creates a trpc default Logger from zap whose caller skip is set to 2. 72 func NewZapLog(c Config) Logger { 73 return NewZapLogWithCallerSkip(c, 2) 74 } 75 76 // NewZapLogWithCallerSkip creates a trpc default Logger from zap. 77 func NewZapLogWithCallerSkip(cfg Config, callerSkip int) Logger { 78 var ( 79 cores []zapcore.Core 80 levels []zap.AtomicLevel 81 ) 82 for _, c := range cfg { 83 writer := GetWriter(c.Writer) 84 if writer == nil { 85 panic("log: writer core: " + c.Writer + " no registered") 86 } 87 decoder := &Decoder{OutputConfig: &c} 88 if err := writer.Setup(c.Writer, decoder); err != nil { 89 panic("log: writer core: " + c.Writer + " setup fail: " + err.Error()) 90 } 91 cores = append(cores, decoder.Core) 92 levels = append(levels, decoder.ZapLevel) 93 } 94 return &zapLog{ 95 levels: levels, 96 logger: zap.New( 97 zapcore.NewTee(cores...), 98 zap.AddCallerSkip(callerSkip), 99 zap.AddCaller(), 100 ), 101 } 102 } 103 104 func newEncoder(c *OutputConfig) zapcore.Encoder { 105 encoderCfg := zapcore.EncoderConfig{ 106 TimeKey: GetLogEncoderKey("T", c.FormatConfig.TimeKey), 107 LevelKey: GetLogEncoderKey("L", c.FormatConfig.LevelKey), 108 NameKey: GetLogEncoderKey("N", c.FormatConfig.NameKey), 109 CallerKey: GetLogEncoderKey("C", c.FormatConfig.CallerKey), 110 FunctionKey: GetLogEncoderKey(zapcore.OmitKey, c.FormatConfig.FunctionKey), 111 MessageKey: GetLogEncoderKey("M", c.FormatConfig.MessageKey), 112 StacktraceKey: GetLogEncoderKey("S", c.FormatConfig.StacktraceKey), 113 LineEnding: zapcore.DefaultLineEnding, 114 EncodeLevel: zapcore.CapitalLevelEncoder, 115 EncodeTime: NewTimeEncoder(c.FormatConfig.TimeFmt), 116 EncodeDuration: zapcore.StringDurationEncoder, 117 EncodeCaller: zapcore.ShortCallerEncoder, 118 } 119 if c.EnableColor { 120 encoderCfg.EncodeLevel = zapcore.CapitalColorLevelEncoder 121 } 122 switch c.Formatter { 123 case "console": 124 return zapcore.NewConsoleEncoder(encoderCfg) 125 case "json": 126 return zapcore.NewJSONEncoder(encoderCfg) 127 default: 128 return zapcore.NewConsoleEncoder(encoderCfg) 129 } 130 } 131 132 // GetLogEncoderKey gets user defined log output name, uses defKey if empty. 133 func GetLogEncoderKey(defKey, key string) string { 134 if key == "" { 135 return defKey 136 } 137 return key 138 } 139 140 func newConsoleCore(c *OutputConfig) (zapcore.Core, zap.AtomicLevel) { 141 lvl := zap.NewAtomicLevelAt(Levels[c.Level]) 142 return zapcore.NewCore( 143 newEncoder(c), 144 zapcore.Lock(os.Stdout), 145 lvl), lvl 146 } 147 148 func newFileCore(c *OutputConfig) (zapcore.Core, zap.AtomicLevel, error) { 149 opts := []rollwriter.Option{ 150 rollwriter.WithMaxAge(c.WriteConfig.MaxAge), 151 rollwriter.WithMaxBackups(c.WriteConfig.MaxBackups), 152 rollwriter.WithCompress(c.WriteConfig.Compress), 153 rollwriter.WithMaxSize(c.WriteConfig.MaxSize), 154 } 155 // roll by time. 156 if c.WriteConfig.RollType != RollBySize { 157 opts = append(opts, rollwriter.WithRotationTime(c.WriteConfig.TimeUnit.Format())) 158 } 159 writer, err := rollwriter.NewRollWriter(c.WriteConfig.Filename, opts...) 160 if err != nil { 161 return nil, zap.AtomicLevel{}, err 162 } 163 164 // write mode. 165 var ws zapcore.WriteSyncer 166 switch m := c.WriteConfig.WriteMode; m { 167 case 0, WriteFast: 168 // Use WriteFast as default mode. 169 // It has better performance, discards logs on full and avoid blocking service. 170 ws = rollwriter.NewAsyncRollWriter(writer, rollwriter.WithDropLog(true)) 171 case WriteSync: 172 ws = zapcore.AddSync(writer) 173 case WriteAsync: 174 ws = rollwriter.NewAsyncRollWriter(writer, rollwriter.WithDropLog(false)) 175 default: 176 return nil, zap.AtomicLevel{}, fmt.Errorf("validating WriteMode parameter: got %d, "+ 177 "but expect one of WriteFast(%d), WriteAsync(%d), or WriteSync(%d)", m, WriteFast, WriteAsync, WriteSync) 178 } 179 180 // log level. 181 lvl := zap.NewAtomicLevelAt(Levels[c.Level]) 182 return zapcore.NewCore( 183 newEncoder(c), 184 ws, lvl, 185 ), lvl, nil 186 } 187 188 // NewTimeEncoder creates a time format encoder. 189 func NewTimeEncoder(format string) zapcore.TimeEncoder { 190 switch format { 191 case "": 192 return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 193 enc.AppendByteString(defaultTimeFormat(t)) 194 } 195 case "seconds": 196 return zapcore.EpochTimeEncoder 197 case "milliseconds": 198 return zapcore.EpochMillisTimeEncoder 199 case "nanoseconds": 200 return zapcore.EpochNanosTimeEncoder 201 default: 202 return func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { 203 enc.AppendString(t.Format(format)) 204 } 205 } 206 } 207 208 // defaultTimeFormat returns the default time format "2006-01-02 15:04:05.000", 209 // which performs better than https://pkg.go.dev/time#Time.AppendFormat. 210 func defaultTimeFormat(t time.Time) []byte { 211 t = t.Local() 212 year, month, day := t.Date() 213 hour, minute, second := t.Clock() 214 micros := t.Nanosecond() / 1000 215 216 buf := make([]byte, 23) 217 buf[0] = byte((year/1000)%10) + '0' 218 buf[1] = byte((year/100)%10) + '0' 219 buf[2] = byte((year/10)%10) + '0' 220 buf[3] = byte(year%10) + '0' 221 buf[4] = '-' 222 buf[5] = byte((month)/10) + '0' 223 buf[6] = byte((month)%10) + '0' 224 buf[7] = '-' 225 buf[8] = byte((day)/10) + '0' 226 buf[9] = byte((day)%10) + '0' 227 buf[10] = ' ' 228 buf[11] = byte((hour)/10) + '0' 229 buf[12] = byte((hour)%10) + '0' 230 buf[13] = ':' 231 buf[14] = byte((minute)/10) + '0' 232 buf[15] = byte((minute)%10) + '0' 233 buf[16] = ':' 234 buf[17] = byte((second)/10) + '0' 235 buf[18] = byte((second)%10) + '0' 236 buf[19] = '.' 237 buf[20] = byte((micros/100000)%10) + '0' 238 buf[21] = byte((micros/10000)%10) + '0' 239 buf[22] = byte((micros/1000)%10) + '0' 240 return buf 241 } 242 243 // zapLog is a Logger implementation based on zaplogger. 244 type zapLog struct { 245 levels []zap.AtomicLevel 246 logger *zap.Logger 247 } 248 249 func (l *zapLog) WithOptions(opts ...Option) Logger { 250 o := &options{} 251 for _, opt := range opts { 252 opt(o) 253 } 254 return &zapLog{ 255 levels: l.levels, 256 logger: l.logger.WithOptions(zap.AddCallerSkip(o.skip)), 257 } 258 } 259 260 // With add user defined fields to Logger. Fields support multiple values. 261 func (l *zapLog) With(fields ...Field) Logger { 262 zapFields := make([]zap.Field, len(fields)) 263 for i := range fields { 264 zapFields[i] = zap.Any(fields[i].Key, fields[i].Value) 265 } 266 267 return &zapLog{ 268 levels: l.levels, 269 logger: l.logger.With(zapFields...)} 270 } 271 272 func getLogMsg(args ...interface{}) string { 273 msg := fmt.Sprint(args...) 274 report.LogWriteSize.IncrBy(float64(len(msg))) 275 return msg 276 } 277 278 func getLogMsgf(format string, args ...interface{}) string { 279 msg := fmt.Sprintf(format, args...) 280 report.LogWriteSize.IncrBy(float64(len(msg))) 281 return msg 282 } 283 284 // Trace logs to TRACE log. Arguments are handled in the manner of fmt.Print. 285 func (l *zapLog) Trace(args ...interface{}) { 286 if l.logger.Core().Enabled(zapcore.DebugLevel) { 287 l.logger.Debug(getLogMsg(args...)) 288 } 289 } 290 291 // Tracef logs to TRACE log. Arguments are handled in the manner of fmt.Printf. 292 func (l *zapLog) Tracef(format string, args ...interface{}) { 293 if l.logger.Core().Enabled(zapcore.DebugLevel) { 294 l.logger.Debug(getLogMsgf(format, args...)) 295 } 296 } 297 298 // Debug logs to DEBUG log. Arguments are handled in the manner of fmt.Print. 299 func (l *zapLog) Debug(args ...interface{}) { 300 if l.logger.Core().Enabled(zapcore.DebugLevel) { 301 l.logger.Debug(getLogMsg(args...)) 302 } 303 } 304 305 // Debugf logs to DEBUG log. Arguments are handled in the manner of fmt.Printf. 306 func (l *zapLog) Debugf(format string, args ...interface{}) { 307 if l.logger.Core().Enabled(zapcore.DebugLevel) { 308 l.logger.Debug(getLogMsgf(format, args...)) 309 } 310 } 311 312 // Info logs to INFO log. Arguments are handled in the manner of fmt.Print. 313 func (l *zapLog) Info(args ...interface{}) { 314 if l.logger.Core().Enabled(zapcore.InfoLevel) { 315 l.logger.Info(getLogMsg(args...)) 316 } 317 } 318 319 // Infof logs to INFO log. Arguments are handled in the manner of fmt.Printf. 320 func (l *zapLog) Infof(format string, args ...interface{}) { 321 if l.logger.Core().Enabled(zapcore.InfoLevel) { 322 l.logger.Info(getLogMsgf(format, args...)) 323 } 324 } 325 326 // Warn logs to WARNING log. Arguments are handled in the manner of fmt.Print. 327 func (l *zapLog) Warn(args ...interface{}) { 328 if l.logger.Core().Enabled(zapcore.WarnLevel) { 329 l.logger.Warn(getLogMsg(args...)) 330 } 331 } 332 333 // Warnf logs to WARNING log. Arguments are handled in the manner of fmt.Printf. 334 func (l *zapLog) Warnf(format string, args ...interface{}) { 335 if l.logger.Core().Enabled(zapcore.WarnLevel) { 336 l.logger.Warn(getLogMsgf(format, args...)) 337 } 338 } 339 340 // Error logs to ERROR log. Arguments are handled in the manner of fmt.Print. 341 func (l *zapLog) Error(args ...interface{}) { 342 if l.logger.Core().Enabled(zapcore.ErrorLevel) { 343 l.logger.Error(getLogMsg(args...)) 344 } 345 } 346 347 // Errorf logs to ERROR log. Arguments are handled in the manner of fmt.Printf. 348 func (l *zapLog) Errorf(format string, args ...interface{}) { 349 if l.logger.Core().Enabled(zapcore.ErrorLevel) { 350 l.logger.Error(getLogMsgf(format, args...)) 351 } 352 } 353 354 // Fatal logs to FATAL log. Arguments are handled in the manner of fmt.Print. 355 func (l *zapLog) Fatal(args ...interface{}) { 356 if l.logger.Core().Enabled(zapcore.FatalLevel) { 357 l.logger.Fatal(getLogMsg(args...)) 358 } 359 } 360 361 // Fatalf logs to FATAL log. Arguments are handled in the manner of fmt.Printf. 362 func (l *zapLog) Fatalf(format string, args ...interface{}) { 363 if l.logger.Core().Enabled(zapcore.FatalLevel) { 364 l.logger.Fatal(getLogMsgf(format, args...)) 365 } 366 } 367 368 // Sync calls the zap logger's Sync method, and flushes any buffered log entries. 369 // Applications should take care to call Sync before exiting. 370 func (l *zapLog) Sync() error { 371 return l.logger.Sync() 372 } 373 374 // SetLevel sets output log level. 375 func (l *zapLog) SetLevel(output string, level Level) { 376 i, e := strconv.Atoi(output) 377 if e != nil { 378 return 379 } 380 if i < 0 || i >= len(l.levels) { 381 return 382 } 383 l.levels[i].SetLevel(levelToZapLevel[level]) 384 } 385 386 // GetLevel gets output log level. 387 func (l *zapLog) GetLevel(output string) Level { 388 i, e := strconv.Atoi(output) 389 if e != nil { 390 return LevelDebug 391 } 392 if i < 0 || i >= len(l.levels) { 393 return LevelDebug 394 } 395 return zapLevelToLevel[l.levels[i].Level()] 396 } 397 398 // CustomTimeFormat customize time format. 399 // Deprecated: Use https://pkg.go.dev/time#Time.Format instead. 400 func CustomTimeFormat(t time.Time, format string) string { 401 return t.Format(format) 402 } 403 404 // DefaultTimeFormat returns the default time format "2006-01-02 15:04:05.000". 405 // Deprecated: Use https://pkg.go.dev/time#Time.AppendFormat instead. 406 func DefaultTimeFormat(t time.Time) []byte { 407 return defaultTimeFormat(t) 408 }