本文次要钻研一下golang的zap的NewExample

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

encoder

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

NewJSONEncoder

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 panicgoroutine 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 +0x585go.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 +0xf6go.uber.org/zap.(*SugaredLogger).Panic(...)        /go/pkg/mod/go.uber.org/zap@v1.16.0/sugar.go:123main.exampleDemo()        /zap_demo.go:19 +0x277main.main()        /zap_demo.go:10 +0x25exit 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

doc

  • zap