共计 6869 个字符,预计需要花费 18 分钟才能阅读完成。
序
本文次要钻研一下 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