mlog: add Logger.WithKV, slightly change Message type to support it

This commit is contained in:
Brian Picciano 2019-01-12 21:01:00 -05:00
parent 448008cb7c
commit 57db101c02
2 changed files with 35 additions and 9 deletions

View File

@ -186,7 +186,7 @@ func (str String) String() string {
type Message struct { type Message struct {
Level Level
Description Stringer Description Stringer
KV KV KVer
} }
func stringSlice(kv KV) [][2]string { func stringSlice(kv KV) [][2]string {
@ -219,12 +219,14 @@ func DefaultFormat(w io.Writer, msg Message) error {
} }
} }
write("~ %s -- %s", msg.Level.String(), msg.Description.String()) write("~ %s -- %s", msg.Level.String(), msg.Description.String())
if len(msg.KV) > 0 { if msg.KVer != nil {
if kv := msg.KV(); len(kv) > 0 {
write(" --") write(" --")
for _, kve := range stringSlice(msg.KV) { for _, kve := range stringSlice(kv) {
write(" %s=%s", kve[0], kve[1]) write(" %s=%s", kve[0], kve[1])
} }
} }
}
write("\n") write("\n")
return err return err
} }
@ -253,6 +255,7 @@ type Logger struct {
w io.Writer w io.Writer
h Handler h Handler
maxLevel uint maxLevel uint
kv KVer
testMsgWrittenCh chan struct{} // only initialized/used in tests testMsgWrittenCh chan struct{} // only initialized/used in tests
} }
@ -301,6 +304,16 @@ func (l *Logger) WithHandler(h Handler) *Logger {
return l return l
} }
// WithKV returns a copy of the Logger which will use the merging of the given
// KVers as a base KVer for all log messages. If the original Logger already had
// a base KVer (via a previous WithKV call) then this set will be merged onto
// that one.
func (l *Logger) WithKV(kvs ...KVer) *Logger {
l = l.clone()
l.kv = MergeInto(l.kv, kvs...)
return l
}
// Log can be used to manually log a message of some custom defined Level. kvs // Log can be used to manually log a message of some custom defined Level. kvs
// will be Merge'd automatically. If the Level is a fatal (Uint() == 0) then // will be Merge'd automatically. If the Level is a fatal (Uint() == 0) then
// calling this will never return, and the process will have os.Exit(1) called. // calling this will never return, and the process will have os.Exit(1) called.
@ -309,6 +322,10 @@ func (l *Logger) Log(msg Message) {
return return
} }
if l.kv != nil {
msg.KVer = MergeInto(l.kv, msg.KVer)
}
if err := l.h(msg); err != nil { if err := l.h(msg); err != nil {
go l.Error("Logger.Handler returned error", ErrKV(err)) go l.Error("Logger.Handler returned error", ErrKV(err))
return return
@ -327,7 +344,7 @@ func mkMsg(lvl Level, descr string, kvs ...KVer) Message {
return Message{ return Message{
Level: lvl, Level: lvl,
Description: String(descr), Description: String(descr),
KV: Merge(kvs...).KV(), KVer: Merge(kvs...),
} }
} }

View File

@ -101,6 +101,15 @@ func TestLogger(t *T) {
assertOut("~ WARN -- BAZ\n"), assertOut("~ WARN -- BAZ\n"),
assertOut("~ ERROR -- buz\n"), assertOut("~ ERROR -- buz\n"),
)) ))
l3 := l2.WithKV(KV{"a": 1})
l3.Info("foo", KV{"b": 2})
l3.Info("bar", KV{"a": 2, "b": 3})
massert.Fatal(t, massert.All(
assertOut("~ INFO -- FOO -- a=\"1\" b=\"2\"\n"),
assertOut("~ INFO -- BAR -- a=\"2\" b=\"3\"\n"),
))
} }
func TestDefaultFormat(t *T) { func TestDefaultFormat(t *T) {
@ -122,13 +131,13 @@ func TestDefaultFormat(t *T) {
msg := Message{Level: InfoLevel, Description: String("this is a test")} msg := Message{Level: InfoLevel, Description: String("this is a test")}
massert.Fatal(t, assertFormat("INFO -- this is a test", msg)) massert.Fatal(t, assertFormat("INFO -- this is a test", msg))
msg.KV = KV{}.KV() msg.KVer = KV{}
massert.Fatal(t, assertFormat("INFO -- this is a test", msg)) massert.Fatal(t, assertFormat("INFO -- this is a test", msg))
msg.KV = KV{"foo": "a"}.KV() msg.KVer = KV{"foo": "a"}
massert.Fatal(t, assertFormat("INFO -- this is a test -- foo=\"a\"", msg)) massert.Fatal(t, assertFormat("INFO -- this is a test -- foo=\"a\"", msg))
msg.KV = KV{"foo": "a", "bar": "b"}.KV() msg.KVer = KV{"foo": "a", "bar": "b"}
massert.Fatal(t, massert.Fatal(t,
assertFormat("INFO -- this is a test -- bar=\"b\" foo=\"a\"", msg)) assertFormat("INFO -- this is a test -- bar=\"b\" foo=\"a\"", msg))
} }