前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊golang的zap的Core

聊聊golang的zap的Core

作者头像
code4it
发布2020-12-11 10:38:08
2820
发布2020-12-11 10:38:08
举报
文章被收录于专栏:码匠的流水账

本文主要研究一下golang的zap的Core

Core

zap@v1.16.0/zapcore/core.go

代码语言:javascript
复制
type Core interface {
    LevelEnabler

    // With adds structured context to the Core.
    With([]Field) Core
    // Check determines whether the supplied Entry should be logged (using the
    // embedded LevelEnabler and possibly some extra logic). If the entry
    // should be logged, the Core adds itself to the CheckedEntry and returns
    // the result.
    //
    // Callers must use Check before calling Write.
    Check(Entry, *CheckedEntry) *CheckedEntry
    // Write serializes the Entry and any Fields supplied at the log site and
    // writes them to their destination.
    //
    // If called, Write should always log the Entry and Fields; it should not
    // replicate the logic of Check.
    Write(Entry, []Field) error
    // Sync flushes buffered logs (if any).
    Sync() error
}

Core接口内嵌了LevelEnabler,定义了With、Check、Write、Sync方法

LevelEnabler

zap@v1.16.0/zapcore/level.go

代码语言:javascript
复制
type LevelEnabler interface {
    Enabled(Level) bool
}

LevelEnabler定义了Enabled方法

nopCore

zap@v1.16.0/zapcore/core.go

代码语言:javascript
复制
type nopCore struct{}

// NewNopCore returns a no-op Core.
func NewNopCore() Core                                        { return nopCore{} }
func (nopCore) Enabled(Level) bool                            { return false }
func (n nopCore) With([]Field) Core                           { return n }
func (nopCore) Check(_ Entry, ce *CheckedEntry) *CheckedEntry { return ce }
func (nopCore) Write(Entry, []Field) error                    { return nil }
func (nopCore) Sync() error                                   { return nil }

nopCore实现了Core接口,为空操作

ioCore

zap@v1.16.0/zapcore/core.go

代码语言:javascript
复制
type ioCore struct {
    LevelEnabler
    enc Encoder
    out WriteSyncer
}

func (c *ioCore) With(fields []Field) Core {
    clone := c.clone()
    addFields(clone.enc, fields)
    return clone
}

func (c *ioCore) Check(ent Entry, ce *CheckedEntry) *CheckedEntry {
    if c.Enabled(ent.Level) {
        return ce.AddCore(ent, c)
    }
    return ce
}

func (c *ioCore) Write(ent Entry, fields []Field) error {
    buf, err := c.enc.EncodeEntry(ent, fields)
    if err != nil {
        return err
    }
    _, err = c.out.Write(buf.Bytes())
    buf.Free()
    if err != nil {
        return err
    }
    if ent.Level > ErrorLevel {
        // Since we may be crashing the program, sync the output. Ignore Sync
        // errors, pending a clean solution to issue #370.
        c.Sync()
    }
    return nil
}

func (c *ioCore) Sync() error {
    return c.out.Sync()
}

func (c *ioCore) clone() *ioCore {
    return &ioCore{
        LevelEnabler: c.LevelEnabler,
        enc:          c.enc.Clone(),
        out:          c.out,
    }
}

ioCore内嵌了LevelEnabler,定义了Encoder、WriteSyncer(out)属性,实现了Core接口;其With方法执行的是clone以及addFields;Check方法先判断c.Enabled(ent.Level),若为true才执行ce.AddCore(ent, c);Write方法先通过encoder的EncodeEntry序列化entry,然后将bytes写入到WriteSyncer,若entry的level大于ErrorLevel的还会执行Sync方法;Sync方法执行out.Sync;clone方法则用原来core来重新一个新的ioCore

addFields

zap@v1.16.0/zapcore/field.go

代码语言:javascript
复制
func addFields(enc ObjectEncoder, fields []Field) {
    for i := range fields {
        fields[i].AddTo(enc)
    }
}

