Preface
This article mainly studies the SugaredLogger of golang’s zap
SugaredLogger
zap@v1.16.0/sugar.go
type SugaredLogger struct { base *Logger } func (s *SugaredLogger) Named(name string) *SugaredLogger { return &SugaredLogger{base: s.base.Named(name)} } func (s *SugaredLogger) With(args ...interface{}) *SugaredLogger { return &SugaredLogger{base: s.base.With(s.sweetenFields(args)...)} } func (s *SugaredLogger) Debug(args ...interface{}) { s.log(DebugLevel, "", args, nil) } func (s *SugaredLogger) Info(args ...interface{}) { s.log(InfoLevel, "", args, nil) } func (s *SugaredLogger) Warn(args ...interface{}) { s.log(WarnLevel, "", args, nil) } func (s *SugaredLogger) Error(args ...interface{}) { s.log(ErrorLevel, "", args, nil) } func (s *SugaredLogger) DPanic(args ...interface{}) { s.log(DPanicLevel, "", args, nil) } func (s *SugaredLogger) Panic(args ...interface{}) { s.log(PanicLevel, "", args, nil) } func (s *SugaredLogger) Fatal(args ...interface{}) { s.log(FatalLevel, "", args, nil) } func (s *SugaredLogger) Debugf(template string, args ...interface{}) { s.log(DebugLevel, template, args, nil) } func (s *SugaredLogger) Infof(template string, args ...interface{}) { s.log(InfoLevel, template, args, nil) } func (s *SugaredLogger) Warnf(template string, args ...interface{}) { s.log(WarnLevel, template, args, nil) } func (s *SugaredLogger) Errorf(template string, args ...interface{}) { s.log(ErrorLevel, template, args, nil) } func (s *SugaredLogger) DPanicf(template string, args ...interface{}) { s.log(DPanicLevel, template, args, nil) } func (s *SugaredLogger) Panicf(template string, args ...interface{}) { s.log(PanicLevel, template, args, nil) } func (s *SugaredLogger) Fatalf(template string, args ...interface{}) { s.log(FatalLevel, template, args, nil) } func (s *SugaredLogger) Debugw(msg string, keysAndValues ...interface{}) { s.log(DebugLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) Infow(msg string, keysAndValues ...interface{}) { s.log(InfoLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) Warnw(msg string, keysAndValues ...interface{}) { s.log(WarnLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) Errorw(msg string, keysAndValues ...interface{}) { s.log(ErrorLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) DPanicw(msg string, keysAndValues ...interface{}) { s.log(DPanicLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) Panicw(msg string, keysAndValues ...interface{}) { s.log(PanicLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) Fatalw(msg string, keysAndValues ...interface{}) { s.log(FatalLevel, msg, nil, keysAndValues) } func (s *SugaredLogger) Sync() error { return s.base.Sync() }
Copy after login
SugaredLogger provides debug, info, warn, error, panic, dpanic, fatal methods (Use the default format of fmt.Sprint
), and also supports format with f, with The w method supports the with key-value pair
level
zap@v1.16.0/level.go
const ( // DebugLevel logs are typically voluminous, and are usually disabled in // production. DebugLevel = zapcore.DebugLevel // InfoLevel is the default logging priority. InfoLevel = zapcore.InfoLevel // WarnLevel logs are more important than Info, but don't need inpidual // human review. WarnLevel = zapcore.WarnLevel // ErrorLevel logs are high-priority. If an application is running smoothly, // it shouldn't generate any error-level logs. ErrorLevel = zapcore.ErrorLevel // DPanicLevel logs are particularly important errors. In development the // logger panics after writing the message. DPanicLevel = zapcore.DPanicLevel // PanicLevel logs a message, then panics. PanicLevel = zapcore.PanicLevel // FatalLevel logs a message, then calls os.Exit(1). FatalLevel = zapcore.FatalLevel )
Copy after login
The levels inside zap are divided into debug, info, warn, error, dpanic, panic, fatal
DPanic
DPanic stands for "panic in development." In development, it logs at PanicLevel; otherwise, it logs at ErrorLevel. DPanic makes it easier to catch errors that are theoretically possible, but shouldn't actually happen, without crashing in production.
DPanic in development
func dpanicInDevelopment() { logger, _ := zap.NewDevelopment() defer logger.Sync() // flushes buffer, if any sugar := logger.Sugar() sugar.DPanic("test dpanic") sugar.Info("this will not be logged") }
Copy after login
The effect of DPanic in development is similar to the panic effect. The final info will not be output
DPanic in production
func dpanicInProduction() { logger, _ := zap.NewProduction() defer logger.Sync() // flushes buffer, if any sugar := logger.Sugar() sugar.DPanic("test dpanic logged as error in not development mode") sugar.Info("this will be logged") }
Copy after login
DPanic degenerates into error mode under non-development conditions, and the final info will still be output, which is safer in production.
logger.check
zap@v1.16.0/logger.go
func (log *Logger) check(lvl zapcore.Level, msg string) *zapcore.CheckedEntry { // check must always be called directly by a method in the Logger interface // (e.g., Check, Info, Fatal). const callerSkipOffset = 2 // Check the level first to reduce the cost of disabled log calls. // Since Panic and higher may exit, we skip the optimization for those levels. if lvl < zapcore.DPanicLevel && !log.core.Enabled(lvl) { return nil } // Create basic checked entry thru the core; this will be non-nil if the // log message will actually be written somewhere. ent := zapcore.Entry{ LoggerName: log.name, Time: time.Now(), Level: lvl, Message: msg, } ce := log.core.Check(ent, nil) willWrite := ce != nil // Set up any required terminal behavior. switch ent.Level { case zapcore.PanicLevel: ce = ce.Should(ent, zapcore.WriteThenPanic) case zapcore.FatalLevel: onFatal := log.onFatal // Noop is the default value for CheckWriteAction, and it leads to // continued execution after a Fatal which is unexpected. if onFatal == zapcore.WriteThenNoop { onFatal = zapcore.WriteThenFatal } ce = ce.Should(ent, onFatal) case zapcore.DPanicLevel: if log.development { ce = ce.Should(ent, zapcore.WriteThenPanic) } } // Only do further annotation if we're going to write this message; checked // entries that exist only for terminal behavior don't benefit from // annotation. if !willWrite { return ce } // Thread the error output through to the CheckedEntry. ce.ErrorOutput = log.errorOutput if log.addCaller { frame, defined := getCallerFrame(log.callerSkip + callerSkipOffset) if !defined { fmt.Fprintf(log.errorOutput, "%v Logger.check error: failed to get caller\n", time.Now().UTC()) log.errorOutput.Sync() } ce.Entry.Caller = zapcore.EntryCaller{ Defined: defined, PC: frame.PC, File: frame.File, Line: frame.Line, Function: frame.Function, } } if log.addStack.Enabled(ce.Entry.Level) { ce.Entry.Stack = StackSkip("", log.callerSkip+callerSkipOffset).String } return ce }
Copy after login
The logger.check method will determine the lvl. If it is zapcore.DPanicLevel, it will further determine whether It is development mode. If it is, it will be set ce.Should(ent, zapcore.WriteThenPanic)
Summary
- zap internal levels are divided into debug, info, warn, error, dpanic, panic, fatal
- SugaredLogger provides debug, info, warn, error, panic, dpanic, fatal methods (
Use the default format of fmt.Sprint
), in addition, the method with f supports format, and the method with w supports with key-value pair - The effect of DPanic under development is similar to the panic effect, and it degenerates into error mode under non-development