美文网首页
聊聊zerolog的encoder

聊聊zerolog的encoder

作者: go4it | 来源:发表于2021-01-04 23:49 被阅读0次

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

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