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

NewDevelopment

zap@v1.16.0/logger.go

func NewDevelopment(options ...Option) (*Logger, error) {    return NewDevelopmentConfig().Build(options...)}
NewDevelopment应用NewDevelopmentConfig进行build

NewDevelopmentConfig

zap@v1.16.0/config.go

func NewDevelopmentConfig() Config {    return Config{        Level:            NewAtomicLevelAt(DebugLevel),        Development:      true,        Encoding:         "console",        EncoderConfig:    NewDevelopmentEncoderConfig(),        OutputPaths:      []string{"stderr"},        ErrorOutputPaths: []string{"stderr"},    }}
NewDevelopmentConfig创立Config,其Level为NewAtomicLevelAt(DebugLevel),Development为true,Encoding为console,EncoderConfig为NewDevelopmentEncoderConfig,OutputPaths及ErrorOutputPaths均为stderr

NewDevelopmentEncoderConfig

zap@v1.16.0/config.go

func NewDevelopmentEncoderConfig() zapcore.EncoderConfig {    return zapcore.EncoderConfig{        // Keys can be anything except the empty string.        TimeKey:        "T",        LevelKey:       "L",        NameKey:        "N",        CallerKey:      "C",        FunctionKey:    zapcore.OmitKey,        MessageKey:     "M",        StacktraceKey:  "S",        LineEnding:     zapcore.DefaultLineEnding,        EncodeLevel:    zapcore.CapitalLevelEncoder,        EncodeTime:     zapcore.ISO8601TimeEncoder,        EncodeDuration: zapcore.StringDurationEncoder,        EncodeCaller:   zapcore.ShortCallerEncoder,    }}
NewDevelopmentEncoderConfig创立zapcore.EncoderConfig,其LineEnding为zapcore.DefaultLineEnding,EncodeLevel为zapcore.CapitalLevelEncoder,EncodeTime为zapcore.ISO8601TimeEncoder,EncodeDuration为zapcore.StringDurationEncoder,EncodeCaller为zapcore.ShortCallerEncoder

encoder

zap@v1.16.0/zapcore/encoder.go

const DefaultLineEnding = "\n"func CapitalLevelEncoder(l Level, enc PrimitiveArrayEncoder) {    enc.AppendString(l.CapitalString())}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())}func ShortCallerEncoder(caller EntryCaller, enc PrimitiveArrayEncoder) {    // TODO: consider using a byte-oriented API to save an allocation.    enc.AppendString(caller.TrimmedPath())}

encoder

zap@v1.16.0/encoder.go

var (    errNoEncoderNameSpecified = errors.New("no encoder name specified")    _encoderNameToConstructor = map[string]func(zapcore.EncoderConfig) (zapcore.Encoder, error){        "console": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {            return zapcore.NewConsoleEncoder(encoderConfig), nil        },        "json": func(encoderConfig zapcore.EncoderConfig) (zapcore.Encoder, error) {            return zapcore.NewJSONEncoder(encoderConfig), nil        },    }    _encoderMutex sync.RWMutex)
_encoderNameToConstructor内置了console、json两种encoder

NewConsoleEncoder

zap@v1.16.0/console_encoder.go

func NewConsoleEncoder(cfg EncoderConfig) Encoder {    if len(cfg.ConsoleSeparator) == 0 {        // Use a default delimiter of '\t' for backwards compatibility        cfg.ConsoleSeparator = "\t"    }    return consoleEncoder{newJSONEncoder(cfg, true)}}type consoleEncoder struct {    *jsonEncoder}func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {    line := bufferpool.Get()    // We don't want the entry's metadata to be quoted and escaped (if it's    // encoded as strings), which means that we can't use the JSON encoder. The    // simplest option is to use the memory encoder and fmt.Fprint.    //    // If this ever becomes a performance bottleneck, we can implement    // ArrayEncoder for our plain-text format.    arr := getSliceEncoder()    if c.TimeKey != "" && c.EncodeTime != nil {        c.EncodeTime(ent.Time, arr)    }    if c.LevelKey != "" && c.EncodeLevel != nil {        c.EncodeLevel(ent.Level, arr)    }    if ent.LoggerName != "" && c.NameKey != "" {        nameEncoder := c.EncodeName        if nameEncoder == nil {            // Fall back to FullNameEncoder for backward compatibility.            nameEncoder = FullNameEncoder        }        nameEncoder(ent.LoggerName, arr)    }    if ent.Caller.Defined {        if c.CallerKey != "" && c.EncodeCaller != nil {            c.EncodeCaller(ent.Caller, arr)        }        if c.FunctionKey != "" {            arr.AppendString(ent.Caller.Function)        }    }    for i := range arr.elems {        if i > 0 {            line.AppendString(c.ConsoleSeparator)        }        fmt.Fprint(line, arr.elems[i])    }    putSliceEncoder(arr)    // Add the message itself.    if c.MessageKey != "" {        c.addSeparatorIfNecessary(line)        line.AppendString(ent.Message)    }    // Add any structured context.    c.writeContext(line, fields)    // If there's no stacktrace key, honor that; this allows users to force    // single-line output.    if ent.Stack != "" && c.StacktraceKey != "" {        line.AppendByte('\n')        line.AppendString(ent.Stack)    }    if c.LineEnding != "" {        line.AppendString(c.LineEnding)    } else {        line.AppendString(DefaultLineEnding)    }    return line, nil}
consoleEncoder内嵌了*jsonEncoder,其EncodeEntry办法通过getSliceEncoder()获取`*sliceArrayEncoder,而后顺次往arr增加time、level、loggerName、caller,最初再增加业务的message自身,对于有stacktrace还会追加stacktrace

实例

func developmentDemo() {    logger, _ := zap.NewDevelopment()    defer logger.Sync() // flushes buffer, if any    sugar := logger.Sugar()    sugar.Info("this will be logged")    sugar.Panic("test panic")}

输入

2020-12-06T23:29:08.081+0800    INFO    log-demo/zap_demo.go:17 this will be logged2020-12-06T23:29:08.082+0800    PANIC   log-demo/zap_demo.go:18 test panicmain.developmentDemo        /zap_demo.go:18main.main        /zap_demo.go:10runtime.main        /usr/local/go/src/runtime/proc.go:204panic: test panicgoroutine 1 [running]:go.uber.org/zap/zapcore.(*CheckedEntry).Write(0xc0000f20c0, 0x0, 0x0, 0x0)        /go/pkg/mod/go.uber.org/zap@v1.16.0/zapcore/entry.go:234 +0x585go.uber.org/zap.(*SugaredLogger).log(0xc0000fbed0, 0x4, 0x0, 0x0, 0xc0000fbed8, 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.developmentDemo()        /zap_demo.go:18 +0x199main.main()        /zap_demo.go:10 +0x25exit status 2

小结

NewDevelopmentEncoderConfig创立zapcore.EncoderConfig,其LineEnding为zapcore.DefaultLineEnding,EncodeLevel为zapcore.CapitalLevelEncoder,EncodeTime为zapcore.ISO8601TimeEncoder,EncodeDuration为zapcore.StringDurationEncoder,EncodeCaller为zapcore.ShortCallerEncoder

doc

  • zap