github.com/Laisky/zap@v1.27.0/zapcore/json_encoder.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 "encoding/base64" 25 "math" 26 "time" 27 "unicode/utf8" 28 29 "github.com/Laisky/zap/buffer" 30 "github.com/Laisky/zap/internal/bufferpool" 31 "github.com/Laisky/zap/internal/pool" 32 ) 33 34 // For JSON-escaping; see jsonEncoder.safeAddString below. 35 const _hex = "0123456789abcdef" 36 37 var _jsonPool = pool.New(func() *jsonEncoder { 38 return &jsonEncoder{} 39 }) 40 41 func putJSONEncoder(enc *jsonEncoder) { 42 if enc.reflectBuf != nil { 43 enc.reflectBuf.Free() 44 } 45 enc.EncoderConfig = nil 46 enc.buf = nil 47 enc.spaced = false 48 enc.openNamespaces = 0 49 enc.reflectBuf = nil 50 enc.reflectEnc = nil 51 _jsonPool.Put(enc) 52 } 53 54 type jsonEncoder struct { 55 *EncoderConfig 56 buf *buffer.Buffer 57 spaced bool // include spaces after colons and commas 58 openNamespaces int 59 60 // for encoding generic values by reflection 61 reflectBuf *buffer.Buffer 62 reflectEnc ReflectedEncoder 63 } 64 65 // NewJSONEncoder creates a fast, low-allocation JSON encoder. The encoder 66 // appropriately escapes all field keys and values. 67 // 68 // Note that the encoder doesn't deduplicate keys, so it's possible to produce 69 // a message like 70 // 71 // {"foo":"bar","foo":"baz"} 72 // 73 // This is permitted by the JSON specification, but not encouraged. Many 74 // libraries will ignore duplicate key-value pairs (typically keeping the last 75 // pair) when unmarshaling, but users should attempt to avoid adding duplicate 76 // keys. 77 func NewJSONEncoder(cfg EncoderConfig) Encoder { 78 return newJSONEncoder(cfg, false) 79 } 80 81 func newJSONEncoder(cfg EncoderConfig, spaced bool) *jsonEncoder { 82 if cfg.SkipLineEnding { 83 cfg.LineEnding = "" 84 } else if cfg.LineEnding == "" { 85 cfg.LineEnding = DefaultLineEnding 86 } 87 88 // If no EncoderConfig.NewReflectedEncoder is provided by the user, then use default 89 if cfg.NewReflectedEncoder == nil { 90 cfg.NewReflectedEncoder = defaultReflectedEncoder 91 } 92 93 return &jsonEncoder{ 94 EncoderConfig: &cfg, 95 buf: bufferpool.Get(), 96 spaced: spaced, 97 } 98 } 99 100 func (enc *jsonEncoder) AddArray(key string, arr ArrayMarshaler) error { 101 enc.addKey(key) 102 return enc.AppendArray(arr) 103 } 104 105 func (enc *jsonEncoder) AddObject(key string, obj ObjectMarshaler) error { 106 enc.addKey(key) 107 return enc.AppendObject(obj) 108 } 109 110 func (enc *jsonEncoder) AddBinary(key string, val []byte) { 111 enc.AddString(key, base64.StdEncoding.EncodeToString(val)) 112 } 113 114 func (enc *jsonEncoder) AddByteString(key string, val []byte) { 115 enc.addKey(key) 116 enc.AppendByteString(val) 117 } 118 119 func (enc *jsonEncoder) AddBool(key string, val bool) { 120 enc.addKey(key) 121 enc.AppendBool(val) 122 } 123 124 func (enc *jsonEncoder) AddComplex128(key string, val complex128) { 125 enc.addKey(key) 126 enc.AppendComplex128(val) 127 } 128 129 func (enc *jsonEncoder) AddComplex64(key string, val complex64) { 130 enc.addKey(key) 131 enc.AppendComplex64(val) 132 } 133 134 func (enc *jsonEncoder) AddDuration(key string, val time.Duration) { 135 enc.addKey(key) 136 enc.AppendDuration(val) 137 } 138 139 func (enc *jsonEncoder) AddFloat64(key string, val float64) { 140 enc.addKey(key) 141 enc.AppendFloat64(val) 142 } 143 144 func (enc *jsonEncoder) AddFloat32(key string, val float32) { 145 enc.addKey(key) 146 enc.AppendFloat32(val) 147 } 148 149 func (enc *jsonEncoder) AddInt64(key string, val int64) { 150 enc.addKey(key) 151 enc.AppendInt64(val) 152 } 153 154 func (enc *jsonEncoder) resetReflectBuf() { 155 if enc.reflectBuf == nil { 156 enc.reflectBuf = bufferpool.Get() 157 enc.reflectEnc = enc.NewReflectedEncoder(enc.reflectBuf) 158 } else { 159 enc.reflectBuf.Reset() 160 } 161 } 162 163 var nullLiteralBytes = []byte("null") 164 165 // Only invoke the standard JSON encoder if there is actually something to 166 // encode; otherwise write JSON null literal directly. 167 func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) { 168 if obj == nil { 169 return nullLiteralBytes, nil 170 } 171 enc.resetReflectBuf() 172 if err := enc.reflectEnc.Encode(obj); err != nil { 173 return nil, err 174 } 175 enc.reflectBuf.TrimNewline() 176 return enc.reflectBuf.Bytes(), nil 177 } 178 179 func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error { 180 valueBytes, err := enc.encodeReflected(obj) 181 if err != nil { 182 return err 183 } 184 enc.addKey(key) 185 _, err = enc.buf.Write(valueBytes) 186 return err 187 } 188 189 func (enc *jsonEncoder) OpenNamespace(key string) { 190 enc.addKey(key) 191 enc.buf.AppendByte('{') 192 enc.openNamespaces++ 193 } 194 195 func (enc *jsonEncoder) AddString(key, val string) { 196 enc.addKey(key) 197 enc.AppendString(val) 198 } 199 200 func (enc *jsonEncoder) AddTime(key string, val time.Time) { 201 enc.addKey(key) 202 enc.AppendTime(val) 203 } 204 205 func (enc *jsonEncoder) AddUint64(key string, val uint64) { 206 enc.addKey(key) 207 enc.AppendUint64(val) 208 } 209 210 func (enc *jsonEncoder) AppendArray(arr ArrayMarshaler) error { 211 enc.addElementSeparator() 212 enc.buf.AppendByte('[') 213 err := arr.MarshalLogArray(enc) 214 enc.buf.AppendByte(']') 215 return err 216 } 217 218 func (enc *jsonEncoder) AppendObject(obj ObjectMarshaler) error { 219 // Close ONLY new openNamespaces that are created during 220 // AppendObject(). 221 old := enc.openNamespaces 222 enc.openNamespaces = 0 223 enc.addElementSeparator() 224 enc.buf.AppendByte('{') 225 err := obj.MarshalLogObject(enc) 226 enc.buf.AppendByte('}') 227 enc.closeOpenNamespaces() 228 enc.openNamespaces = old 229 return err 230 } 231 232 func (enc *jsonEncoder) AppendBool(val bool) { 233 enc.addElementSeparator() 234 enc.buf.AppendBool(val) 235 } 236 237 func (enc *jsonEncoder) AppendByteString(val []byte) { 238 enc.addElementSeparator() 239 enc.buf.AppendByte('"') 240 enc.safeAddByteString(val) 241 enc.buf.AppendByte('"') 242 } 243 244 // appendComplex appends the encoded form of the provided complex128 value. 245 // precision specifies the encoding precision for the real and imaginary 246 // components of the complex number. 247 func (enc *jsonEncoder) appendComplex(val complex128, precision int) { 248 enc.addElementSeparator() 249 // Cast to a platform-independent, fixed-size type. 250 r, i := float64(real(val)), float64(imag(val)) 251 enc.buf.AppendByte('"') 252 // Because we're always in a quoted string, we can use strconv without 253 // special-casing NaN and +/-Inf. 254 enc.buf.AppendFloat(r, precision) 255 // If imaginary part is less than 0, minus (-) sign is added by default 256 // by AppendFloat. 257 if i >= 0 { 258 enc.buf.AppendByte('+') 259 } 260 enc.buf.AppendFloat(i, precision) 261 enc.buf.AppendByte('i') 262 enc.buf.AppendByte('"') 263 } 264 265 func (enc *jsonEncoder) AppendDuration(val time.Duration) { 266 cur := enc.buf.Len() 267 if e := enc.EncodeDuration; e != nil { 268 e(val, enc) 269 } 270 if cur == enc.buf.Len() { 271 // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep 272 // JSON valid. 273 enc.AppendInt64(int64(val)) 274 } 275 } 276 277 func (enc *jsonEncoder) AppendInt64(val int64) { 278 enc.addElementSeparator() 279 enc.buf.AppendInt(val) 280 } 281 282 func (enc *jsonEncoder) AppendReflected(val interface{}) error { 283 valueBytes, err := enc.encodeReflected(val) 284 if err != nil { 285 return err 286 } 287 enc.addElementSeparator() 288 _, err = enc.buf.Write(valueBytes) 289 return err 290 } 291 292 func (enc *jsonEncoder) AppendString(val string) { 293 enc.addElementSeparator() 294 enc.buf.AppendByte('"') 295 enc.safeAddString(val) 296 enc.buf.AppendByte('"') 297 } 298 299 func (enc *jsonEncoder) AppendTimeLayout(time time.Time, layout string) { 300 enc.addElementSeparator() 301 enc.buf.AppendByte('"') 302 enc.buf.AppendTime(time, layout) 303 enc.buf.AppendByte('"') 304 } 305 306 func (enc *jsonEncoder) AppendTime(val time.Time) { 307 cur := enc.buf.Len() 308 if e := enc.EncodeTime; e != nil { 309 e(val, enc) 310 } 311 if cur == enc.buf.Len() { 312 // User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep 313 // output JSON valid. 314 enc.AppendInt64(val.UnixNano()) 315 } 316 } 317 318 func (enc *jsonEncoder) AppendUint64(val uint64) { 319 enc.addElementSeparator() 320 enc.buf.AppendUint(val) 321 } 322 323 func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } 324 func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } 325 func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } 326 func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } 327 func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } 328 func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } 329 func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } 330 func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } 331 func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } 332 func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.appendComplex(complex128(v), 32) } 333 func (enc *jsonEncoder) AppendComplex128(v complex128) { enc.appendComplex(complex128(v), 64) } 334 func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } 335 func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } 336 func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } 337 func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } 338 func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } 339 func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } 340 func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } 341 func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } 342 func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } 343 func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } 344 func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } 345 346 func (enc *jsonEncoder) Clone() Encoder { 347 clone := enc.clone() 348 clone.buf.Write(enc.buf.Bytes()) 349 return clone 350 } 351 352 func (enc *jsonEncoder) clone() *jsonEncoder { 353 clone := _jsonPool.Get() 354 clone.EncoderConfig = enc.EncoderConfig 355 clone.spaced = enc.spaced 356 clone.openNamespaces = enc.openNamespaces 357 clone.buf = bufferpool.Get() 358 return clone 359 } 360 361 func (enc *jsonEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) { 362 final := enc.clone() 363 final.buf.AppendByte('{') 364 365 if final.LevelKey != "" && final.EncodeLevel != nil { 366 final.addKey(final.LevelKey) 367 cur := final.buf.Len() 368 final.EncodeLevel(ent.Level, final) 369 if cur == final.buf.Len() { 370 // User-supplied EncodeLevel was a no-op. Fall back to strings to keep 371 // output JSON valid. 372 final.AppendString(ent.Level.String()) 373 } 374 } 375 if final.TimeKey != "" && !ent.Time.IsZero() { 376 final.AddTime(final.TimeKey, ent.Time) 377 } 378 if ent.LoggerName != "" && final.NameKey != "" { 379 final.addKey(final.NameKey) 380 cur := final.buf.Len() 381 nameEncoder := final.EncodeName 382 383 // if no name encoder provided, fall back to FullNameEncoder for backwards 384 // compatibility 385 if nameEncoder == nil { 386 nameEncoder = FullNameEncoder 387 } 388 389 nameEncoder(ent.LoggerName, final) 390 if cur == final.buf.Len() { 391 // User-supplied EncodeName was a no-op. Fall back to strings to 392 // keep output JSON valid. 393 final.AppendString(ent.LoggerName) 394 } 395 } 396 if ent.Caller.Defined { 397 if final.CallerKey != "" { 398 final.addKey(final.CallerKey) 399 cur := final.buf.Len() 400 final.EncodeCaller(ent.Caller, final) 401 if cur == final.buf.Len() { 402 // User-supplied EncodeCaller was a no-op. Fall back to strings to 403 // keep output JSON valid. 404 final.AppendString(ent.Caller.String()) 405 } 406 } 407 if final.FunctionKey != "" { 408 final.addKey(final.FunctionKey) 409 final.AppendString(ent.Caller.Function) 410 } 411 } 412 if final.MessageKey != "" { 413 final.addKey(enc.MessageKey) 414 final.AppendString(ent.Message) 415 } 416 if enc.buf.Len() > 0 { 417 final.addElementSeparator() 418 final.buf.Write(enc.buf.Bytes()) 419 } 420 addFields(final, fields) 421 final.closeOpenNamespaces() 422 if ent.Stack != "" && final.StacktraceKey != "" { 423 final.AddString(final.StacktraceKey, ent.Stack) 424 } 425 final.buf.AppendByte('}') 426 final.buf.AppendString(final.LineEnding) 427 428 ret := final.buf 429 putJSONEncoder(final) 430 return ret, nil 431 } 432 433 func (enc *jsonEncoder) truncate() { 434 enc.buf.Reset() 435 } 436 437 func (enc *jsonEncoder) closeOpenNamespaces() { 438 for i := 0; i < enc.openNamespaces; i++ { 439 enc.buf.AppendByte('}') 440 } 441 enc.openNamespaces = 0 442 } 443 444 func (enc *jsonEncoder) addKey(key string) { 445 enc.addElementSeparator() 446 enc.buf.AppendByte('"') 447 enc.safeAddString(key) 448 enc.buf.AppendByte('"') 449 enc.buf.AppendByte(':') 450 if enc.spaced { 451 enc.buf.AppendByte(' ') 452 } 453 } 454 455 func (enc *jsonEncoder) addElementSeparator() { 456 last := enc.buf.Len() - 1 457 if last < 0 { 458 return 459 } 460 switch enc.buf.Bytes()[last] { 461 case '{', '[', ':', ',', ' ': 462 return 463 default: 464 enc.buf.AppendByte(',') 465 if enc.spaced { 466 enc.buf.AppendByte(' ') 467 } 468 } 469 } 470 471 func (enc *jsonEncoder) appendFloat(val float64, bitSize int) { 472 enc.addElementSeparator() 473 switch { 474 case math.IsNaN(val): 475 enc.buf.AppendString(`"NaN"`) 476 case math.IsInf(val, 1): 477 enc.buf.AppendString(`"+Inf"`) 478 case math.IsInf(val, -1): 479 enc.buf.AppendString(`"-Inf"`) 480 default: 481 enc.buf.AppendFloat(val, bitSize) 482 } 483 } 484 485 // safeAddString JSON-escapes a string and appends it to the internal buffer. 486 // Unlike the standard library's encoder, it doesn't attempt to protect the 487 // user from browser vulnerabilities or JSONP-related problems. 488 func (enc *jsonEncoder) safeAddString(s string) { 489 safeAppendStringLike( 490 (*buffer.Buffer).AppendString, 491 utf8.DecodeRuneInString, 492 enc.buf, 493 s, 494 ) 495 } 496 497 // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. 498 func (enc *jsonEncoder) safeAddByteString(s []byte) { 499 safeAppendStringLike( 500 (*buffer.Buffer).AppendBytes, 501 utf8.DecodeRune, 502 enc.buf, 503 s, 504 ) 505 } 506 507 // safeAppendStringLike is a generic implementation of safeAddString and safeAddByteString. 508 // It appends a string or byte slice to the buffer, escaping all special characters. 509 func safeAppendStringLike[S []byte | string]( 510 // appendTo appends this string-like object to the buffer. 511 appendTo func(*buffer.Buffer, S), 512 // decodeRune decodes the next rune from the string-like object 513 // and returns its value and width in bytes. 514 decodeRune func(S) (rune, int), 515 buf *buffer.Buffer, 516 s S, 517 ) { 518 // The encoding logic below works by skipping over characters 519 // that can be safely copied as-is, 520 // until a character is found that needs special handling. 521 // At that point, we copy everything we've seen so far, 522 // and then handle that special character. 523 // 524 // last is the index of the last byte that was copied to the buffer. 525 last := 0 526 for i := 0; i < len(s); { 527 if s[i] >= utf8.RuneSelf { 528 // Character >= RuneSelf may be part of a multi-byte rune. 529 // They need to be decoded before we can decide how to handle them. 530 r, size := decodeRune(s[i:]) 531 if r != utf8.RuneError || size != 1 { 532 // No special handling required. 533 // Skip over this rune and continue. 534 i += size 535 continue 536 } 537 538 // Invalid UTF-8 sequence. 539 // Replace it with the Unicode replacement character. 540 appendTo(buf, s[last:i]) 541 buf.AppendString(`\ufffd`) 542 543 i++ 544 last = i 545 } else { 546 // Character < RuneSelf is a single-byte UTF-8 rune. 547 if s[i] >= 0x20 && s[i] != '\\' && s[i] != '"' { 548 // No escaping necessary. 549 // Skip over this character and continue. 550 i++ 551 continue 552 } 553 554 // This character needs to be escaped. 555 appendTo(buf, s[last:i]) 556 switch s[i] { 557 case '\\', '"': 558 buf.AppendByte('\\') 559 buf.AppendByte(s[i]) 560 case '\n': 561 buf.AppendByte('\\') 562 buf.AppendByte('n') 563 case '\r': 564 buf.AppendByte('\\') 565 buf.AppendByte('r') 566 case '\t': 567 buf.AppendByte('\\') 568 buf.AppendByte('t') 569 default: 570 // Encode bytes < 0x20, except for the escape sequences above. 571 buf.AppendString(`\u00`) 572 buf.AppendByte(_hex[s[i]>>4]) 573 buf.AppendByte(_hex[s[i]&0xF]) 574 } 575 576 i++ 577 last = i 578 } 579 } 580 581 // add remaining 582 appendTo(buf, s[last:]) 583 }