序
本文主要研究一下golang的zap的Core
Core
[email protected]/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方法
LevelEnabler
[email protected]/zapcore/level.go
type LevelEnabler interface {
Enabled(Level) bool
}
LevelEnabler定义了Enabled方法
nopCore
[email protected]/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接口,为空操作
ioCore
[email protected]/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
addFields
[email protected]/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。