Skip to content

Instantly share code, notes, and snippets.

@melekes
Created April 22, 2020 10:37
Show Gist options
  • Save melekes/9e33d14073559db425662aa5e84e3b23 to your computer and use it in GitHub Desktop.
Save melekes/9e33d14073559db425662aa5e84e3b23 to your computer and use it in GitHub Desktop.
package log
import (
"fmt"
"io"
stdlog "log"
"strings"
)
type stdlibLogger struct {
next *stdlog.Logger
keyvals []interface{}
}
// Interface assertions
var _ Logger = (*stdlibLogger)(nil)
// NewStdLibLogger returns a logger that encodes msg and keyvals to the Writer
// using standard library log as an underlying logger.
func NewStdLibLogger(w io.Writer, prefix string, flag int) Logger {
return &stdlibLogger{
next: stdlog.New(w, prefix, flag),
keyvals: make([]interface{}, 0),
}
}
// Info logs a message at level Info.
func (l *stdlibLogger) Info(msg string, keyvals ...interface{}) {
l.logf("info: ", msg, keyvals...)
}
// Debug logs a message at level Debug.
func (l *stdlibLogger) Debug(msg string, keyvals ...interface{}) {
l.logf("debug: ", msg, keyvals...)
}
// Error logs a message at level Error.
func (l *stdlibLogger) Error(msg string, keyvals ...interface{}) {
l.logf("error: ", msg, keyvals...)
}
// With returns a new contextual logger with keyvals prepended to those passed
// to calls to Info, Debug or Error.
func (l *stdlibLogger) With(keyvals ...interface{}) Logger {
return &stdlibLogger{
next: l.next,
keyvals: append(keyvals, l.keyvals...),
}
}
func (l *stdlibLogger) logf(prefix, msg string, keyvals ...interface{}) {
// join keyvals
var b strings.Builder
for i := 0; i < len(l.keyvals); i += 2 {
fmt.Fprintf(&b, " %v=%v", l.keyvals[i], l.keyvals[i+1])
}
for i := 0; i < len(keyvals); i += 2 {
fmt.Fprintf(&b, " %v=%v", keyvals[i], keyvals[i+1])
}
l.next.Printf("%s%s%s\n", prefix, msg, b.String())
}
package log_test
import (
"bytes"
stdlog "log"
"strings"
"testing"
"github.com/tendermint/tendermint/libs/log"
)
func TestStdLibLogger(t *testing.T) {
var buf bytes.Buffer
logger := log.NewStdLibLogger(&buf, "prefix ", stdlog.LstdFlags)
logger.Info("foo", "baz", "bar")
msg := strings.TrimSpace(buf.String())
if !strings.Contains(msg, "info: foo baz=bar") {
t.Errorf("expected logger to contain log level, msg, and keyvals, got %s", msg)
}
if !strings.Contains(msg, "prefix ") {
t.Errorf("expected logger to contain prefix, got %s", msg)
}
buf.Reset()
logger.Debug("foo", "baz", "bar")
msg = strings.TrimSpace(buf.String())
if !strings.Contains(msg, "debug: foo baz=bar") {
t.Errorf("expected logger to contain log level, msg, and keyvals, got %s", msg)
}
buf.Reset()
logger.Error("foo", "baz", "bar")
msg = strings.TrimSpace(buf.String())
if !strings.Contains(msg, "error: foo baz=bar") {
t.Errorf("expected logger to contain log level, msg, and keyvals, got %s", msg)
}
buf.Reset()
logger2 := logger.With("module", "devs")
logger2.Error("foo", "baz", "bar")
msg = strings.TrimSpace(buf.String())
if !strings.Contains(msg, "error: foo module=devs baz=bar") {
t.Errorf("expected logger to contain log level, msg, and keyvals, got %s", msg)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment