共计 8701 个字符,预计需要花费 22 分钟才能阅读完成。
序
本文次要钻研一下 golang 的 zap 的 ReflectType
sweetenFields
zap@v1.16.0/sugar.go
func (s *SugaredLogger) sweetenFields(args []interface{}) []Field {if len(args) == 0 {return nil}
// Allocate enough space for the worst case; if users pass only structured
// fields, we shouldn't penalize them with extra allocations.
fields := make([]Field, 0, len(args))
var invalid invalidPairs
for i := 0; i < len(args); {
// This is a strongly-typed field. Consume it and move on.
if f, ok := args[i].(Field); ok {fields = append(fields, f)
i++
continue
}
// Make sure this element isn't a dangling key.
if i == len(args)-1 {s.base.DPanic(_oddNumberErrMsg, Any("ignored", args[i]))
break
}
// Consume this value and the next, treating them as a key-value pair. If the
// key isn't a string, add this pair to the slice of invalid pairs.
key, val := args[i], args[i+1]
if keyStr, ok := key.(string); !ok {
// Subsequent errors are likely, so allocate once up front.
if cap(invalid) == 0 {invalid = make(invalidPairs, 0, len(args)/2)
}
invalid = append(invalid, invalidPair{i, key, val})
} else {fields = append(fields, Any(keyStr, val))
}
i += 2
}
// If we encountered any invalid key-value pairs, log an error.
if len(invalid) > 0 {s.base.DPanic(_nonStringKeyErrMsg, Array("invalid", invalid))
}
return fields
}
sweetenFields 办法执行的是
fields = append(fields, Any(keyStr, val))
Any
zap@v1.16.0/field.go
func Any(key string, value interface{}) Field {switch val := value.(type) {
case zapcore.ObjectMarshaler:
return Object(key, val)
case zapcore.ArrayMarshaler:
return Array(key, val)
case bool:
return Bool(key, val)
case *bool:
return Boolp(key, val)
case []bool:
return Bools(key, val)
case complex128:
return Complex128(key, val)
case *complex128:
return Complex128p(key, val)
case []complex128:
return Complex128s(key, val)
case complex64:
return Complex64(key, val)
case *complex64:
return Complex64p(key, val)
case []complex64:
return Complex64s(key, val)
case float64:
return Float64(key, val)
case *float64:
return Float64p(key, val)
case []float64:
return Float64s(key, val)
case float32:
return Float32(key, val)
case *float32:
return Float32p(key, val)
case []float32:
return Float32s(key, val)
case int:
return Int(key, val)
case *int:
return Intp(key, val)
case []int:
return Ints(key, val)
case int64:
return Int64(key, val)
case *int64:
return Int64p(key, val)
case []int64:
return Int64s(key, val)
case int32:
return Int32(key, val)
case *int32:
return Int32p(key, val)
case []int32:
return Int32s(key, val)
case int16:
return Int16(key, val)
case *int16:
return Int16p(key, val)
case []int16:
return Int16s(key, val)
case int8:
return Int8(key, val)
case *int8:
return Int8p(key, val)
case []int8:
return Int8s(key, val)
case string:
return String(key, val)
case *string:
return Stringp(key, val)
case []string:
return Strings(key, val)
case uint:
return Uint(key, val)
case *uint:
return Uintp(key, val)
case []uint:
return Uints(key, val)
case uint64:
return Uint64(key, val)
case *uint64:
return Uint64p(key, val)
case []uint64:
return Uint64s(key, val)
case uint32:
return Uint32(key, val)
case *uint32:
return Uint32p(key, val)
case []uint32:
return Uint32s(key, val)
case uint16:
return Uint16(key, val)
case *uint16:
return Uint16p(key, val)
case []uint16:
return Uint16s(key, val)
case uint8:
return Uint8(key, val)
case *uint8:
return Uint8p(key, val)
case []byte:
return Binary(key, val)
case uintptr:
return Uintptr(key, val)
case *uintptr:
return Uintptrp(key, val)
case []uintptr:
return Uintptrs(key, val)
case time.Time:
return Time(key, val)
case *time.Time:
return Timep(key, val)
case []time.Time:
return Times(key, val)
case time.Duration:
return Duration(key, val)
case *time.Duration:
return Durationp(key, val)
case []time.Duration:
return Durations(key, val)
case error:
return NamedError(key, val)
case []error:
return Errors(key, val)
case fmt.Stringer:
return Stringer(key, val)
default:
return Reflect(key, val)
}
}
Any 办法会依据 value 的类型返回不同的 Field,如果 value 没有实现 zapcore.ObjectMarshaler、zapcore.ArrayMarshaler,也不是根底类型,则走的是默认的
Reflect(key, val)
Reflect
zap@v1.16.0/field.go
func Reflect(key string, val interface{}) Field {return Field{Key: key, Type: zapcore.ReflectType, Interface: val}
}
Reflect 创立的 Field 类型的 Type 为 zapcore.ReflectType
AddTo
zap@v1.16.0/zapcore/field.go
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())
}
}
AddTo 办法依据 Field 的类型做不同解决,如果是 ReflectType 类型,则执行的是 enc.AddReflected(f.Key, f.Interface)
AddReflected
zap@v1.16.0/zapcore/json_encoder.go
func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error {valueBytes, err := enc.encodeReflected(obj)
if err != nil {return err}
enc.addKey(key)
_, err = enc.buf.Write(valueBytes)
return err
}
func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) {
if obj == nil {return nullLiteralBytes, nil}
enc.resetReflectBuf()
if err := enc.reflectEnc.Encode(obj); err != nil {return nil, err}
enc.reflectBuf.TrimNewline()
return enc.reflectBuf.Bytes(), nil}
func (enc *jsonEncoder) resetReflectBuf() {
if enc.reflectBuf == nil {enc.reflectBuf = bufferpool.Get()
enc.reflectEnc = json.NewEncoder(enc.reflectBuf)
// For consistency with our custom JSON encoder.
enc.reflectEnc.SetEscapeHTML(false)
} else {enc.reflectBuf.Reset()
}
}
jsonEncoder 的 AddReflected 办法用 enc.encodeReflected(obj) 来序列化 value;encodeReflected 办法执行的是 enc.resetReflectBuf() 及 enc.reflectEnc.Encode(obj);resetReflectBuf 办法在 reflectBuf 为 nil 时创立 reflectBuf 及 json.NewEncoder(enc.reflectBuf),不为 nil 时执行 reflectBuf.Reset();enc.reflectEnc 用的是 golang 内置的 json encoder
json.Encode
/usr/local/go/src/encoding/json/stream.go
func NewEncoder(w io.Writer) *Encoder {return &Encoder{w: w, escapeHTML: true}
}
func (enc *Encoder) Encode(v interface{}) error {
if enc.err != nil {return enc.err}
e := newEncodeState()
err := e.marshal(v, encOpts{escapeHTML: enc.escapeHTML})
if err != nil {return err}
// Terminate each value with a newline.
// This makes the output look a little nicer
// when debugging, and some kind of space
// is required if the encoded value was a number,
// so that the reader knows there aren't more
// digits coming.
e.WriteByte('\n')
b := e.Bytes()
if enc.indentPrefix != ""|| enc.indentValue !="" {
if enc.indentBuf == nil {enc.indentBuf = new(bytes.Buffer)
}
enc.indentBuf.Reset()
err = Indent(enc.indentBuf, b, enc.indentPrefix, enc.indentValue)
if err != nil {return err}
b = enc.indentBuf.Bytes()}
if _, err = enc.w.Write(b); err != nil {enc.err = err}
encodeStatePool.Put(e)
return err
}
Encode 办法通过 encodeState 的 marshal 办法进行序列化,这里它读取了 enc.escapeHTML 选项
实例
type User struct {
Name string
Email string
CreatedAt time.Time
}
type Users []*User
func reflectTypeDemo() {logger, err := zap.NewProduction()
defer logger.Sync()
if err != nil {panic(err)
}
var user = &User{
Name: "hello1",
Email: "hello1@test.com",
CreatedAt: time.Date(2020, 12, 19, 8, 0, 0, 0, time.UTC),
}
var users Users
users = append(users, &User{
Name: "hello2",
Email: "hello2@test.com",
CreatedAt: time.Date(2020, 12, 19, 9, 0, 0, 0, time.UTC),
}, &User{
Name: "hello3",
Email: "hello3@test.com",
CreatedAt: time.Date(2020, 12, 20, 10, 0, 0, 0, time.UTC),
})
logger.Sugar().Infow("hello", "user", user, "users", users)
}
输入
{"level":"info","ts":1608350874.177944,"caller":"zap/zap_demo.go:42","msg":"hello","user":{"Name":"hello1","Email":"hello1@test.com","CreatedAt":"2020-12-19T08:00:00Z"},"users":[{"Name":"hello2","Email":"hello2@test.com","CreatedAt":"2020-12-19T09:00:00Z"},{"Name":"hello3","Email":"hello3@test.com","CreatedAt":"2020-12-20T10:00:00Z"}]}
小结
zap 的 sugar 提供 Infow 办法,它通过 sweetenFields 办法来将 key,value 封装为 Field;sweetenFields 办法应用的是 Any 办法,它会依据 value 的类型返回不同的 Field,如果 value 没有实现 zapcore.ObjectMarshaler、zapcore.ArrayMarshaler,也不是根底类型,则走的是默认的 Reflect(key, val)
;AddTo 办法依据 Field 的类型做不同解决,如果是 ReflectType 类型,则执行的是 enc.AddReflected(f.Key, f.Interface);jsonEncoder 的 AddReflected 办法应用 golang 内置的 json.Encoder 来序列化。
doc
- zap