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

Entry

zap@v1.16.0/zapcore/entry.go

type Entry struct {    Level      Level    Time       time.Time    LoggerName string    Message    string    Caller     EntryCaller    Stack      string}
Entry定义了Level、Time、LoggerName、Message、Caller、Stack属性

CheckedEntry

zap@v1.16.0/zapcore/entry.go

type CheckedEntry struct {    Entry    ErrorOutput WriteSyncer    dirty       bool // best-effort detection of pool misuse    should      CheckWriteAction    cores       []Core}
CheckedEntry内嵌了Entry,定义了ErrorOutput、dirty、CheckWriteAction、cores属性

reset

zap@v1.16.0/zapcore/entry.go

func (ce *CheckedEntry) reset() {    ce.Entry = Entry{}    ce.ErrorOutput = nil    ce.dirty = false    ce.should = WriteThenNoop    for i := range ce.cores {        // don't keep references to cores        ce.cores[i] = nil    }    ce.cores = ce.cores[:0]}
reset会重置CheckedEntry的Entry、ErrorOutput、dirty、CheckWriteAction、cores属性

Write

zap@v1.16.0/zapcore/entry.go

func (ce *CheckedEntry) Write(fields ...Field) {    if ce == nil {        return    }    if ce.dirty {        if ce.ErrorOutput != nil {            // Make a best effort to detect unsafe re-use of this CheckedEntry.            // If the entry is dirty, log an internal error; because the            // CheckedEntry is being used after it was returned to the pool,            // the message may be an amalgamation from multiple call sites.            fmt.Fprintf(ce.ErrorOutput, "%v Unsafe CheckedEntry re-use near Entry %+v.\n", time.Now(), ce.Entry)            ce.ErrorOutput.Sync()        }        return    }    ce.dirty = true    var err error    for i := range ce.cores {        err = multierr.Append(err, ce.cores[i].Write(ce.Entry, fields))    }    if ce.ErrorOutput != nil {        if err != nil {            fmt.Fprintf(ce.ErrorOutput, "%v write error: %v\n", time.Now(), err)            ce.ErrorOutput.Sync()        }    }    should, msg := ce.should, ce.Message    putCheckedEntry(ce)    switch should {    case WriteThenPanic:        panic(msg)    case WriteThenFatal:        exit.Exit()    case WriteThenGoexit:        runtime.Goexit()    }}
Write办法先判断CheckedEntry是否是dirty,如果是则示意该entry复用出问题了,就往ErrorOutput输入错误信息,而后返回;不是dirty的话,就先标注为dirty,而后遍历cores挨个执行core的Write办法,并用multierr来记录谬误,如果呈现err且ErrorOutput不为nil则往ErrorOutput输入err信息;之后执行putCheckedEntry放入_cePool中,最初依据CheckWriteAction来执行对应的操作

AddCore

zap@v1.16.0/zapcore/entry.go

func (ce *CheckedEntry) AddCore(ent Entry, core Core) *CheckedEntry {    if ce == nil {        ce = getCheckedEntry()        ce.Entry = ent    }    ce.cores = append(ce.cores, core)    return ce}
AddCore往CheckedEntry的cores增加core,相当于多增加一个输入

Should

zap@v1.16.0/zapcore/entry.go

func (ce *CheckedEntry) Should(ent Entry, should CheckWriteAction) *CheckedEntry {    if ce == nil {        ce = getCheckedEntry()        ce.Entry = ent    }    ce.should = should    return ce}
Should用于更新CheckedEntry的CheckWriteAction

_cePool

zap@v1.16.0/zapcore/entry.go

var (    _cePool = sync.Pool{New: func() interface{} {        // Pre-allocate some space for cores.        return &CheckedEntry{            cores: make([]Core, 4),        }    }})func getCheckedEntry() *CheckedEntry {    ce := _cePool.Get().(*CheckedEntry)    ce.reset()    return ce}func putCheckedEntry(ce *CheckedEntry) {    if ce == nil {        return    }    _cePool.Put(ce)}
_cePool为CheckedEntry的Pool,其New函数创立cores长度为4的CheckedEntry;其getCheckedEntry办法从_cePool取出一个CheckedEntry,而后执行reset,再返回;其putCheckedEntry办法将CheckedEntry偿还到_cePool中

实例

func checkedEntryDemo() {    entry := zapcore.Entry{        Level:      zapcore.InfoLevel,        Time:       time.Now(),        LoggerName: "demoLogger",        Message:    "hello world",        Caller:     zapcore.NewEntryCaller(100, "/path/to/foo.go", 42, false),        Stack:      "this is stack",    }    ce := &zapcore.CheckedEntry{        Entry:       entry,        ErrorOutput: zapcore.Lock(os.Stderr),    }    buf := &bytes.Buffer{}    core := zapcore.NewCore(zapcore.NewJSONEncoder(zap.NewProductionEncoderConfig()), zapcore.AddSync(buf), zap.InfoLevel)    ce.AddCore(entry, core)    ce.Write()    fmt.Print(buf)}

输入

{"level":"info","ts":1608133564.1996229,"logger":"demoLogger","msg":"hello world","stacktrace":"this is stack"}

小结

CheckedEntry内嵌了Entry,定义了ErrorOutput、dirty、CheckWriteAction、cores属性;entry包应用_cePool来获取和偿还CheckedEntry;CheckedEntry提供了AddCore办法往CheckedEntry的cores增加core,其Write会遍历cores挨个执行core的Write办法,其reset办法用于在从pool中取出CheckedEntry时重置其属性。

doc

  • zap