本文主要研究一下golang的zap的NewExample
zap@v1.16.0/logger.go
func NewExample(options ...Option) *Logger { encoderCfg := zapcore.EncoderConfig{ MessageKey: "msg", LevelKey: "level", NameKey: "logger", EncodeLevel: zapcore.LowercaseLevelEncoder, EncodeTime: zapcore.ISO8601TimeEncoder, EncodeDuration: zapcore.StringDurationEncoder, } core := zapcore.NewCore(zapcore.NewJSONEncoder(encoderCfg), os.Stdout, DebugLevel) return New(core).WithOptions(options...) }
NewExample使用通过core来创建Logger,其中core使用的Encoder为JSONEncoder,WriteSyncer使用的是os.Stdout,LevelEnabler使用的是DebugLevel;使用的JSONEncoder的zapcore.EncoderConfig其EncodeLevel为zapcore.LowercaseLevelEncoder,其TimeEncoder为zapcore.ISO8601TimeEncoder,,其DurationEncoder为zapcore.StringDurationEncoder
zap@v1.16.0/zapcore/encoder.go
func LowercaseLevelEncoder(l Level, enc PrimitiveArrayEncoder) { enc.AppendString(l.String()) } func ISO8601TimeEncoder(t time.Time, enc PrimitiveArrayEncoder) { encodeTimeLayout(t, "2006-01-02T15:04:05.000Z0700", enc) } func StringDurationEncoder(d time.Duration, enc PrimitiveArrayEncoder) { enc.AppendString(d.String()) }
LowercaseLevelEncoder使用小写打印log level;ISO8601TimeEncoder使用2006-01-02T15:04:05.000Z0700
格式打印时间;StringDurationEncoder使用Duration内置的String()打印time.Duration
zap@v1.16.0/zapcore/json_encoder.go
func NewJSONEncoder(cfg EncoderConfig) Encoder { return newJSONEncoder(cfg, false) } func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder { return &jsonEncoder{ EncoderConfig: &cfg, buf: bufferpool.Get(), spaced: spaced, } } func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) { final := enc.clone() final.buf.AppendByte('{') if final.LevelKey != "" { final.addKey(final.LevelKey) cur := final.buf.Len() final.EncodeLevel(ent.Level, final) if cur == final.buf.Len() { // User-supplied EncodeLevel was a no-op. Fall back to strings to keep // output JSON valid. final.AppendString(ent.Level.String()) } } if final.TimeKey != "" { final.AddTime(final.TimeKey, ent.Time) } if ent.LoggerName != "" && final.NameKey != "" { final.addKey(final.NameKey) cur := final.buf.Len() nameEncoder := final.EncodeName // if no name encoder provided, fall back to FullNameEncoder for backwards // compatibility if nameEncoder == nil { nameEncoder = FullNameEncoder } nameEncoder(ent.LoggerName, final) if cur == final.buf.Len() { // User-supplied EncodeName was a no-op. Fall back to strings to // keep output JSON valid. final.AppendString(ent.LoggerName) } } if ent.Caller.Defined { if final.CallerKey != "" { final.addKey(final.CallerKey) cur := final.buf.Len() final.EncodeCaller(ent.Caller, final) if cur == final.buf.Len() { // User-supplied EncodeCaller was a no-op. Fall back to strings to // keep output JSON valid. final.AppendString(ent.Caller.String()) } } if final.FunctionKey != "" { final.addKey(final.FunctionKey) final.AppendString(ent.Caller.Function) } } if final.MessageKey != "" { final.addKey(enc.MessageKey) final.AppendString(ent.Message) } if enc.buf.Len() > 0 { final.addElementSeparator() final.buf.Write(enc.buf.Bytes()) } addFields(final, fields) final.closeOpenNamespaces() if ent.Stack != "" && final.StacktraceKey != "" { final.AddString(final.StacktraceKey, ent.Stack) } final.buf.AppendByte('}') if final.LineEnding != "" { final.buf.AppendString(final.LineEnding) } else { final.buf.AppendString(DefaultLineEnding) } ret := final.buf putJSONEncoder(final) return ret, nil }
NewJSONEncoder创建的是jsonEncoder;其EncodeEntry方法一次打印LevelKey、TimeKey、LoggerName、Caller,最后才是业务的message本身,然后结束json打印,对于有stacktrace还会以非json的形式(普通堆栈形式)打印stacktrace
func exampleDemo() { logger := zap.NewExample() defer logger.Sync() // flushes buffer, if any sugar := logger.Sugar() sugar.Info("this will be logged") sugar.Info("time=", time.Now()) sugar.Panic("test panic") }
输出
{"level":"info","msg":"this will be logged"} {"level":"info","msg":"time=2020-12-07 23:14:48.50402 +0800 CST m=+0.000602110"} {"level":"panic","msg":"test panic"} panic: test panic goroutine 1 [running]: go.uber.org/zap/zapcore.(*CheckedEntry).Write(0xc0001680c0, 0x0, 0x0, 0x0) /go/pkg/mod/go.uber.org/zap@v1.16.0/zapcore/entry.go:234 +0x585 go.uber.org/zap.(*SugaredLogger).log(0xc000179e98, 0xc000054e04, 0x0, 0x0, 0xc000179ea0, 0x1, 0x1, 0x0, 0x0, 0x0) /go/pkg/mod/go.uber.org/zap@v1.16.0/sugar.go:234 +0xf6 go.uber.org/zap.(*SugaredLogger).Panic(...) /go/pkg/mod/go.uber.org/zap@v1.16.0/sugar.go:123 main.exampleDemo() /zap_demo.go:19 +0x277 main.main() /zap_demo.go:10 +0x25 exit status 2
NewExample使用通过core来创建Logger,其中core使用的Encoder为JSONEncoder,WriteSyncer使用的是os.Stdout,LevelEnabler使用的是DebugLevel;NewJSONEncoder创建的是jsonEncoder;其EncodeEntry方法一次打印LevelKey、TimeKey、LoggerName、Caller,最后才是业务的message本身,然后结束json打印,对于有stacktrace还会以非json的形式(普通堆栈形式)打印stacktrace