本文主要研究一下golang的zap的Core
zap@v1.16.0/zapcore/core.go
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方法
zap@v1.16.0/zapcore/level.go
type LevelEnabler interface { Enabled(Level) bool }
LevelEnabler定义了Enabled方法
zap@v1.16.0/zapcore/core.go
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接口,为空操作
zap@v1.16.0/zapcore/core.go
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
zap@v1.16.0/zapcore/field.go
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的对应方法
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
输出
{"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。