Source file
src/log/slog/text_handler.go
1
2
3
4
5 package slog
6
7 import (
8 "context"
9 "encoding"
10 "fmt"
11 "io"
12 "reflect"
13 "strconv"
14 "sync"
15 "unicode"
16 "unicode/utf8"
17 )
18
19
20
21 type TextHandler struct {
22 *commonHandler
23 }
24
25
26
27
28 func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler {
29 if opts == nil {
30 opts = &HandlerOptions{}
31 }
32 return &TextHandler{
33 &commonHandler{
34 json: false,
35 w: w,
36 opts: *opts,
37 mu: &sync.Mutex{},
38 },
39 }
40 }
41
42
43
44 func (h *TextHandler) Enabled(_ context.Context, level Level) bool {
45 return h.commonHandler.enabled(level)
46 }
47
48
49
50 func (h *TextHandler) WithAttrs(attrs []Attr) Handler {
51 return &TextHandler{commonHandler: h.commonHandler.withAttrs(attrs)}
52 }
53
54 func (h *TextHandler) WithGroup(name string) Handler {
55 return &TextHandler{commonHandler: h.commonHandler.withGroup(name)}
56 }
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92 func (h *TextHandler) Handle(_ context.Context, r Record) error {
93 return h.commonHandler.handle(r)
94 }
95
96 func appendTextValue(s *handleState, v Value) error {
97 switch v.Kind() {
98 case KindString:
99 s.appendString(v.str())
100 case KindTime:
101 s.appendTime(v.time())
102 case KindAny:
103 if ta, ok := v.any.(encoding.TextAppender); ok {
104 var buf []byte
105 buf, err := ta.AppendText(buf)
106 if err != nil {
107 return err
108 }
109
110 s.appendString(string(buf))
111 return nil
112 } else if tm, ok := v.any.(encoding.TextMarshaler); ok {
113 data, err := tm.MarshalText()
114 if err != nil {
115 return err
116 }
117
118 s.appendString(string(data))
119 return nil
120 }
121 if bs, ok := byteSlice(v.any); ok {
122
123 s.buf.WriteString(strconv.Quote(string(bs)))
124 return nil
125 }
126 s.appendString(fmt.Sprintf("%+v", v.Any()))
127 default:
128 *s.buf = v.append(*s.buf)
129 }
130 return nil
131 }
132
133
134
135
136 func byteSlice(a any) ([]byte, bool) {
137 if bs, ok := a.([]byte); ok {
138 return bs, true
139 }
140
141 t := reflect.TypeOf(a)
142 if t != nil && t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
143 return reflect.ValueOf(a).Bytes(), true
144 }
145 return nil, false
146 }
147
148 func needsQuoting(s string) bool {
149 if len(s) == 0 {
150 return true
151 }
152 for i := 0; i < len(s); {
153 b := s[i]
154 if b < utf8.RuneSelf {
155
156
157 if b != '\\' && (b == ' ' || b == '=' || !safeSet[b]) {
158 return true
159 }
160 i++
161 continue
162 }
163 r, size := utf8.DecodeRuneInString(s[i:])
164 if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {
165 return true
166 }
167 i += size
168 }
169 return false
170 }
171
View as plain text