@@ -268,8 +268,65 @@ our handler makes a single call to `h.out.Write` with the buffer we've accumulat
268
268
We hold the lock for this write to make it atomic with respect to other
269
269
goroutines that may be calling ` Handle ` at the same time.
270
270
271
- TODO(jba): talk about appendAttr
271
+ At the heart of the handler is the ` appendAttr ` method, responsible for
272
+ formatting a single attribute:
272
273
274
+ ```
275
+ func (h *IndentHandler) appendAttr(buf []byte, a slog.Attr, indentLevel int) []byte {
276
+ // Resolve the Attr's value before doing anything else.
277
+ a.Value = a.Value.Resolve()
278
+ // Ignore empty Attrs.
279
+ if a.Equal(slog.Attr{}) {
280
+ return buf
281
+ }
282
+ // Indent 4 spaces per level.
283
+ buf = fmt.Appendf(buf, "%*s", indentLevel*4, "")
284
+ switch a.Value.Kind() {
285
+ case slog.KindString:
286
+ // Quote string values, to make them easy to parse.
287
+ buf = fmt.Appendf(buf, "%s: %q\n", a.Key, a.Value.String())
288
+ case slog.KindTime:
289
+ // Write times in a standard way, without the monotonic time.
290
+ buf = fmt.Appendf(buf, "%s: %s\n", a.Key, a.Value.Time().Format(time.RFC3339Nano))
291
+ case slog.KindGroup:
292
+ attrs := a.Value.Group()
293
+ // Ignore empty groups.
294
+ if len(attrs) == 0 {
295
+ return buf
296
+ }
297
+ // If the key is non-empty, write it out and indent the rest of the attrs.
298
+ // Otherwise, inline the attrs.
299
+ if a.Key != "" {
300
+ buf = fmt.Appendf(buf, "%s:\n", a.Key)
301
+ indentLevel++
302
+ }
303
+ for _, ga := range attrs {
304
+ buf = h.appendAttr(buf, ga, indentLevel)
305
+ }
306
+ default:
307
+ buf = fmt.Appendf(buf, "%s: %s\n", a.Key, a.Value)
308
+ }
309
+ return buf
310
+ }
311
+ ```
312
+
313
+ It begins by resolving the attribute, to run the ` LogValuer.LogValue ` method of
314
+ the value if it has one. All handlers should resolve every attribute they
315
+ process.
316
+
317
+ Next, it follows the handler rule that says that empty attributes should be
318
+ ignored.
319
+
320
+ Then it switches on the attribute kind to determine what format to use. For most
321
+ (the default case of the switch), it relies on ` slog.Value ` 's ` String ` method to
322
+ produce something reasonable. It handles strings and times specially:
323
+ strings by quoting them, and times by formatting them in a standard way.
324
+
325
+ When ` appendAttr ` sees a ` Group ` , it calls itself recursively on the group's
326
+ attributes, after applying two more handler rules.
327
+ First, a group with no attributes is ignored&emdash;not even its key is displayed.
328
+ Second, a group with an empty key is inlined: the group boundary isn't marked in
329
+ any way. In our case, that means the group's attributes aren't indented.
273
330
274
331
## The ` WithAttrs ` method
275
332
0 commit comments