Don Newton | 7577f07 | 2020-01-06 12:41:11 -0500 | [diff] [blame] | 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 complex128. |
| 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. |
| 69 | TimeType |
| 70 | // Uint64Type indicates that the field carries a uint64. |
| 71 | Uint64Type |
| 72 | // Uint32Type indicates that the field carries a uint32. |
| 73 | Uint32Type |
| 74 | // Uint16Type indicates that the field carries a uint16. |
| 75 | Uint16Type |
| 76 | // Uint8Type indicates that the field carries a uint8. |
| 77 | Uint8Type |
| 78 | // UintptrType indicates that the field carries a uintptr. |
| 79 | UintptrType |
| 80 | // ReflectType indicates that the field carries an interface{}, which should |
| 81 | // be serialized using reflection. |
| 82 | ReflectType |
| 83 | // NamespaceType signals the beginning of an isolated namespace. All |
| 84 | // subsequent fields should be added to the new namespace. |
| 85 | NamespaceType |
| 86 | // StringerType indicates that the field carries a fmt.Stringer. |
| 87 | StringerType |
| 88 | // ErrorType indicates that the field carries an error. |
| 89 | ErrorType |
| 90 | // SkipType indicates that the field is a no-op. |
| 91 | SkipType |
| 92 | ) |
| 93 | |
| 94 | // A Field is a marshaling operation used to add a key-value pair to a logger's |
| 95 | // context. Most fields are lazily marshaled, so it's inexpensive to add fields |
| 96 | // to disabled debug-level log statements. |
| 97 | type Field struct { |
| 98 | Key string |
| 99 | Type FieldType |
| 100 | Integer int64 |
| 101 | String string |
| 102 | Interface interface{} |
| 103 | } |
| 104 | |
| 105 | // AddTo exports a field through the ObjectEncoder interface. It's primarily |
| 106 | // useful to library authors, and shouldn't be necessary in most applications. |
| 107 | func (f Field) AddTo(enc ObjectEncoder) { |
| 108 | var err error |
| 109 | |
| 110 | switch f.Type { |
| 111 | case ArrayMarshalerType: |
| 112 | err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler)) |
| 113 | case ObjectMarshalerType: |
| 114 | err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler)) |
| 115 | case BinaryType: |
| 116 | enc.AddBinary(f.Key, f.Interface.([]byte)) |
| 117 | case BoolType: |
| 118 | enc.AddBool(f.Key, f.Integer == 1) |
| 119 | case ByteStringType: |
| 120 | enc.AddByteString(f.Key, f.Interface.([]byte)) |
| 121 | case Complex128Type: |
| 122 | enc.AddComplex128(f.Key, f.Interface.(complex128)) |
| 123 | case Complex64Type: |
| 124 | enc.AddComplex64(f.Key, f.Interface.(complex64)) |
| 125 | case DurationType: |
| 126 | enc.AddDuration(f.Key, time.Duration(f.Integer)) |
| 127 | case Float64Type: |
| 128 | enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer))) |
| 129 | case Float32Type: |
| 130 | enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer))) |
| 131 | case Int64Type: |
| 132 | enc.AddInt64(f.Key, f.Integer) |
| 133 | case Int32Type: |
| 134 | enc.AddInt32(f.Key, int32(f.Integer)) |
| 135 | case Int16Type: |
| 136 | enc.AddInt16(f.Key, int16(f.Integer)) |
| 137 | case Int8Type: |
| 138 | enc.AddInt8(f.Key, int8(f.Integer)) |
| 139 | case StringType: |
| 140 | enc.AddString(f.Key, f.String) |
| 141 | case TimeType: |
| 142 | if f.Interface != nil { |
| 143 | enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location))) |
| 144 | } else { |
| 145 | // Fall back to UTC if location is nil. |
| 146 | enc.AddTime(f.Key, time.Unix(0, f.Integer)) |
| 147 | } |
| 148 | case Uint64Type: |
| 149 | enc.AddUint64(f.Key, uint64(f.Integer)) |
| 150 | case Uint32Type: |
| 151 | enc.AddUint32(f.Key, uint32(f.Integer)) |
| 152 | case Uint16Type: |
| 153 | enc.AddUint16(f.Key, uint16(f.Integer)) |
| 154 | case Uint8Type: |
| 155 | enc.AddUint8(f.Key, uint8(f.Integer)) |
| 156 | case UintptrType: |
| 157 | enc.AddUintptr(f.Key, uintptr(f.Integer)) |
| 158 | case ReflectType: |
| 159 | err = enc.AddReflected(f.Key, f.Interface) |
| 160 | case NamespaceType: |
| 161 | enc.OpenNamespace(f.Key) |
| 162 | case StringerType: |
| 163 | err = encodeStringer(f.Key, f.Interface, enc) |
| 164 | case ErrorType: |
| 165 | encodeError(f.Key, f.Interface.(error), enc) |
| 166 | case SkipType: |
| 167 | break |
| 168 | default: |
| 169 | panic(fmt.Sprintf("unknown field type: %v", f)) |
| 170 | } |
| 171 | |
| 172 | if err != nil { |
| 173 | enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error()) |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | // Equals returns whether two fields are equal. For non-primitive types such as |
| 178 | // errors, marshalers, or reflect types, it uses reflect.DeepEqual. |
| 179 | func (f Field) Equals(other Field) bool { |
| 180 | if f.Type != other.Type { |
| 181 | return false |
| 182 | } |
| 183 | if f.Key != other.Key { |
| 184 | return false |
| 185 | } |
| 186 | |
| 187 | switch f.Type { |
| 188 | case BinaryType, ByteStringType: |
| 189 | return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte)) |
| 190 | case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType: |
| 191 | return reflect.DeepEqual(f.Interface, other.Interface) |
| 192 | default: |
| 193 | return f == other |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | func addFields(enc ObjectEncoder, fields []Field) { |
| 198 | for i := range fields { |
| 199 | fields[i].AddTo(enc) |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (err error) { |
| 204 | defer func() { |
| 205 | if v := recover(); v != nil { |
| 206 | err = fmt.Errorf("PANIC=%v", v) |
| 207 | } |
| 208 | }() |
| 209 | |
| 210 | enc.AddString(key, stringer.(fmt.Stringer).String()) |
| 211 | return |
| 212 | } |