func (f Field) AddTo(enc ObjectEncoder) {
    var err error

    switch f.Type {
    case ArrayMarshalerType:
        err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
    case ObjectMarshalerType:
        err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
    case BinaryType:
        enc.AddBinary(f.Key, f.Interface.([]byte))
    case BoolType:
        enc.AddBool(f.Key, f.Integer == 1)
    case ByteStringType:
        enc.AddByteString(f.Key, f.Interface.([]byte))
    case Complex128Type:
        enc.AddComplex128(f.Key, f.Interface.(complex128))
    case Complex64Type:
        enc.AddComplex64(f.Key, f.Interface.(complex64))
    case DurationType:
        enc.AddDuration(f.Key, time.Duration(f.Integer))
    case Float64Type:
        enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
    case Float32Type:
        enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
    case Int64Type:
        enc.AddInt64(f.Key, f.Integer)
    case Int32Type:
        enc.AddInt32(f.Key, int32(f.Integer))
    case Int16Type:
        enc.AddInt16(f.Key, int16(f.Integer))
    case Int8Type:
        enc.AddInt8(f.Key, int8(f.Integer))
    case StringType:
        enc.AddString(f.Key, f.String)
    case TimeType:
        if f.Interface != nil {
            enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
        } else {
            // Fall back to UTC if location is nil.
            enc.AddTime(f.Key, time.Unix(0, f.Integer))
        }
    case TimeFullType:
        enc.AddTime(f.Key, f.Interface.(time.Time))
    case Uint64Type:
        enc.AddUint64(f.Key, uint64(f.Integer))
    case Uint32Type:
        enc.AddUint32(f.Key, uint32(f.Integer))
    case Uint16Type:
        enc.AddUint16(f.Key, uint16(f.Integer))
    case Uint8Type:
        enc.AddUint8(f.Key, uint8(f.Integer))
    case UintptrType:
        enc.AddUintptr(f.Key, uintptr(f.Integer))
    case ReflectType:
        err = enc.AddReflected(f.Key, f.Interface)
    case NamespaceType:
        enc.OpenNamespace(f.Key)
    case StringerType:
        err = encodeStringer(f.Key, f.Interface, enc)
    case ErrorType:
        encodeError(f.Key, f.Interface.(error), enc)
    case SkipType:
        break
    default:
        panic(fmt.Sprintf("unknown field type: %v", f))
    }

    if err != nil {
        enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
    }
}

addFields方法遍历fields,执行Field的AddTo方法;AddTo方法会根据f.Type来执行ObjectEncoder的对应方法

实例

代码语言:javascript
复制
func newCoreDemo() {
    temp, err := ioutil.TempFile("", "zapcore-test-iocore")
    if err != nil {
        panic(err)
    }
    fmt.Println(temp.Name())
    //defer os.Remove(temp.Name())

    cfg := zapcore.EncoderConfig{
        MessageKey:     "msg",
        LevelKey:       "level",
        NameKey:        "name",
        TimeKey:        "ts",
        CallerKey:      "caller",
        FunctionKey:    "func",
        StacktraceKey:  "stacktrace",
        LineEnding:     "\n",
        EncodeTime:     zapcore.EpochTimeEncoder,
        EncodeLevel:    zapcore.LowercaseLevelEncoder,
        EncodeDuration: zapcore.SecondsDurationEncoder,
        EncodeCaller:   zapcore.ShortCallerEncoder,
    }
    cfg.TimeKey = ""

    core := zapcore.NewCore(
        zapcore.NewJSONEncoder(cfg),
        temp,
        zapcore.InfoLevel,
    ).With([]zapcore.Field{zapcore.Field{Type: zapcore.Int64Type, Integer: int64(1), Key: "k"}})

    if ce := core.Check(zapcore.Entry{Level: zapcore.DebugLevel, Message: "debug"}, nil); ce != nil {
        ce.Write(zapcore.Field{Type: zapcore.Int64Type, Integer: int64(2), Key: "k"})
    }
    if ce := core.Check(zapcore.Entry{Level: zapcore.InfoLevel, Message: "info"}, nil); ce != nil {
        ce.Write(zapcore.Field{Type: zapcore.Int64Type, Integer: int64(3), Key: "k"})
    }
    if ce := core.Check(zapcore.Entry{Level: zapcore.WarnLevel, Message: "warn"}, nil); ce != nil {
        ce.Write(zapcore.Field{Type: zapcore.Int64Type, Integer: int64(4), Key: "k"})
    }

}

这里NewJSONEncoder使用指定的zapcore.EncoderConfig,zapcore.NewCore的out设置为temp文件,level级别为InfoLevel,因而只会输出level及以上的entry

输出

代码语言:javascript
复制
{"level":"info","msg":"info","k":1,"k":3}
{"level":"warn","msg":"warn","k":1,"k":4}

其中k为1的是withField全局指定的,然后k为2因为是debug级别所以没有输出出来

小结

Core接口内嵌了LevelEnabler,定义了With、Check、Write、Sync方法;它有nopCore及ioCore两种实现,ioCore内嵌了LevelEnabler,定义了Encoder、WriteSyncer(out)属性,其中encoder用来序列化entry为bytes,而WriteSyncer则用于写入bytes。

doc

  • zap
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-12-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Core
  • LevelEnabler
  • nopCore
  • ioCore
  • addFields
  • 实例
  • 小结
  • doc
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档