本文次要钻研一下zerolog的encoder

encoder

github.com/rs/zerolog@v1.20.0/encoder.go

type encoder interface {    AppendArrayDelim(dst []byte) []byte    AppendArrayEnd(dst []byte) []byte    AppendArrayStart(dst []byte) []byte    AppendBeginMarker(dst []byte) []byte    AppendBool(dst []byte, val bool) []byte    AppendBools(dst []byte, vals []bool) []byte    AppendBytes(dst, s []byte) []byte    AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte    AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte    AppendEndMarker(dst []byte) []byte    AppendFloat32(dst []byte, val float32) []byte    AppendFloat64(dst []byte, val float64) []byte    AppendFloats32(dst []byte, vals []float32) []byte    AppendFloats64(dst []byte, vals []float64) []byte    AppendHex(dst, s []byte) []byte    AppendIPAddr(dst []byte, ip net.IP) []byte    AppendIPPrefix(dst []byte, pfx net.IPNet) []byte    AppendInt(dst []byte, val int) []byte    AppendInt16(dst []byte, val int16) []byte    AppendInt32(dst []byte, val int32) []byte    AppendInt64(dst []byte, val int64) []byte    AppendInt8(dst []byte, val int8) []byte    AppendInterface(dst []byte, i interface{}) []byte    AppendInts(dst []byte, vals []int) []byte    AppendInts16(dst []byte, vals []int16) []byte    AppendInts32(dst []byte, vals []int32) []byte    AppendInts64(dst []byte, vals []int64) []byte    AppendInts8(dst []byte, vals []int8) []byte    AppendKey(dst []byte, key string) []byte    AppendLineBreak(dst []byte) []byte    AppendMACAddr(dst []byte, ha net.HardwareAddr) []byte    AppendNil(dst []byte) []byte    AppendObjectData(dst []byte, o []byte) []byte    AppendString(dst []byte, s string) []byte    AppendStrings(dst []byte, vals []string) []byte    AppendTime(dst []byte, t time.Time, format string) []byte    AppendTimes(dst []byte, vals []time.Time, format string) []byte    AppendUint(dst []byte, val uint) []byte    AppendUint16(dst []byte, val uint16) []byte    AppendUint32(dst []byte, val uint32) []byte    AppendUint64(dst []byte, val uint64) []byte    AppendUint8(dst []byte, val uint8) []byte    AppendUints(dst []byte, vals []uint) []byte    AppendUints16(dst []byte, vals []uint16) []byte    AppendUints32(dst []byte, vals []uint32) []byte    AppendUints64(dst []byte, vals []uint64) []byte    AppendUints8(dst []byte, vals []uint8) []byte}
encoder接口定义了一系列的Append办法

AppendMarker

github.com/rs/zerolog@v1.20.0/internal/json/types.go

// AppendBeginMarker inserts a map start into the dst byte array.func (Encoder) AppendBeginMarker(dst []byte) []byte {    return append(dst, '{')}// AppendEndMarker inserts a map end into the dst byte array.func (Encoder) AppendEndMarker(dst []byte) []byte {    return append(dst, '}')}
AppendBeginMarker及AppendEndMarker用于追加map start和end

AppendArray

github.com/rs/zerolog@v1.20.0/internal/json/types.go

// AppendArrayStart adds markers to indicate the start of an array.func (Encoder) AppendArrayStart(dst []byte) []byte {    return append(dst, '[')}// AppendArrayEnd adds markers to indicate the end of an array.func (Encoder) AppendArrayEnd(dst []byte) []byte {    return append(dst, ']')}
AppendArrayStart及AppendArrayEnd用于追加array start和end

AppendLineBreak

github.com/rs/zerolog@v1.20.0/internal/json/types.go

// AppendLineBreak appends a line break.func (Encoder) AppendLineBreak(dst []byte) []byte {    return append(dst, '\n')}
AppendLineBreak用于追加换行符

AppendInterface

github.com/rs/zerolog@v1.20.0/internal/json/types.go

// AppendInterface marshals the input interface to a string and// appends the encoded string to the input byte slice.func (e Encoder) AppendInterface(dst []byte, i interface{}) []byte {    marshaled, err := json.Marshal(i)    if err != nil {        return e.AppendString(dst, fmt.Sprintf("marshaling error: %v", err))    }    return append(dst, marshaled...)}
AppendInterface办法应用json来序列化interface

AppendObjectData

github.com/rs/zerolog@v1.20.0/internal/json/types.go

