@@ -17,6 +17,8 @@ import (
17
17
"sync"
18
18
"sync/atomic"
19
19
"time"
20
+ "unicode"
21
+ "unicode/utf8"
20
22
21
23
"github.com/fatih/color"
22
24
)
@@ -420,7 +422,9 @@ func (l *intLogger) logPlain(t time.Time, name string, level Level, msg string,
420
422
} else {
421
423
l .writer .WriteByte ('=' )
422
424
}
423
- l .writer .WriteString (strconv .Quote (val ))
425
+ l .writer .WriteByte ('"' )
426
+ writeEscapedForOutput (l .writer , val , true )
427
+ l .writer .WriteByte ('"' )
424
428
} else {
425
429
l .writer .WriteByte (' ' )
426
430
l .writer .WriteString (key )
@@ -448,19 +452,98 @@ func writeIndent(w *writer, str string, indent string) {
448
452
if nl == - 1 {
449
453
if str != "" {
450
454
w .WriteString (indent )
451
- w . WriteString ( str )
455
+ writeEscapedForOutput ( w , str , false )
452
456
w .WriteString ("\n " )
453
457
}
454
458
return
455
459
}
456
460
457
461
w .WriteString (indent )
458
- w . WriteString ( str [:nl ])
462
+ writeEscapedForOutput ( w , str [:nl ], false )
459
463
w .WriteString ("\n " )
460
464
str = str [nl + 1 :]
461
465
}
462
466
}
463
467
468
+ func needsEscaping (str string ) bool {
469
+ for _ , b := range str {
470
+ if ! unicode .IsPrint (b ) || b == '"' {
471
+ return true
472
+ }
473
+ }
474
+
475
+ return false
476
+ }
477
+
478
+ const (
479
+ lowerhex = "0123456789abcdef"
480
+ )
481
+
482
+ var bufPool = sync.Pool {
483
+ New : func () interface {} {
484
+ return new (bytes.Buffer )
485
+ },
486
+ }
487
+
488
+ func writeEscapedForOutput (w io.Writer , str string , escapeQuotes bool ) {
489
+ if ! needsEscaping (str ) {
490
+ w .Write ([]byte (str ))
491
+ return
492
+ }
493
+
494
+ bb := bufPool .New ().(* bytes.Buffer )
495
+ bb .Reset ()
496
+
497
+ defer bufPool .Put (bb )
498
+
499
+ for _ , r := range str {
500
+ if escapeQuotes && r == '"' {
501
+ bb .WriteString (`\"` )
502
+ } else if unicode .IsPrint (r ) {
503
+ bb .WriteRune (r )
504
+ } else {
505
+ switch r {
506
+ case '\a' :
507
+ bb .WriteString (`\a` )
508
+ case '\b' :
509
+ bb .WriteString (`\b` )
510
+ case '\f' :
511
+ bb .WriteString (`\f` )
512
+ case '\n' :
513
+ bb .WriteString (`\n` )
514
+ case '\r' :
515
+ bb .WriteString (`\r` )
516
+ case '\t' :
517
+ bb .WriteString (`\t` )
518
+ case '\v' :
519
+ bb .WriteString (`\v` )
520
+ default :
521
+ switch {
522
+ case r < ' ' :
523
+ bb .WriteString (`\x` )
524
+ bb .WriteByte (lowerhex [byte (r )>> 4 ])
525
+ bb .WriteByte (lowerhex [byte (r )& 0xF ])
526
+ case ! utf8 .ValidRune (r ):
527
+ r = 0xFFFD
528
+ fallthrough
529
+ case r < 0x10000 :
530
+ bb .WriteString (`\u` )
531
+ for s := 12 ; s >= 0 ; s -= 4 {
532
+ bb .WriteByte (lowerhex [r >> uint (s )& 0xF ])
533
+ }
534
+ default :
535
+ bb .WriteString (`\U` )
536
+ for s := 28 ; s >= 0 ; s -= 4 {
537
+ bb .WriteByte (lowerhex [r >> uint (s )& 0xF ])
538
+ }
539
+ }
540
+ }
541
+ }
542
+ }
543
+
544
+ w .Write (bb .Bytes ())
545
+ }
546
+
464
547
func (l * intLogger ) renderSlice (v reflect.Value ) string {
465
548
var buf bytes.Buffer
466
549
0 commit comments