Codebase list golang-github-go-kit-kit / 6335bc2
log: Reuse encoders and buffers for Logfmt logger This uses sync.Pool to avoid always allocating new encoders and buffers. Reduces the number of allocations percall to Log by 2, if a value exists in the pool. Justin Nuß 7 years ago
1 changed file(s) with 35 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
00 package log
11
22 import (
3 "bytes"
34 "io"
5 "sync"
46
57 "github.com/go-logfmt/logfmt"
68 )
9
10 type logfmtEncoder struct {
11 *logfmt.Encoder
12 buf bytes.Buffer
13 }
14
15 func (l *logfmtEncoder) Reset() {
16 l.Encoder.Reset()
17 l.buf.Reset()
18 }
19
20 var logfmtEncoderPool = sync.Pool{
21 New: func() interface{} {
22 var enc logfmtEncoder
23 enc.Encoder = logfmt.NewEncoder(&enc.buf)
24 return &enc
25 },
26 }
727
828 type logfmtLogger struct {
929 w io.Writer
1737 }
1838
1939 func (l logfmtLogger) Log(keyvals ...interface{}) error {
40 enc := logfmtEncoderPool.Get().(*logfmtEncoder)
41 enc.Reset()
42 defer logfmtEncoderPool.Put(enc)
43
44 if err := enc.EncodeKeyvals(keyvals...); err != nil {
45 return err
46 }
47
48 // Add newline to the end of the buffer
49 if err := enc.EndRecord(); err != nil {
50 return err
51 }
52
2053 // The Logger interface requires implementations to be safe for concurrent
2154 // use by multiple goroutines. For this implementation that means making
22 // only one call to l.w.Write() for each call to Log. We first collect all
23 // of the bytes into b, and then call l.w.Write(b).
24 b, err := logfmt.MarshalKeyvals(keyvals...)
25 if err != nil {
26 return err
27 }
28 b = append(b, '\n')
29 if _, err := l.w.Write(b); err != nil {
55 // only one call to l.w.Write() for each call to Log.
56 if _, err := l.w.Write(enc.buf.Bytes()); err != nil {
3057 return err
3158 }
3259 return nil