美文网首页
聊聊golang的zap的CheckedEntry

聊聊golang的zap的CheckedEntry

作者: go4it | 来源:发表于2020-12-16 23:52 被阅读0次

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

    相关文章

      网友评论

          本文标题:聊聊golang的zap的CheckedEntry

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