func TestEncodeKeyval(t *testing.T) { data := []struct { key, value interface{} want string err error }{ {key: "k", value: "v", want: "k=v"}, {key: "k", value: nil, want: "k=null"}, {key: `\`, value: "v", want: `\=v`}, {key: "k", value: "", want: "k="}, {key: "k", value: "null", want: `k="null"`}, {key: "k", value: "<nil>", want: `k=<nil>`}, {key: "k", value: true, want: "k=true"}, {key: "k", value: 1, want: "k=1"}, {key: "k", value: 1.025, want: "k=1.025"}, {key: "k", value: 1e-3, want: "k=0.001"}, {key: "k", value: 3.5 + 2i, want: "k=(3.5+2i)"}, {key: "k", value: "v v", want: `k="v v"`}, {key: "k", value: " ", want: `k=" "`}, {key: "k", value: `"`, want: `k="\""`}, {key: "k", value: `=`, want: `k="="`}, {key: "k", value: `\`, want: `k=\`}, {key: "k", value: `=\`, want: `k="=\\"`}, {key: "k", value: `\"`, want: `k="\\\""`}, {key: "k", value: [2]int{2, 19}, err: logfmt.ErrUnsupportedValueType}, {key: "k", value: []string{"e1", "e 2"}, err: logfmt.ErrUnsupportedValueType}, {key: "k", value: structData{"a a", 9}, err: logfmt.ErrUnsupportedValueType}, {key: "k", value: decimalMarshaler{5, 9}, want: "k=5.9"}, {key: "k", value: (*decimalMarshaler)(nil), want: "k=null"}, {key: "k", value: decimalStringer{5, 9}, want: "k=5.9"}, {key: "k", value: (*decimalStringer)(nil), want: "k=null"}, {key: "k", value: marshalerStringer{5, 9}, want: "k=5.9"}, {key: "k", value: (*marshalerStringer)(nil), want: "k=null"}, {key: "k", value: new(nilMarshaler), want: "k=notnilmarshaler"}, {key: "k", value: (*nilMarshaler)(nil), want: "k=nilmarshaler"}, {key: (*marshalerStringer)(nil), value: "v", err: logfmt.ErrNilKey}, {key: decimalMarshaler{5, 9}, value: "v", want: "5.9=v"}, {key: (*decimalMarshaler)(nil), value: "v", err: logfmt.ErrNilKey}, {key: decimalStringer{5, 9}, value: "v", want: "5.9=v"}, {key: (*decimalStringer)(nil), value: "v", err: logfmt.ErrNilKey}, {key: marshalerStringer{5, 9}, value: "v", want: "5.9=v"}, } for _, d := range data { w := &bytes.Buffer{} enc := logfmt.NewEncoder(w) err := enc.EncodeKeyval(d.key, d.value) if err != d.err { t.Errorf("%#v, %#v: got error: %v, want error: %v", d.key, d.value, err, d.err) } if got, want := w.String(), d.want; got != want { t.Errorf("%#v, %#v: got '%s', want '%s'", d.key, d.value, got, want) } } }
func ExampleEncoder() { check := func(err error) { if err != nil { panic(err) } } e := logfmt.NewEncoder(os.Stdout) check(e.EncodeKeyval("id", 1)) check(e.EncodeKeyval("dur", time.Second+time.Millisecond)) check(e.EndRecord()) check(e.EncodeKeyval("id", 1)) check(e.EncodeKeyval("path", "/path/to/file")) check(e.EncodeKeyval("err", errors.New("file not found"))) check(e.EndRecord()) // Output: // id=1 dur=1.001s // id=1 path=/path/to/file err="file not found" }
) type logfmtEncoder struct { *logfmt.Encoder buf bytes.Buffer } func (l *logfmtEncoder) Reset() { l.Encoder.Reset() l.buf.Reset() } var logfmtEncoderPool = sync.Pool{ New: func() interface{} { var enc logfmtEncoder enc.Encoder = logfmt.NewEncoder(&enc.buf) return &enc }, } type logfmtLogger struct { w io.Writer } // NewLogfmtLogger returns a logger that encodes keyvals to the Writer in // logfmt format. Each log event produces no more than one call to w.Write. // The passed Writer must be safe for concurrent use by multiple goroutines if // the returned Logger will be used concurrently. func NewLogfmtLogger(w io.Writer) Logger { return &logfmtLogger{w} }
func NewLogfmt(w io.Writer) *Logfmt { enc := logfmt.NewEncoder(w) return &Logfmt{ enc: enc, } }
// New handler. func New(w io.Writer) *Handler { return &Handler{ enc: logfmt.NewEncoder(w), } }