github.com/gagliardetto/solana-go@v1.11.0/zap-box/encoder.go (about) 1 // Copyright 2020 dfuse Platform Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package zapbox 16 17 import ( 18 "encoding/base64" 19 "math" 20 "os" 21 "path" 22 "strings" 23 "sync" 24 "time" 25 "unicode/utf8" 26 27 jsoniter "github.com/json-iterator/go" 28 "github.com/logrusorgru/aurora" 29 . "github.com/logrusorgru/aurora" 30 "go.uber.org/zap" 31 "go.uber.org/zap/buffer" 32 "go.uber.org/zap/zapcore" 33 "golang.org/x/crypto/ssh/terminal" 34 ) 35 36 var json = jsoniter.ConfigCompatibleWithStandardLibrary 37 38 const ( 39 ansiColorEscape = "\033[" 40 clearANSIModifier = ansiColorEscape + "0m" 41 grayFg = (Color(232 + 12)) << 16 42 ) 43 44 var bufferpool = buffer.NewPool() 45 var levelToColor map[zapcore.Level]Color 46 47 var _loggerPool = sync.Pool{New: func() interface{} { 48 return &Encoder{} 49 }} 50 51 func init() { 52 levelToColor = make(map[zapcore.Level]Color) 53 levelToColor[zap.DebugLevel] = MagentaFg 54 levelToColor[zap.InfoLevel] = GreenFg 55 levelToColor[zap.WarnLevel] = BrownFg 56 levelToColor[zap.ErrorLevel] = RedFg 57 levelToColor[zap.DPanicLevel] = RedFg 58 levelToColor[zap.PanicLevel] = RedFg 59 levelToColor[zap.FatalLevel] = RedFg 60 } 61 62 type Encoder struct { 63 *jsonEncoder 64 65 showLevel bool 66 showLoggerName bool 67 showCallerName bool 68 showFullCaller bool 69 showStacktrace bool 70 showTime bool 71 72 enableAnsiColor bool 73 } 74 75 func NewEncoder(verbosity int) zapcore.Encoder { 76 isDebug := os.Getenv("DEBUG") != "" 77 isInfo := os.Getenv("INFO") != "" 78 isTTY := terminal.IsTerminal(int(os.Stdout.Fd())) 79 80 return &Encoder{ 81 jsonEncoder: newJSONEncoder(zapcore.EncoderConfig{ 82 EncodeDuration: zapcore.StringDurationEncoder, 83 EncodeTime: zapcore.ISO8601TimeEncoder, 84 }, true), 85 86 showLevel: isInfo || isDebug || verbosity >= 1, 87 showLoggerName: isInfo || isDebug || verbosity >= 1, 88 showTime: isInfo || isDebug || verbosity >= 1, 89 showCallerName: isInfo || isDebug || verbosity >= 1, 90 showFullCaller: verbosity >= 4, 91 92 // Also always forced displayed on "Error" level and above 93 showStacktrace: isInfo || isDebug || verbosity >= 2, 94 95 enableAnsiColor: isTTY, 96 } 97 } 98 99 func (c Encoder) Clone() zapcore.Encoder { 100 return &Encoder{ 101 jsonEncoder: c.jsonEncoder.Clone().(*jsonEncoder), 102 103 showLevel: c.showLevel, 104 showLoggerName: c.showLoggerName, 105 showStacktrace: c.showStacktrace, 106 showCallerName: c.showCallerName, 107 showFullCaller: c.showFullCaller, 108 showTime: c.showTime, 109 110 enableAnsiColor: c.enableAnsiColor, 111 } 112 } 113 114 func (c Encoder) colorString(color, s string) (out string) { 115 if c.enableAnsiColor { 116 out += ansiColorEscape + color + "m" 117 } 118 119 out += s 120 121 if c.enableAnsiColor { 122 out += clearANSIModifier 123 } 124 125 return 126 } 127 128 func (c Encoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { 129 line := bufferpool.Get() 130 lineColor := levelColor(ent.Level) 131 132 if c.showTime { 133 line.AppendString(c.colorString(grayFg.Nos(true), ent.Time.Format("2006-01-02T15:04:05.000Z0700")+" ")) 134 } 135 136 showLoggerName := c.showLoggerName && ent.LoggerName != "" 137 if showLoggerName { 138 loggerName := ent.LoggerName 139 if loggerName == "common" && ent.Caller.Defined { 140 base := path.Base(ent.Caller.FullPath()) 141 packagePath := strings.Split(base, ".")[0] 142 if packagePath != "" { 143 loggerName = packagePath 144 } 145 } 146 147 line.AppendString(c.colorString(BlueFg.Nos(true), "("+loggerName+") ")) 148 } 149 150 message := ent.Message 151 if strings.HasSuffix(message, ".") && !strings.HasSuffix(message, "...") { 152 message = strings.TrimSuffix(message, ".") 153 } 154 155 line.AppendString(c.colorString(lineColor.Nos(true), message)) 156 157 showCaller := (c.showCallerName || zap.WarnLevel.Enabled(ent.Level)) && ent.Caller.Defined 158 if showCaller && ent.LoggerName != "box" { 159 callerPath := ent.Caller.TrimmedPath() 160 if !c.showFullCaller { 161 callerPath = maybeRemovePackageVersion(callerPath) 162 } 163 164 line.AppendString(c.colorString(BlueFg.Nos(true), " ("+callerPath+")")) 165 } 166 167 // Add any structured context even if len(fields) == 0 because there could be implicit (With()) fields 168 if c.enableAnsiColor { 169 line.AppendString(ansiColorEscape + grayFg.Nos(true) + "m ") 170 } 171 c.writeJSONFields(line, fields) 172 if c.enableAnsiColor { 173 line.AppendString(clearANSIModifier) 174 } 175 176 if ent.Stack != "" && (c.showStacktrace || zap.ErrorLevel.Enabled(ent.Level)) { 177 line.AppendString("\n" + c.colorString(lineColor.Nos(true), ent.Stack)) 178 } 179 180 line.AppendString("\n") 181 182 return line, nil 183 } 184 185 func maybeRemovePackageVersion(input string) string { 186 atIndex := strings.Index(input, "@") 187 if atIndex == -1 { 188 return input 189 } 190 191 cutUpToIndex := strings.LastIndex(input, "/") 192 if cutUpToIndex == -1 { 193 return input 194 } 195 196 return input[0:atIndex] + input[cutUpToIndex:] 197 } 198 199 func (c Encoder) writeJSONFields(line *buffer.Buffer, extra []zapcore.Field) { 200 context := c.Clone().(*Encoder) 201 defer context.buf.Free() 202 203 addFields(context, extra) 204 context.closeOpenNamespaces() 205 if context.buf.Len() == 0 { 206 return 207 } 208 209 line.AppendByte('{') 210 line.Write(context.buf.Bytes()) 211 line.AppendByte('}') 212 } 213 214 func levelColor(level zapcore.Level) aurora.Color { 215 color := levelToColor[level] 216 if color == 0 { 217 color = BlueFg 218 } 219 220 return color 221 } 222 223 func addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) { 224 for i := range fields { 225 fields[i].AddTo(enc) 226 } 227 } 228 229 // Copied from `github.com/uber-go/zap/zapcore/json_encoder.go` 230 231 // For JSON-escaping; see jsonEncoder.safeAddString below. 232 const _hex = "0123456789abcdef" 233 234 var _jsonPool = sync.Pool{New: func() interface{} { 235 return &jsonEncoder{} 236 }} 237 238 func getJSONEncoder() *jsonEncoder { 239 return _jsonPool.Get().(*jsonEncoder) 240 } 241 242 func putJSONEncoder(enc *jsonEncoder) { 243 if enc.reflectBuf != nil { 244 enc.reflectBuf.Free() 245 } 246 enc.EncoderConfig = nil 247 enc.buf = nil 248 enc.spaced = false 249 enc.openNamespaces = 0 250 enc.reflectBuf = nil 251 enc.reflectEnc = nil 252 _jsonPool.Put(enc) 253 } 254 255 type jsonEncoder struct { 256 *zapcore.EncoderConfig 257 buf *buffer.Buffer 258 spaced bool // include spaces after colons and commas 259 openNamespaces int 260 261 // for encoding generic values by reflection 262 reflectBuf *buffer.Buffer 263 reflectEnc *jsoniter.Encoder 264 } 265 266 func newJSONEncoder(cfg zapcore.EncoderConfig, spaced bool) *jsonEncoder { 267 return &jsonEncoder{ 268 EncoderConfig: &cfg, 269 buf: bufferpool.Get(), 270 spaced: spaced, 271 } 272 } 273 274 func (enc *jsonEncoder) AddArray(key string, arr zapcore.ArrayMarshaler) error { 275 enc.addKey(key) 276 return enc.AppendArray(arr) 277 } 278 279 func (enc *jsonEncoder) AddObject(key string, obj zapcore.ObjectMarshaler) error { 280 enc.addKey(key) 281 return enc.AppendObject(obj) 282 } 283 284 func (enc *jsonEncoder) AddBinary(key string, val []byte) { 285 enc.AddString(key, base64.StdEncoding.EncodeToString(val)) 286 } 287 288 func (enc *jsonEncoder) AddByteString(key string, val []byte) { 289 enc.addKey(key) 290 enc.AppendByteString(val) 291 } 292 293 func (enc *jsonEncoder) AddBool(key string, val bool) { 294 enc.addKey(key) 295 enc.AppendBool(val) 296 } 297 298 func (enc *jsonEncoder) AddComplex128(key string, val complex128) { 299 enc.addKey(key) 300 enc.AppendComplex128(val) 301 } 302 303 func (enc *jsonEncoder) AddDuration(key string, val time.Duration) { 304 enc.addKey(key) 305 enc.AppendDuration(val) 306 } 307 308 func (enc *jsonEncoder) AddFloat64(key string, val float64) { 309 enc.addKey(key) 310 enc.AppendFloat64(val) 311 } 312 313 func (enc *jsonEncoder) AddInt64(key string, val int64) { 314 enc.addKey(key) 315 enc.AppendInt64(val) 316 } 317 318 func (enc *jsonEncoder) resetReflectBuf() { 319 if enc.reflectBuf == nil { 320 enc.reflectBuf = bufferpool.Get() 321 enc.reflectEnc = json.NewEncoder(enc.reflectBuf) 322 323 // For consistency with our custom JSON encoder. 324 enc.reflectEnc.SetEscapeHTML(false) 325 } else { 326 enc.reflectBuf.Reset() 327 } 328 } 329 330 var nullLiteralBytes = []byte("null") 331 332 // Only invoke the standard JSON encoder if there is actually something to 333 // encode; otherwise write JSON null literal directly. 334 func (enc *jsonEncoder) encodeReflected(obj interface{}) ([]byte, error) { 335 if obj == nil { 336 return nullLiteralBytes, nil 337 } 338 enc.resetReflectBuf() 339 if err := enc.reflectEnc.Encode(obj); err != nil { 340 return nil, err 341 } 342 enc.reflectBuf.TrimNewline() 343 return enc.reflectBuf.Bytes(), nil 344 } 345 346 func (enc *jsonEncoder) AddReflected(key string, obj interface{}) error { 347 valueBytes, err := enc.encodeReflected(obj) 348 if err != nil { 349 return err 350 } 351 enc.addKey(key) 352 _, err = enc.buf.Write(valueBytes) 353 return err 354 } 355 356 func (enc *jsonEncoder) OpenNamespace(key string) { 357 enc.addKey(key) 358 enc.buf.AppendByte('{') 359 enc.openNamespaces++ 360 } 361 362 func (enc *jsonEncoder) AddString(key, val string) { 363 enc.addKey(key) 364 enc.AppendString(val) 365 } 366 367 func (enc *jsonEncoder) AddTime(key string, val time.Time) { 368 enc.addKey(key) 369 enc.AppendTime(val) 370 } 371 372 func (enc *jsonEncoder) AddUint64(key string, val uint64) { 373 enc.addKey(key) 374 enc.AppendUint64(val) 375 } 376 377 func (enc *jsonEncoder) AppendArray(arr zapcore.ArrayMarshaler) error { 378 enc.addElementSeparator() 379 enc.buf.AppendByte('[') 380 err := arr.MarshalLogArray(enc) 381 enc.buf.AppendByte(']') 382 return err 383 } 384 385 func (enc *jsonEncoder) AppendObject(obj zapcore.ObjectMarshaler) error { 386 enc.addElementSeparator() 387 enc.buf.AppendByte('{') 388 err := obj.MarshalLogObject(enc) 389 enc.buf.AppendByte('}') 390 return err 391 } 392 393 func (enc *jsonEncoder) AppendBool(val bool) { 394 enc.addElementSeparator() 395 enc.buf.AppendBool(val) 396 } 397 398 func (enc *jsonEncoder) AppendByteString(val []byte) { 399 enc.addElementSeparator() 400 enc.buf.AppendByte('"') 401 enc.safeAddByteString(val) 402 enc.buf.AppendByte('"') 403 } 404 405 func (enc *jsonEncoder) AppendComplex128(val complex128) { 406 enc.addElementSeparator() 407 // Cast to a platform-independent, fixed-size type. 408 r, i := float64(real(val)), float64(imag(val)) 409 enc.buf.AppendByte('"') 410 // Because we're always in a quoted string, we can use strconv without 411 // special-casing NaN and +/-Inf. 412 enc.buf.AppendFloat(r, 64) 413 enc.buf.AppendByte('+') 414 enc.buf.AppendFloat(i, 64) 415 enc.buf.AppendByte('i') 416 enc.buf.AppendByte('"') 417 } 418 419 func (enc *jsonEncoder) AppendDuration(val time.Duration) { 420 cur := enc.buf.Len() 421 enc.EncodeDuration(val, enc) 422 if cur == enc.buf.Len() { 423 // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds to keep 424 // JSON valid. 425 enc.AppendInt64(int64(val)) 426 } 427 } 428 429 func (enc *jsonEncoder) AppendInt64(val int64) { 430 enc.addElementSeparator() 431 enc.buf.AppendInt(val) 432 } 433 434 func (enc *jsonEncoder) AppendReflected(val interface{}) error { 435 valueBytes, err := enc.encodeReflected(val) 436 if err != nil { 437 return err 438 } 439 enc.addElementSeparator() 440 _, err = enc.buf.Write(valueBytes) 441 return err 442 } 443 444 func (enc *jsonEncoder) AppendString(val string) { 445 enc.addElementSeparator() 446 enc.buf.AppendByte('"') 447 enc.safeAddString(val) 448 enc.buf.AppendByte('"') 449 } 450 451 func (enc *jsonEncoder) AppendTimeLayout(time time.Time, layout string) { 452 enc.buf.AppendByte('"') 453 enc.buf.AppendTime(time, layout) 454 enc.buf.AppendByte('"') 455 } 456 457 func (enc *jsonEncoder) AppendTime(val time.Time) { 458 cur := enc.buf.Len() 459 enc.EncodeTime(val, enc) 460 if cur == enc.buf.Len() { 461 // User-supplied EncodeTime is a no-op. Fall back to nanos since epoch to keep 462 // output JSON valid. 463 enc.AppendInt64(val.UnixNano()) 464 } 465 } 466 467 func (enc *jsonEncoder) AppendUint64(val uint64) { 468 enc.addElementSeparator() 469 enc.buf.AppendUint(val) 470 } 471 472 func (enc *jsonEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) } 473 func (enc *jsonEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) } 474 func (enc *jsonEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } 475 func (enc *jsonEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } 476 func (enc *jsonEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } 477 func (enc *jsonEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } 478 func (enc *jsonEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } 479 func (enc *jsonEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } 480 func (enc *jsonEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } 481 func (enc *jsonEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } 482 func (enc *jsonEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } 483 func (enc *jsonEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) } 484 func (enc *jsonEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } 485 func (enc *jsonEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } 486 func (enc *jsonEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } 487 func (enc *jsonEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } 488 func (enc *jsonEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } 489 func (enc *jsonEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } 490 func (enc *jsonEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } 491 func (enc *jsonEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } 492 func (enc *jsonEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } 493 func (enc *jsonEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } 494 func (enc *jsonEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } 495 496 func (enc *jsonEncoder) Clone() zapcore.Encoder { 497 clone := enc.clone() 498 clone.buf.Write(enc.buf.Bytes()) 499 return clone 500 } 501 502 func (enc *jsonEncoder) clone() *jsonEncoder { 503 clone := getJSONEncoder() 504 clone.EncoderConfig = enc.EncoderConfig 505 clone.spaced = enc.spaced 506 clone.openNamespaces = enc.openNamespaces 507 clone.buf = bufferpool.Get() 508 return clone 509 } 510 511 func (enc *jsonEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { 512 final := enc.clone() 513 final.buf.AppendByte('{') 514 515 if final.LevelKey != "" { 516 final.addKey(final.LevelKey) 517 cur := final.buf.Len() 518 final.EncodeLevel(ent.Level, final) 519 if cur == final.buf.Len() { 520 // User-supplied EncodeLevel was a no-op. Fall back to strings to keep 521 // output JSON valid. 522 final.AppendString(ent.Level.String()) 523 } 524 } 525 if final.TimeKey != "" { 526 final.AddTime(final.TimeKey, ent.Time) 527 } 528 if ent.LoggerName != "" && final.NameKey != "" { 529 final.addKey(final.NameKey) 530 cur := final.buf.Len() 531 nameEncoder := final.EncodeName 532 533 // if no name encoder provided, fall back to FullNameEncoder for backwards 534 // compatibility 535 if nameEncoder == nil { 536 nameEncoder = zapcore.FullNameEncoder 537 } 538 539 nameEncoder(ent.LoggerName, final) 540 if cur == final.buf.Len() { 541 // User-supplied EncodeName was a no-op. Fall back to strings to 542 // keep output JSON valid. 543 final.AppendString(ent.LoggerName) 544 } 545 } 546 if ent.Caller.Defined && final.CallerKey != "" { 547 final.addKey(final.CallerKey) 548 cur := final.buf.Len() 549 final.EncodeCaller(ent.Caller, final) 550 if cur == final.buf.Len() { 551 // User-supplied EncodeCaller was a no-op. Fall back to strings to 552 // keep output JSON valid. 553 final.AppendString(ent.Caller.String()) 554 } 555 } 556 if final.MessageKey != "" { 557 final.addKey(enc.MessageKey) 558 final.AppendString(ent.Message) 559 } 560 if enc.buf.Len() > 0 { 561 final.addElementSeparator() 562 final.buf.Write(enc.buf.Bytes()) 563 } 564 addFields(final, fields) 565 final.closeOpenNamespaces() 566 if ent.Stack != "" && final.StacktraceKey != "" { 567 final.AddString(final.StacktraceKey, ent.Stack) 568 } 569 final.buf.AppendByte('}') 570 if final.LineEnding != "" { 571 final.buf.AppendString(final.LineEnding) 572 } else { 573 final.buf.AppendString(zapcore.DefaultLineEnding) 574 } 575 576 ret := final.buf 577 putJSONEncoder(final) 578 return ret, nil 579 } 580 581 func (enc *jsonEncoder) truncate() { 582 enc.buf.Reset() 583 } 584 585 func (enc *jsonEncoder) closeOpenNamespaces() { 586 for i := 0; i < enc.openNamespaces; i++ { 587 enc.buf.AppendByte('}') 588 } 589 } 590 591 func (enc *jsonEncoder) addKey(key string) { 592 enc.addElementSeparator() 593 enc.buf.AppendByte('"') 594 enc.safeAddString(key) 595 enc.buf.AppendByte('"') 596 enc.buf.AppendByte(':') 597 if enc.spaced { 598 enc.buf.AppendByte(' ') 599 } 600 } 601 602 func (enc *jsonEncoder) addElementSeparator() { 603 last := enc.buf.Len() - 1 604 if last < 0 { 605 return 606 } 607 switch enc.buf.Bytes()[last] { 608 case '{', '[', ':', ',', ' ': 609 return 610 default: 611 enc.buf.AppendByte(',') 612 if enc.spaced { 613 enc.buf.AppendByte(' ') 614 } 615 } 616 } 617 618 func (enc *jsonEncoder) appendFloat(val float64, bitSize int) { 619 enc.addElementSeparator() 620 switch { 621 case math.IsNaN(val): 622 enc.buf.AppendString(`"NaN"`) 623 case math.IsInf(val, 1): 624 enc.buf.AppendString(`"+Inf"`) 625 case math.IsInf(val, -1): 626 enc.buf.AppendString(`"-Inf"`) 627 default: 628 enc.buf.AppendFloat(val, bitSize) 629 } 630 } 631 632 // safeAddString JSON-escapes a string and appends it to the internal buffer. 633 // Unlike the standard library's encoder, it doesn't attempt to protect the 634 // user from browser vulnerabilities or JSONP-related problems. 635 func (enc *jsonEncoder) safeAddString(s string) { 636 for i := 0; i < len(s); { 637 if enc.tryAddRuneSelf(s[i]) { 638 i++ 639 continue 640 } 641 r, size := utf8.DecodeRuneInString(s[i:]) 642 if enc.tryAddRuneError(r, size) { 643 i++ 644 continue 645 } 646 enc.buf.AppendString(s[i : i+size]) 647 i += size 648 } 649 } 650 651 // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. 652 func (enc *jsonEncoder) safeAddByteString(s []byte) { 653 for i := 0; i < len(s); { 654 if enc.tryAddRuneSelf(s[i]) { 655 i++ 656 continue 657 } 658 r, size := utf8.DecodeRune(s[i:]) 659 if enc.tryAddRuneError(r, size) { 660 i++ 661 continue 662 } 663 enc.buf.Write(s[i : i+size]) 664 i += size 665 } 666 } 667 668 // tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte. 669 func (enc *jsonEncoder) tryAddRuneSelf(b byte) bool { 670 if b >= utf8.RuneSelf { 671 return false 672 } 673 if 0x20 <= b && b != '\\' && b != '"' { 674 enc.buf.AppendByte(b) 675 return true 676 } 677 switch b { 678 case '\\', '"': 679 enc.buf.AppendByte('\\') 680 enc.buf.AppendByte(b) 681 case '\n': 682 enc.buf.AppendByte('\\') 683 enc.buf.AppendByte('n') 684 case '\r': 685 enc.buf.AppendByte('\\') 686 enc.buf.AppendByte('r') 687 case '\t': 688 enc.buf.AppendByte('\\') 689 enc.buf.AppendByte('t') 690 default: 691 // Encode bytes < 0x20, except for the escape sequences above. 692 enc.buf.AppendString(`\u00`) 693 enc.buf.AppendByte(_hex[b>>4]) 694 enc.buf.AppendByte(_hex[b&0xF]) 695 } 696 return true 697 } 698 699 func (enc *jsonEncoder) tryAddRuneError(r rune, size int) bool { 700 if r == utf8.RuneError && size == 1 { 701 enc.buf.AppendString(`\ufffd`) 702 return true 703 } 704 return false 705 }