乐趣区

关于golang:聊聊golang的zap的NewExample

本文次要钻研一下 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

  • zap
退出移动版