5

聊聊golang的zap的ReflectType

 3 years ago
source link: https://studygolang.com/articles/32249
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

sweetenFields

[email protected]/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))

[email protected]/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

[email protected]/field.go

func Reflect(key string, val interface{}) Field {
    return Field{Key: key, Type: zapcore.ReflectType, Interface: val}
}

Reflect创建的Field类型的Type为zapcore.ReflectType

AddTo

[email protected]/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

[email protected]/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:     "[email protected]",
        CreatedAt: time.Date(2020, 12, 19, 8, 0, 0, 0, time.UTC),
    }
    var users Users
    users = append(users, &User{
        Name:      "hello2",
        Email:     "[email protected]",
        CreatedAt: time.Date(2020, 12, 19, 9, 0, 0, 0, time.UTC),
    }, &User{
        Name:      "hello3",
        Email:     "[email protected]",
        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":"[email protected]","CreatedAt":"2020-12-19T08:00:00Z"},"users":[{"Name":"hello2","Email":"[email protected]","CreatedAt":"2020-12-19T09:00:00Z"},{"Name":"hello3","Email":"[email protected]","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来序列化。


有疑问加站长微信联系(非本文作者)

280

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK