美文网首页
聊聊golang的zap的NewExample

聊聊golang的zap的NewExample

作者: go4it | 来源:发表于2020-12-07 23:26 被阅读0次

    本文主要研究一下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 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

    doc

    相关文章

      网友评论

          本文标题:聊聊golang的zap的NewExample

          本文链接:https://www.haomeiwen.com/subject/wsbxgktx.html