go 50 lines · 8 steps

Pooling buffers for logfmt encoding in Go

A sync.Pool recycles byte buffers so each log record is built without fresh allocations.

Explained by highlit
1package logfmt
2 
3import (
4 "bytes"
5 "io"
6 "sync"
7)
8 
9var bufferPool = sync.Pool{
10 New: func() any {
11 return new(bytes.Buffer)
12 },
13}
14 
15func getBuffer() *bytes.Buffer {
16 return bufferPool.Get().(*bytes.Buffer)
17}
18 
19func putBuffer(buf *bytes.Buffer) {
20 if buf.Cap() > 64<<10 {
21 return
22 }
23 buf.Reset()
24 bufferPool.Put(buf)
25}
26 
27func WriteRecord(w io.Writer, fields map[string]string) (int, error) {
28 buf := getBuffer()
29 defer putBuffer(buf)
30 
31 first := true
32 for key, value := range fields {
33 if !first {
34 buf.WriteByte(' ')
35 }
36 first = false
37 buf.WriteString(key)
38 buf.WriteByte('=')
39 if bytes.ContainsAny([]byte(value), " \"") {
40 buf.WriteByte('"')
41 buf.WriteString(value)
42 buf.WriteByte('"')
43 } else {
44 buf.WriteString(value)
45 }
46 }
47 buf.WriteByte('\n')
48 
49 return w.Write(buf.Bytes())
50}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1A sync.Pool amortizes allocation cost by reusing temporary objects across calls.
  2. 2Capping the size of returned objects prevents the pool from hoarding oversized buffers.
  3. 3Always reset pooled objects before returning them so stale data never leaks into the next user.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Pooling buffers for logfmt encoding in Go — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code