...
1
2
3
4
5
6
7 package qlog
8
9 import (
10 "bytes"
11 "fmt"
12 "io"
13 "log/slog"
14 "strconv"
15 "sync"
16 "time"
17 )
18
19
20
21
22
23 type jsonWriter struct {
24 mu sync.Mutex
25 w io.WriteCloser
26 buf bytes.Buffer
27 }
28
29
30 func (w *jsonWriter) writeRecordStart() {
31 w.mu.Lock()
32 w.buf.WriteByte(0x1e)
33 w.buf.WriteByte('{')
34 }
35
36
37 func (w *jsonWriter) writeRecordEnd() {
38 w.buf.WriteByte('}')
39 w.buf.WriteByte('\n')
40 w.w.Write(w.buf.Bytes())
41 w.buf.Reset()
42 w.mu.Unlock()
43 }
44
45 func (w *jsonWriter) writeAttrs(attrs []slog.Attr) {
46 w.buf.WriteByte('{')
47 for _, a := range attrs {
48 if a.Key == "" {
49 continue
50 }
51 w.writeAttr(a)
52 }
53 w.buf.WriteByte('}')
54 }
55
56 func (w *jsonWriter) writeAttr(a slog.Attr) {
57 w.writeName(a.Key)
58 w.writeValue(a.Value)
59 }
60
61
62 func (w *jsonWriter) writeAttrsField(name string, attrs []slog.Attr) {
63 w.writeName(name)
64 w.writeAttrs(attrs)
65 }
66
67 func (w *jsonWriter) writeValue(v slog.Value) {
68 v = v.Resolve()
69 switch v.Kind() {
70 case slog.KindAny:
71 switch v := v.Any().(type) {
72 case []slog.Value:
73 w.writeArray(v)
74 case interface{ AppendJSON([]byte) []byte }:
75 w.buf.Write(v.AppendJSON(w.buf.AvailableBuffer()))
76 default:
77 w.writeString(fmt.Sprint(v))
78 }
79 case slog.KindBool:
80 w.writeBool(v.Bool())
81 case slog.KindDuration:
82 w.writeDuration(v.Duration())
83 case slog.KindFloat64:
84 w.writeFloat64(v.Float64())
85 case slog.KindInt64:
86 w.writeInt64(v.Int64())
87 case slog.KindString:
88 w.writeString(v.String())
89 case slog.KindTime:
90 w.writeTime(v.Time())
91 case slog.KindUint64:
92 w.writeUint64(v.Uint64())
93 case slog.KindGroup:
94 w.writeAttrs(v.Group())
95 default:
96 w.writeString("unhandled kind")
97 }
98 }
99
100
101 func (w *jsonWriter) writeName(name string) {
102 if b := w.buf.Bytes(); len(b) > 0 && b[len(b)-1] != '{' {
103
104 w.buf.WriteByte(',')
105 }
106 w.writeString(name)
107 w.buf.WriteByte(':')
108 }
109
110 func (w *jsonWriter) writeObject(f func()) {
111 w.buf.WriteByte('{')
112 f()
113 w.buf.WriteByte('}')
114 }
115
116
117
118 func (w *jsonWriter) writeObjectField(name string, f func()) {
119 w.writeName(name)
120 w.writeObject(f)
121 }
122
123 func (w *jsonWriter) writeArray(vals []slog.Value) {
124 w.buf.WriteByte('[')
125 for i, v := range vals {
126 if i != 0 {
127 w.buf.WriteByte(',')
128 }
129 w.writeValue(v)
130 }
131 w.buf.WriteByte(']')
132 }
133
134 func (w *jsonWriter) writeRaw(v string) {
135 w.buf.WriteString(v)
136 }
137
138
139 func (w *jsonWriter) writeRawField(name, v string) {
140 w.writeName(name)
141 w.writeRaw(v)
142 }
143
144 func (w *jsonWriter) writeBool(v bool) {
145 if v {
146 w.buf.WriteString("true")
147 } else {
148 w.buf.WriteString("false")
149 }
150 }
151
152
153 func (w *jsonWriter) writeBoolField(name string, v bool) {
154 w.writeName(name)
155 w.writeBool(v)
156 }
157
158
159 func (w *jsonWriter) writeDuration(v time.Duration) {
160 if v < 0 {
161 w.buf.WriteByte('-')
162 v = -v
163 }
164 fmt.Fprintf(&w.buf, "%d.%06d", v.Milliseconds(), v%time.Millisecond)
165 }
166
167
168 func (w *jsonWriter) writeDurationField(name string, v time.Duration) {
169 w.writeName(name)
170 w.writeDuration(v)
171 }
172
173 func (w *jsonWriter) writeFloat64(v float64) {
174 w.buf.Write(strconv.AppendFloat(w.buf.AvailableBuffer(), v, 'f', -1, 64))
175 }
176
177
178 func (w *jsonWriter) writeFloat64Field(name string, v float64) {
179 w.writeName(name)
180 w.writeFloat64(v)
181 }
182
183 func (w *jsonWriter) writeInt64(v int64) {
184 w.buf.Write(strconv.AppendInt(w.buf.AvailableBuffer(), v, 10))
185 }
186
187
188 func (w *jsonWriter) writeInt64Field(name string, v int64) {
189 w.writeName(name)
190 w.writeInt64(v)
191 }
192
193 func (w *jsonWriter) writeUint64(v uint64) {
194 w.buf.Write(strconv.AppendUint(w.buf.AvailableBuffer(), v, 10))
195 }
196
197
198 func (w *jsonWriter) writeUint64Field(name string, v uint64) {
199 w.writeName(name)
200 w.writeUint64(v)
201 }
202
203
204 func (w *jsonWriter) writeTime(v time.Time) {
205 fmt.Fprintf(&w.buf, "%d.%06d", v.UnixMilli(), v.Nanosecond()%int(time.Millisecond))
206 }
207
208
209 func (w *jsonWriter) writeTimeField(name string, v time.Time) {
210 w.writeName(name)
211 w.writeTime(v)
212 }
213
214 func jsonSafeSet(c byte) bool {
215
216
217
218
219 const mask = 0 |
220 (1<<(0x22-0x20)-1)<<0x20 |
221 (1<<(0x5c-0x23)-1)<<0x23 |
222 (1<<(0x7f-0x5d)-1)<<0x5d
223 return ((uint64(1)<<c)&(mask&(1<<64-1)) |
224 (uint64(1)<<(c-64))&(mask>>64)) != 0
225 }
226
227 func jsonNeedsEscape(s string) bool {
228 for i := range s {
229 if !jsonSafeSet(s[i]) {
230 return true
231 }
232 }
233 return false
234 }
235
236
237
238
239
240
241 func (w *jsonWriter) writeString(v string) {
242 w.buf.WriteByte('"')
243 if !jsonNeedsEscape(v) {
244 w.buf.WriteString(v)
245 } else {
246 for i := range v {
247 if jsonSafeSet(v[i]) {
248 w.buf.WriteByte(v[i])
249 } else {
250 fmt.Fprintf(&w.buf, `\u%04x`, v[i])
251 }
252 }
253 }
254 w.buf.WriteByte('"')
255 }
256
257
258 func (w *jsonWriter) writeStringField(name, v string) {
259 w.writeName(name)
260 w.writeString(v)
261 }
262
View as plain text