10 kitlog "github.com/go-kit/kit/log"
11 kitlevel "github.com/go-kit/kit/log/level"
12 "github.com/go-logfmt/logfmt"
15 type tmfmtEncoder struct {
20 func (l *tmfmtEncoder) Reset() {
25 var tmfmtEncoderPool = sync.Pool{
26 New: func() interface{} {
28 enc.Encoder = logfmt.NewEncoder(&enc.buf)
33 type tmfmtLogger struct {
37 // NewTMFmtLogger returns a logger that encodes keyvals to the Writer in
38 // Tendermint custom format. Note complex types (structs, maps, slices)
39 // formatted as "%+v".
41 // Each log event produces no more than one call to w.Write.
42 // The passed Writer must be safe for concurrent use by multiple goroutines if
43 // the returned Logger will be used concurrently.
44 func NewTMFmtLogger(w io.Writer) kitlog.Logger {
45 return &tmfmtLogger{w}
48 func (l tmfmtLogger) Log(keyvals ...interface{}) error {
49 enc := tmfmtEncoderPool.Get().(*tmfmtEncoder)
51 defer tmfmtEncoderPool.Put(enc)
53 const unknown = "unknown"
58 // indexes of keys to skip while encoding later
59 excludeIndexes := make([]int, 0)
61 for i := 0; i < len(keyvals)-1; i += 2 {
63 if keyvals[i] == kitlevel.Key() {
64 excludeIndexes = append(excludeIndexes, i)
65 switch keyvals[i+1].(type) {
67 lvl = keyvals[i+1].(string)
69 lvl = keyvals[i+1].(kitlevel.Value).String()
71 panic(fmt.Sprintf("level value of unknown type %T", keyvals[i+1]))
74 } else if keyvals[i] == msgKey {
75 excludeIndexes = append(excludeIndexes, i)
76 msg = keyvals[i+1].(string)
77 // and module (could be multiple keyvals; if such case last keyvalue wins)
78 } else if keyvals[i] == moduleKey {
79 excludeIndexes = append(excludeIndexes, i)
80 module = keyvals[i+1].(string)
84 // Form a custom Tendermint line
87 // D[05-02|11:06:44.322] Stopping AddrBook (ignoring: already stopped)
90 // D - first character of the level, uppercase (ASCII only)
91 // [05-02|11:06:44.322] - our time format (see https://golang.org/src/time/format.go)
92 // Stopping ... - message
93 enc.buf.WriteString(fmt.Sprintf("%c[%s] %-44s ", lvl[0]-32, time.Now().UTC().Format("01-02|15:04:05.000"), msg))
95 if module != unknown {
96 enc.buf.WriteString("module=" + module + " ")
100 for i := 0; i < len(keyvals)-1; i += 2 {
101 for _, j := range excludeIndexes {
103 continue KeyvalueLoop
107 err := enc.EncodeKeyval(keyvals[i], keyvals[i+1])
108 if err == logfmt.ErrUnsupportedValueType {
109 enc.EncodeKeyval(keyvals[i], fmt.Sprintf("%+v", keyvals[i+1]))
110 } else if err != nil {
115 // Add newline to the end of the buffer
116 if err := enc.EndRecord(); err != nil {
120 // The Logger interface requires implementations to be safe for concurrent
121 // use by multiple goroutines. For this implementation that means making
122 // only one call to l.w.Write() for each call to Log.
123 if _, err := l.w.Write(enc.buf.Bytes()); err != nil {