// AppendObjectData takes in an object that is already in a byte array// and adds it to the dst.func (Encoder) AppendObjectData(dst []byte, o []byte) []byte {    // Three conditions apply here:    // 1. new content starts with '{' - which should be dropped   OR    // 2. new content starts with '{' - which should be replaced with ','    //    to separate with existing content OR    // 3. existing content has already other fields    if o[0] == '{' {        if len(dst) > 1 {            dst = append(dst, ',')        }        o = o[1:]    } else if len(dst) > 1 {        dst = append(dst, ',')    }    return append(dst, o...)}
AppendObjectData用于追加byte数组

Context

github.com/rs/zerolog@v1.20.0/context.go

// Context configures a new sub-logger with contextual fields.type Context struct {    l Logger}// Logger returns the logger with the context previously set.func (c Context) Logger() Logger {    return c.l}func (c Context) Array(key string, arr LogArrayMarshaler) Context {    c.l.context = enc.AppendKey(c.l.context, key)    if arr, ok := arr.(*Array); ok {        c.l.context = arr.write(c.l.context)        return c    }    var a *Array    if aa, ok := arr.(*Array); ok {        a = aa    } else {        a = Arr()        arr.MarshalZerologArray(a)    }    c.l.context = a.write(c.l.context)    return c}// Object marshals an object that implement the LogObjectMarshaler interface.func (c Context) Object(key string, obj LogObjectMarshaler) Context {    e := newEvent(levelWriterAdapter{ioutil.Discard}, 0)    e.Object(key, obj)    c.l.context = enc.AppendObjectData(c.l.context, e.buf)    putEvent(e)    return c}// EmbedObject marshals and Embeds an object that implement the LogObjectMarshaler interface.func (c Context) EmbedObject(obj LogObjectMarshaler) Context {    e := newEvent(levelWriterAdapter{ioutil.Discard}, 0)    e.EmbedObject(obj)    c.l.context = enc.AppendObjectData(c.l.context, e.buf)    putEvent(e)    return c}func (c Context) RawJSON(key string, b []byte) Context {    c.l.context = appendJSON(enc.AppendKey(c.l.context, key), b)    return c}// Interface adds the field key with obj marshaled using reflection.func (c Context) Interface(key string, i interface{}) Context {    c.l.context = enc.AppendInterface(enc.AppendKey(c.l.context, key), i)    return c}
Context提供了各种类型的办法,其外头执行的是encoder的对应类型的Append办法

With

github.com/rs/zerolog@v1.20.0/log.go

type Logger struct {    w       LevelWriter    level   Level    sampler Sampler    context []byte    hooks   []Hook}// With creates a child logger with the field added to its context.func (l Logger) With() Context {    context := l.context    l.context = make([]byte, 0, 500)    if context != nil {        l.context = append(l.context, context...)    } else {        // This is needed for AppendKey to not check len of input        // thus making it inlinable        l.context = enc.AppendBeginMarker(l.context)    }    return Context{l}}
With办法创立一个新的Context,包装了以后的logger;logger的context属性为byte数组;Context提供的各种类型的Append办法最初都作为byte数组追加到logger的context属性中

newEvent

github.com/rs/zerolog@v1.20.0/log.go

func (l *Logger) newEvent(level Level, done func(string)) *Event {    enabled := l.should(level)    if !enabled {        return nil    }    e := newEvent(l.w, level)    e.done = done    e.ch = l.hooks    if level != NoLevel {        e.Str(LevelFieldName, LevelFieldMarshalFunc(level))    }    if l.context != nil && len(l.context) > 1 {        e.buf = enc.AppendObjectData(e.buf, l.context)    }    return e}
newEvent办法会将logger的context属性通过encoder的AppendObjectData办法拷贝到event的buf中

实例

func withDemo() {    logger := zerolog.New(os.Stderr).With().Timestamp().Str("key", "value").Logger()    logger.Info().Str("k1", "v1").Msg("hello world")    logger.Info().Str("k2", "v2").Msg("hello world")}

输入

{"level":"info","key":"value","k1":"v1","time":"2021-01-04T23:45:10+08:00","message":"hello world"}{"level":"info","key":"value","k2":"v2","time":"2021-01-04T23:45:10+08:00","message":"hello world"}

小结

encoder接口定义了一系列的Append办法;Context提供了各种类型的办法,其外头执行的是encoder的对应类型的Append办法;With办法创立一个新的Context,包装了以后的logger;logger的context属性为byte数组;Context提供的各种类型的Append办法最初都作为byte数组追加到logger的context属性中;newEvent办法会将logger的context属性通过encoder的AppendObjectData办法拷贝到event的buf中。

doc

  • zerolog