github.com/Laisky/zap@v1.27.0/zapcore/field.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package zapcore 22 23 import ( 24 "bytes" 25 "fmt" 26 "math" 27 "reflect" 28 "time" 29 ) 30 31 // A FieldType indicates which member of the Field union struct should be used 32 // and how it should be serialized. 33 type FieldType uint8 34 35 const ( 36 // UnknownType is the default field type. Attempting to add it to an encoder will panic. 37 UnknownType FieldType = iota 38 // ArrayMarshalerType indicates that the field carries an ArrayMarshaler. 39 ArrayMarshalerType 40 // ObjectMarshalerType indicates that the field carries an ObjectMarshaler. 41 ObjectMarshalerType 42 // BinaryType indicates that the field carries an opaque binary blob. 43 BinaryType 44 // BoolType indicates that the field carries a bool. 45 BoolType 46 // ByteStringType indicates that the field carries UTF-8 encoded bytes. 47 ByteStringType 48 // Complex128Type indicates that the field carries a complex128. 49 Complex128Type 50 // Complex64Type indicates that the field carries a complex64. 51 Complex64Type 52 // DurationType indicates that the field carries a time.Duration. 53 DurationType 54 // Float64Type indicates that the field carries a float64. 55 Float64Type 56 // Float32Type indicates that the field carries a float32. 57 Float32Type 58 // Int64Type indicates that the field carries an int64. 59 Int64Type 60 // Int32Type indicates that the field carries an int32. 61 Int32Type 62 // Int16Type indicates that the field carries an int16. 63 Int16Type 64 // Int8Type indicates that the field carries an int8. 65 Int8Type 66 // StringType indicates that the field carries a string. 67 StringType 68 // TimeType indicates that the field carries a time.Time that is 69 // representable by a UnixNano() stored as an int64. 70 TimeType 71 // TimeFullType indicates that the field carries a time.Time stored as-is. 72 TimeFullType 73 // Uint64Type indicates that the field carries a uint64. 74 Uint64Type 75 // Uint32Type indicates that the field carries a uint32. 76 Uint32Type 77 // Uint16Type indicates that the field carries a uint16. 78 Uint16Type 79 // Uint8Type indicates that the field carries a uint8. 80 Uint8Type 81 // UintptrType indicates that the field carries a uintptr. 82 UintptrType 83 // ReflectType indicates that the field carries an interface{}, which should 84 // be serialized using reflection. 85 ReflectType 86 // NamespaceType signals the beginning of an isolated namespace. All 87 // subsequent fields should be added to the new namespace. 88 NamespaceType 89 // StringerType indicates that the field carries a fmt.Stringer. 90 StringerType 91 // ErrorType indicates that the field carries an error. 92 ErrorType 93 // SkipType indicates that the field is a no-op. 94 SkipType 95 96 // InlineMarshalerType indicates that the field carries an ObjectMarshaler 97 // that should be inlined. 98 InlineMarshalerType 99 ) 100 101 // A Field is a marshaling operation used to add a key-value pair to a logger's 102 // context. Most fields are lazily marshaled, so it's inexpensive to add fields 103 // to disabled debug-level log statements. 104 type Field struct { 105 Key string 106 Type FieldType 107 Integer int64 108 String string 109 Interface interface{} 110 } 111 112 // AddTo exports a field through the ObjectEncoder interface. It's primarily 113 // useful to library authors, and shouldn't be necessary in most applications. 114 func (f Field) AddTo(enc ObjectEncoder) { 115 var err error 116 117 switch f.Type { 118 case ArrayMarshalerType: 119 err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler)) 120 case ObjectMarshalerType: 121 err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler)) 122 case InlineMarshalerType: 123 err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc) 124 case BinaryType: 125 enc.AddBinary(f.Key, f.Interface.([]byte)) 126 case BoolType: 127 enc.AddBool(f.Key, f.Integer == 1) 128 case ByteStringType: 129 enc.AddByteString(f.Key, f.Interface.([]byte)) 130 case Complex128Type: 131 enc.AddComplex128(f.Key, f.Interface.(complex128)) 132 case Complex64Type: 133 enc.AddComplex64(f.Key, f.Interface.(complex64)) 134 case DurationType: 135 enc.AddDuration(f.Key, time.Duration(f.Integer)) 136 case Float64Type: 137 enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer))) 138 case Float32Type: 139 enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer))) 140 case Int64Type: 141 enc.AddInt64(f.Key, f.Integer) 142 case Int32Type: 143 enc.AddInt32(f.Key, int32(f.Integer)) 144 case Int16Type: 145 enc.AddInt16(f.Key, int16(f.Integer)) 146 case Int8Type: 147 enc.AddInt8(f.Key, int8(f.Integer)) 148 case StringType: 149 enc.AddString(f.Key, f.String) 150 case TimeType: 151 if f.Interface != nil { 152 enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location))) 153 } else { 154 // Fall back to UTC if location is nil. 155 enc.AddTime(f.Key, time.Unix(0, f.Integer)) 156 } 157 case TimeFullType: 158 enc.AddTime(f.Key, f.Interface.(time.Time)) 159 case Uint64Type: 160 enc.AddUint64(f.Key, uint64(f.Integer)) 161 case Uint32Type: 162 enc.AddUint32(f.Key, uint32(f.Integer)) 163 case Uint16Type: 164 enc.AddUint16(f.Key, uint16(f.Integer)) 165 case Uint8Type: 166 enc.AddUint8(f.Key, uint8(f.Integer)) 167 case UintptrType: 168 enc.AddUintptr(f.Key, uintptr(f.Integer)) 169 case ReflectType: 170 err = enc.AddReflected(f.Key, f.Interface) 171 case NamespaceType: 172 enc.OpenNamespace(f.Key) 173 case StringerType: 174 err = encodeStringer(f.Key, f.Interface, enc) 175 case ErrorType: 176 err = encodeError(f.Key, f.Interface.(error), enc) 177 case SkipType: 178 break 179 default: 180 panic(fmt.Sprintf("unknown field type: %v", f)) 181 } 182 183 if err != nil { 184 enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error()) 185 } 186 } 187 188 // Equals returns whether two fields are equal. For non-primitive types such as 189 // errors, marshalers, or reflect types, it uses reflect.DeepEqual. 190 func (f Field) Equals(other Field) bool { 191 if f.Type != other.Type { 192 return false 193 } 194 if f.Key != other.Key { 195 return false 196 } 197 198 switch f.Type { 199 case BinaryType, ByteStringType: 200 return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte)) 201 case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType: 202 return reflect.DeepEqual(f.Interface, other.Interface) 203 default: 204 return f == other 205 } 206 } 207 208 func addFields(enc ObjectEncoder, fields []Field) { 209 for i := range fields { 210 fields[i].AddTo(enc) 211 } 212 } 213 214 func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr error) { 215 // Try to capture panics (from nil references or otherwise) when calling 216 // the String() method, similar to https://golang.org/src/fmt/print.go#L540 217 defer func() { 218 if err := recover(); err != nil { 219 // If it's a nil pointer, just say "<nil>". The likeliest causes are a 220 // Stringer that fails to guard against nil or a nil pointer for a 221 // value receiver, and in either case, "<nil>" is a nice result. 222 if v := reflect.ValueOf(stringer); v.Kind() == reflect.Ptr && v.IsNil() { 223 enc.AddString(key, "<nil>") 224 return 225 } 226 227 retErr = fmt.Errorf("PANIC=%v", err) 228 } 229 }() 230 231 enc.AddString(key, stringer.(fmt.Stringer).String()) 232 return nil 233 }