乐趣区

关于golang:聊聊golang的zap的CheckedEntry

本文次要钻研一下 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
退出移动版