@@ -17,6 +17,8 @@ import (
1717 "sync"
1818 "sync/atomic"
1919 "time"
20+ "unicode"
21+ "unicode/utf8"
2022
2123 "github.com/fatih/color"
2224)
@@ -420,7 +422,9 @@ func (l *intLogger) logPlain(t time.Time, name string, level Level, msg string,
420422 } else {
421423 l .writer .WriteByte ('=' )
422424 }
423- l .writer .WriteString (strconv .Quote (val ))
425+ l .writer .WriteByte ('"' )
426+ writeEscapedForOutput (l .writer , val , true )
427+ l .writer .WriteByte ('"' )
424428 } else {
425429 l .writer .WriteByte (' ' )
426430 l .writer .WriteString (key )
@@ -448,19 +452,98 @@ func writeIndent(w *writer, str string, indent string) {
448452 if nl == - 1 {
449453 if str != "" {
450454 w .WriteString (indent )
451- w . WriteString ( str )
455+ writeEscapedForOutput ( w , str , false )
452456 w .WriteString ("\n " )
453457 }
454458 return
455459 }
456460
457461 w .WriteString (indent )
458- w . WriteString ( str [:nl ])
462+ writeEscapedForOutput ( w , str [:nl ], false )
459463 w .WriteString ("\n " )
460464 str = str [nl + 1 :]
461465 }
462466}
463467
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 .Get ().(* 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+
464547func (l * intLogger ) renderSlice (v reflect.Value ) string {
465548 var buf bytes.Buffer
466549
0 commit comments