Holger Hildebrandt | fa07499 | 2020-03-27 15:42:06 +0000 | [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 | "encoding/base64" |
| 25 | "encoding/json" |
| 26 | "math" |
| 27 | "sync" |
| 28 | "time" |
| 29 | "unicode/utf8" |
| 30 | |
| 31 | "go.uber.org/zap/buffer" |
| 32 | "go.uber.org/zap/internal/bufferpool" |
| 33 | ) |
| 34 | |
| 35 | // For JSON-escaping; see jsonEncoder.safeAddString below. |
| 36 | const _hex = "0123456789abcdef" |
| 37 | |
| 38 | var _jsonPool = sync.Pool{New: func() interface{} { |
| 39 | return &jsonEncoder{} |
| 40 | }} |
| 41 | |
| 42 | func getJSONEncoder() *jsonEncoder { |
| 43 | return _jsonPool.Get().(*jsonEncoder) |
| 44 | } |
| 45 | |
| 46 | func putJSONEncoder(enc *jsonEncoder) { |
| 47 | if enc.reflectBuf != nil { |
| 48 | enc.reflectBuf.Free() |
| 49 | } |
| 50 | enc.EncoderConfig = nil |
| 51 | enc.buf = nil |
| 52 | enc.spaced = false |
| 53 | enc.openNamespaces = 0 |
| 54 | enc.reflectBuf = nil |
| 55 | enc.reflectEnc = nil |
| 56 | _jsonPool.Put(enc) |
| 57 | } |
| 58 | |
| 59 | type jsonEncoder struct { |
| 60 | *EncoderConfig |
| 61 | buf *buffer.Buffer |
| 62 | spaced bool // include spaces after colons and commas |
| 63 | openNamespaces int |
| 64 | |
| 65 | // for encoding generic values by reflection |
| 66 | reflectBuf *buffer.Buffer |
| 67 | reflectEnc *json.Encoder |
| 68 | } |
| 69 | |
| 70 | // NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder |
| 71 | // appropriately escapes all field keys and values. |
| 72 | // |
| 73 | // Note that the encoder doesn't deduplicate keys, so it's possible to produce |
| 74 | // a message like |
| 75 | // {"foo":"bar","foo":"baz"} |
| 76 | // This is permitted by the JSON specification, but not encouraged. Many |
| 77 | // libraries will ignore duplicate key-value pairs (typically keeping the last |
| 78 | // pair) when unmarshaling, but users should attempt to avoid adding duplicate |
| 79 | // keys. |
| 80 | func NewJSONEncoder(cfg EncoderConfig) Encoder { |
| 81 | return newJSONEncoder(cfg, false) |
| 82 | } |
| 83 | |
| 84 | func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder { |
| 85 | return &jsonEncoder{ |
| 86 | EncoderConfig: &cfg, |
| 87 | buf: bufferpool.Get(), |
| 88 | spaced: spaced, |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | func (enc *jsonEncoder) AddArray(key string, arr ArrayMarshaler) error { |
| 93 | enc.addKey(key) |
| 94 | return enc.AppendArray(arr) |
| 95 | } |
| 96 | |
| 97 | func (enc *jsonEncoder) AddObject(key string, obj ObjectMarshaler) error { |
| 98 | enc.addKey(key) |
| 99 | return enc.AppendObject(obj) |
| 100 | } |
| 101 | |
| 102 | func (enc *jsonEncoder) AddBinary(key string, val []byte) { |
| 103 | enc.AddString(key, base64.StdEncoding.EncodeToString(val)) |
| 104 | } |
| 105 | |
| 106 | func (enc *jsonEncoder) AddByteString(key string, val []byte) { |
| 107 | enc.addKey(key) |
| 108 | enc.AppendByteString(val) |
| 109 | } |
| 110 | |
| 111 | func (enc *jsonEncoder) AddBool(key string, val bool) { |
| 112 | enc.addKey(key) |
| 113 | enc.AppendBool(val) |
| 114 | } |
| 115 | |
| 116 | func (enc *jsonEncoder) AddComplex128(key string, val complex128) { |
| 117 | enc.addKey(key) |
| 118 | enc.AppendComplex128(val) |
| 119 | } |
| 120 | |
| 121 | func (enc *jsonEncoder) AddDuration(key string, val time.Duration) { |
| 122 | enc.addKey(key) |
| 123 | enc.AppendDuration(val) |
| 124 | } |
| 125 | |
| 126 | func (enc *jsonEncoder) AddFloat64(key string, val float64) { |
| 127 | enc.addKey(key) |
| 128 | enc.AppendFloat64(val) |
| 129 | } |
| 130 | |
| 131 | func (enc *jsonEncoder) AddInt64(key string, val int64) { |
| 132 | enc.addKey(key) |
| 133 | enc.AppendInt64(val) |
| 134 | } |
| 135 | |
| 136 | func (enc *jsonEncoder) resetReflectBuf() { |
| 137 | if enc.reflectBuf == nil { |
| 138 | enc.reflectBuf = bufferpool.Get() |
| 139 | enc.reflectEnc = json.NewEncoder(enc.reflectBuf) |
| 140 | |
| 141 | // For consistency with our custom JSON encoder. |
| 142 | enc.reflectEnc.SetEscapeHTML(false) |
| 143 | } else { |
| 144 | enc.reflectBuf.Reset() |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error { |
| 149 | enc.resetReflectBuf() |
| 150 | err := enc.reflectEnc.Encode(obj) |
| 151 | if err != nil { |
| 152 | return err |
| 153 | } |
| 154 | enc.reflectBuf.TrimNewline() |
| 155 | enc.addKey(key) |
| 156 | _, err = enc.buf.Write(enc.reflectBuf.Bytes()) |
| 157 | return err |
| 158 | } |
| 159 | |
| 160 | func (enc *jsonEncoder) OpenNamespace(key string) { |
| 161 | enc.addKey(key) |
| 162 | enc.buf.AppendByte('{') |
| 163 | enc.openNamespaces++ |
| 164 | } |
| 165 | |
| 166 | func (enc *jsonEncoder) AddString(key, val string) { |
| 167 | enc.addKey(key) |
| 168 | enc.AppendString(val) |
| 169 | } |
| 170 | |
| 171 | func (enc *jsonEncoder) AddTime(key string, val time.Time) { |
| 172 | enc.addKey(key) |
| 173 | enc.AppendTime(val) |
| 174 | } |
| 175 | |
| 176 | func (enc *jsonEncoder) AddUint64(key string, val uint64) { |
| 177 | enc.addKey(key) |
| 178 | enc.AppendUint64(val) |
| 179 | } |
| 180 | |
| 181 | func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error { |
| 182 | enc.addElementSeparator() |
| 183 | enc.buf.AppendByte('[') |
| 184 | err := arr.MarshalLogArray(enc) |
| 185 | enc.buf.AppendByte(']') |
| 186 | return err |
| 187 | } |
| 188 | |
| 189 | func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error { |
| 190 | enc.addElementSeparator() |
| 191 | enc.buf.AppendByte('{') |
| 192 | err := obj.MarshalLogObject(enc) |
| 193 | enc.buf.AppendByte('}') |
| 194 | return err |
| 195 | } |
| 196 | |
| 197 | func (enc *jsonEncoder) AppendBool(val bool) { |
| 198 | enc.addElementSeparator() |
| 199 | enc.buf.AppendBool(val) |
| 200 | } |
| 201 | |
| 202 | func (enc *jsonEncoder) AppendByteString(val []byte) { |
| 203 | enc.addElementSeparator() |
| 204 | enc.buf.AppendByte('"') |
| 205 | enc.safeAddByteString(val) |
| 206 | enc.buf.AppendByte('"') |
| 207 | } |
| 208 | |
| 209 | func (enc *jsonEncoder) AppendComplex128(val complex128) { |
| 210 | enc.addElementSeparator() |
| 211 | // Cast to a platform-independent, fixed-size type. |
| 212 | r, i := float64(real(val)), float64(imag(val)) |
| 213 | enc.buf.AppendByte('"') |
| 214 | // Because we're always in a quoted string, we can use strconv without |
| 215 | // special-casing NaN and +/-Inf. |
| 216 | enc.buf.AppendFloat(r, 64) |
| 217 | enc.buf.AppendByte('+') |
| 218 | enc.buf.AppendFloat(i, 64) |
| 219 | enc.buf.AppendByte('i') |
| 220 | enc.buf.AppendByte('"') |
| 221 | } |
| 222 | |
| 223 | func (enc *jsonEncoder) AppendDuration(val time.Duration) { |
| 224 | cur := enc.buf.Len() |
| 225 | enc.EncodeDuration(val, enc) |
| 226 | if cur == enc.buf.Len() { |
| 227 | // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep |
| 228 | // JSON valid. |
| 229 | enc.AppendInt64(int64(val)) |
| 230 | } |
| 231 | } |
| 232 | |
| 233 | func (enc *jsonEncoder) AppendInt64(val int64) { |
| 234 | enc.addElementSeparator() |
| 235 | enc.buf.AppendInt(val) |
| 236 | } |
| 237 | |
| 238 | func (enc *jsonEncoder) AppendReflected(val interface{}) error { |
| 239 | enc.resetReflectBuf() |
| 240 | err := enc.reflectEnc.Encode(val) |
| 241 | if err != nil { |
| 242 | return err |
| 243 | } |
| 244 | enc.reflectBuf.TrimNewline() |
| 245 | enc.addElementSeparator() |
| 246 | _, err = enc.buf.Write(enc.reflectBuf.Bytes()) |
| 247 | return err |
| 248 | } |
| 249 | |
| 250 | func (enc *jsonEncoder) AppendString(val string) { |
| 251 | enc.addElementSeparator() |
| 252 | enc.buf.AppendByte('"') |
| 253 | enc.safeAddString(val) |
| 254 | enc.buf.AppendByte('"') |
| 255 | } |
| 256 | |
| 257 | func (enc *jsonEncoder) AppendTime(val time.Time) { |
| 258 | cur := enc.buf.Len() |
| 259 | enc.EncodeTime(val, enc) |
| 260 | if cur == enc.buf.Len() { |
| 261 | // User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep |
| 262 | // output JSON valid. |
| 263 | enc.AppendInt64(val.UnixNano()) |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | func (enc *jsonEncoder) AppendUint64(val uint64) { |
| 268 | enc.addElementSeparator() |
| 269 | enc.buf.AppendUint(val) |
| 270 | } |
| 271 | |
| 272 | func (enc *jsonEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) } |
| 273 | func (enc *jsonEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) } |
| 274 | func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } |
| 275 | func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } |
| 276 | func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } |
| 277 | func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } |
| 278 | func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } |
| 279 | func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } |
| 280 | func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } |
| 281 | func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } |
| 282 | func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } |
| 283 | func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) } |
| 284 | func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } |
| 285 | func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } |
| 286 | func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } |
| 287 | func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } |
| 288 | func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } |
| 289 | func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } |
| 290 | func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } |
| 291 | func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } |
| 292 | func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } |
| 293 | func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } |
| 294 | func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } |
| 295 | |
| 296 | func (enc *jsonEncoder) Clone() Encoder { |
| 297 | clone := enc.clone() |
| 298 | clone.buf.Write(enc.buf.Bytes()) |
| 299 | return clone |
| 300 | } |
| 301 | |
| 302 | func (enc *jsonEncoder) clone() *jsonEncoder { |
| 303 | clone := getJSONEncoder() |
| 304 | clone.EncoderConfig = enc.EncoderConfig |
| 305 | clone.spaced = enc.spaced |
| 306 | clone.openNamespaces = enc.openNamespaces |
| 307 | clone.buf = bufferpool.Get() |
| 308 | return clone |
| 309 | } |
| 310 | |
| 311 | func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) { |
| 312 | final := enc.clone() |
| 313 | final.buf.AppendByte('{') |
| 314 | |
| 315 | if final.LevelKey != "" { |
| 316 | final.addKey(final.LevelKey) |
| 317 | cur := final.buf.Len() |
| 318 | final.EncodeLevel(ent.Level, final) |
| 319 | if cur == final.buf.Len() { |
| 320 | // User-supplied EncodeLevel was a no-op. Fall back to strings to keep |
| 321 | // output JSON valid. |
| 322 | final.AppendString(ent.Level.String()) |
| 323 | } |
| 324 | } |
| 325 | if final.TimeKey != "" { |
| 326 | final.AddTime(final.TimeKey, ent.Time) |
| 327 | } |
| 328 | if ent.LoggerName != "" && final.NameKey != "" { |
| 329 | final.addKey(final.NameKey) |
| 330 | cur := final.buf.Len() |
| 331 | nameEncoder := final.EncodeName |
| 332 | |
| 333 | // if no name encoder provided, fall back to FullNameEncoder for backwards |
| 334 | // compatibility |
| 335 | if nameEncoder == nil { |
| 336 | nameEncoder = FullNameEncoder |
| 337 | } |
| 338 | |
| 339 | nameEncoder(ent.LoggerName, final) |
| 340 | if cur == final.buf.Len() { |
| 341 | // User-supplied EncodeName was a no-op. Fall back to strings to |
| 342 | // keep output JSON valid. |
| 343 | final.AppendString(ent.LoggerName) |
| 344 | } |
| 345 | } |
| 346 | if ent.Caller.Defined && final.CallerKey != "" { |
| 347 | final.addKey(final.CallerKey) |
| 348 | cur := final.buf.Len() |
| 349 | final.EncodeCaller(ent.Caller, final) |
| 350 | if cur == final.buf.Len() { |
| 351 | // User-supplied EncodeCaller was a no-op. Fall back to strings to |
| 352 | // keep output JSON valid. |
| 353 | final.AppendString(ent.Caller.String()) |
| 354 | } |
| 355 | } |
| 356 | if final.MessageKey != "" { |
| 357 | final.addKey(enc.MessageKey) |
| 358 | final.AppendString(ent.Message) |
| 359 | } |
| 360 | if enc.buf.Len() > 0 { |
| 361 | final.addElementSeparator() |
| 362 | final.buf.Write(enc.buf.Bytes()) |
| 363 | } |
| 364 | addFields(final, fields) |
| 365 | final.closeOpenNamespaces() |
| 366 | if ent.Stack != "" && final.StacktraceKey != "" { |
| 367 | final.AddString(final.StacktraceKey, ent.Stack) |
| 368 | } |
| 369 | final.buf.AppendByte('}') |
| 370 | if final.LineEnding != "" { |
| 371 | final.buf.AppendString(final.LineEnding) |
| 372 | } else { |
| 373 | final.buf.AppendString(DefaultLineEnding) |
| 374 | } |
| 375 | |
| 376 | ret := final.buf |
| 377 | putJSONEncoder(final) |
| 378 | return ret, nil |
| 379 | } |
| 380 | |
| 381 | func (enc *jsonEncoder) truncate() { |
| 382 | enc.buf.Reset() |
| 383 | } |
| 384 | |
| 385 | func (enc *jsonEncoder) closeOpenNamespaces() { |
| 386 | for i := 0; i < enc.openNamespaces; i++ { |
| 387 | enc.buf.AppendByte('}') |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | func (enc *jsonEncoder) addKey(key string) { |
| 392 | enc.addElementSeparator() |
| 393 | enc.buf.AppendByte('"') |
| 394 | enc.safeAddString(key) |
| 395 | enc.buf.AppendByte('"') |
| 396 | enc.buf.AppendByte(':') |
| 397 | if enc.spaced { |
| 398 | enc.buf.AppendByte(' ') |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | func (enc *jsonEncoder) addElementSeparator() { |
| 403 | last := enc.buf.Len() - 1 |
| 404 | if last < 0 { |
| 405 | return |
| 406 | } |
| 407 | switch enc.buf.Bytes()[last] { |
| 408 | case '{', '[', ':', ',', ' ': |
| 409 | return |
| 410 | default: |
| 411 | enc.buf.AppendByte(',') |
| 412 | if enc.spaced { |
| 413 | enc.buf.AppendByte(' ') |
| 414 | } |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | func (enc *jsonEncoder) appendFloat(val float64, bitSize int) { |
| 419 | enc.addElementSeparator() |
| 420 | switch { |
| 421 | case math.IsNaN(val): |
| 422 | enc.buf.AppendString(`"NaN"`) |
| 423 | case math.IsInf(val, 1): |
| 424 | enc.buf.AppendString(`"+Inf"`) |
| 425 | case math.IsInf(val, -1): |
| 426 | enc.buf.AppendString(`"-Inf"`) |
| 427 | default: |
| 428 | enc.buf.AppendFloat(val, bitSize) |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | // safeAddString JSON-escapes a string and appends it to the internal buffer. |
| 433 | // Unlike the standard library's encoder, it doesn't attempt to protect the |
| 434 | // user from browser vulnerabilities or JSONP-related problems. |
| 435 | func (enc *jsonEncoder) safeAddString(s string) { |
| 436 | for i := 0; i < len(s); { |
| 437 | if enc.tryAddRuneSelf(s[i]) { |
| 438 | i++ |
| 439 | continue |
| 440 | } |
| 441 | r, size := utf8.DecodeRuneInString(s[i:]) |
| 442 | if enc.tryAddRuneError(r, size) { |
| 443 | i++ |
| 444 | continue |
| 445 | } |
| 446 | enc.buf.AppendString(s[i : i+size]) |
| 447 | i += size |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. |
| 452 | func (enc *jsonEncoder) safeAddByteString(s []byte) { |
| 453 | for i := 0; i < len(s); { |
| 454 | if enc.tryAddRuneSelf(s[i]) { |
| 455 | i++ |
| 456 | continue |
| 457 | } |
| 458 | r, size := utf8.DecodeRune(s[i:]) |
| 459 | if enc.tryAddRuneError(r, size) { |
| 460 | i++ |
| 461 | continue |
| 462 | } |
| 463 | enc.buf.Write(s[i : i+size]) |
| 464 | i += size |
| 465 | } |
| 466 | } |
| 467 | |
| 468 | // tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte. |
| 469 | func (enc *jsonEncoder) tryAddRuneSelf(b byte) bool { |
| 470 | if b >= utf8.RuneSelf { |
| 471 | return false |
| 472 | } |
| 473 | if 0x20 <= b && b != '\\' && b != '"' { |
| 474 | enc.buf.AppendByte(b) |
| 475 | return true |
| 476 | } |
| 477 | switch b { |
| 478 | case '\\', '"': |
| 479 | enc.buf.AppendByte('\\') |
| 480 | enc.buf.AppendByte(b) |
| 481 | case '\n': |
| 482 | enc.buf.AppendByte('\\') |
| 483 | enc.buf.AppendByte('n') |
| 484 | case '\r': |
| 485 | enc.buf.AppendByte('\\') |
| 486 | enc.buf.AppendByte('r') |
| 487 | case '\t': |
| 488 | enc.buf.AppendByte('\\') |
| 489 | enc.buf.AppendByte('t') |
| 490 | default: |
| 491 | // Encode bytes < 0x20, except for the escape sequences above. |
| 492 | enc.buf.AppendString(`\u00`) |
| 493 | enc.buf.AppendByte(_hex[b>>4]) |
| 494 | enc.buf.AppendByte(_hex[b&0xF]) |
| 495 | } |
| 496 | return true |
| 497 | } |
| 498 | |
| 499 | func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool { |
| 500 | if r == utf8.RuneError && size == 1 { |
| 501 | enc.buf.AppendString(`\ufffd`) |
| 502 | return true |
| 503 | } |
| 504 | return false |
| 505 | } |