1package log 2 3import ( 4 "bytes" 5 "io" 6 "sync" 7 8 "github.com/go-logfmt/logfmt" 9) 10 11type logfmtEncoder struct { 12 *logfmt.Encoder 13 buf bytes.Buffer 14} 15 16func (l *logfmtEncoder) Reset() { 17 l.Encoder.Reset() 18 l.buf.Reset() 19} 20 21var logfmtEncoderPool = sync.Pool{ 22 New: func() interface{} { 23 var enc logfmtEncoder 24 enc.Encoder = logfmt.NewEncoder(&enc.buf) 25 return &enc 26 }, 27} 28 29type logfmtLogger struct { 30 w io.Writer 31} 32 33// NewLogfmtLogger returns a logger that encodes keyvals to the Writer in 34// logfmt format. Each log event produces no more than one call to w.Write. 35// The passed Writer must be safe for concurrent use by multiple goroutines if 36// the returned Logger will be used concurrently. 37func NewLogfmtLogger(w io.Writer) Logger { 38 return &logfmtLogger{w} 39} 40 41func (l logfmtLogger) Log(keyvals ...interface{}) error { 42 enc := logfmtEncoderPool.Get().(*logfmtEncoder) 43 enc.Reset() 44 defer logfmtEncoderPool.Put(enc) 45 46 if err := enc.EncodeKeyvals(keyvals...); err != nil { 47 return err 48 } 49 50 // Add newline to the end of the buffer 51 if err := enc.EndRecord(); err != nil { 52 return err 53 } 54 55 // The Logger interface requires implementations to be safe for concurrent 56 // use by multiple goroutines. For this implementation that means making 57 // only one call to l.w.Write() for each call to Log. 58 if _, err := l.w.Write(enc.buf.Bytes()); err != nil { 59 return err 60 } 61 return nil 62} 63