mlog: redefine KVer to return a map[string]interface, not a KV, to allow other packages to implement KVer without importing mlog

This commit is contained in:
Brian Picciano 2019-01-14 22:32:26 -05:00
parent fe07e1cfdc
commit 1562c4e8f6
6 changed files with 52 additions and 45 deletions

View File

@ -73,8 +73,8 @@ func (pk PublicKey) String() string {
} }
// KV implements the method for the mlog.KVer interface // KV implements the method for the mlog.KVer interface
func (pk PublicKey) KV() mlog.KV { func (pk PublicKey) KV() map[string]interface{} {
return mlog.KV{"publicKey": pk.String()} return map[string]interface{}{"publicKey": pk.String()}
} }
// MarshalText implements the method for the encoding.TextMarshaler interface // MarshalText implements the method for the encoding.TextMarshaler interface
@ -169,8 +169,8 @@ func (pk PrivateKey) String() string {
} }
// KV implements the method for the mlog.KVer interface // KV implements the method for the mlog.KVer interface
func (pk PrivateKey) KV() mlog.KV { func (pk PrivateKey) KV() map[string]interface{} {
return mlog.KV{"privateKey": pk.String()} return map[string]interface{}{"privateKey": pk.String()}
} }
// MarshalText implements the method for the encoding.TextMarshaler interface // MarshalText implements the method for the encoding.TextMarshaler interface

View File

@ -51,8 +51,8 @@ func (s Signature) String() string {
} }
// KV implements the method for the mlog.KVer interface // KV implements the method for the mlog.KVer interface
func (s Signature) KV() mlog.KV { func (s Signature) KV() map[string]interface{} {
return mlog.KV{"sig": s.String()} return map[string]interface{}{"sig": s.String()}
} }
// MarshalText implements the method for the encoding.TextMarshaler interface // MarshalText implements the method for the encoding.TextMarshaler interface

View File

@ -53,8 +53,8 @@ func (u UUID) Time() time.Time {
} }
// KV implements the method for the mlog.KVer interface // KV implements the method for the mlog.KVer interface
func (u UUID) KV() mlog.KV { func (u UUID) KV() map[string]interface{} {
return mlog.KV{"uuid": u.String()} return map[string]interface{}{"uuid": u.String()}
} }
// MarshalText implements the method for the encoding.TextMarshaler interface // MarshalText implements the method for the encoding.TextMarshaler interface

View File

@ -76,26 +76,25 @@ var (
// KVer is used to provide context to a log entry in the form of a dynamic set // KVer is used to provide context to a log entry in the form of a dynamic set
// of key/value pairs which can be different for every entry. // of key/value pairs which can be different for every entry.
// //
// Each returned KV should be modifiable. // Each returned map should be modifiable.
type KVer interface { type KVer interface {
KV() KV KV() map[string]interface{}
} }
// KVerFunc is a function which implements the KVer interface by calling itself. // KVerFunc is a function which implements the KVer interface by calling itself.
type KVerFunc func() KV type KVerFunc func() map[string]interface{}
// KV implements the KVer interface by calling the KVerFunc itself. // KV implements the KVer interface by calling the KVerFunc itself.
func (kvf KVerFunc) KV() KV { func (kvf KVerFunc) KV() map[string]interface{} {
return kvf() return kvf()
} }
// KV is a set of key/value pairs which provides context for a log entry by a // KV is a KVer which returns a copy of itself when KV is called.
// KVer. KV is itself also a KVer.
type KV map[string]interface{} type KV map[string]interface{}
// KV implements the KVer method by returning a copy of the KV // KV implements the KVer method by returning a copy of itself.
func (kv KV) KV() KV { func (kv KV) KV() map[string]interface{} {
nkv := make(KV, len(kv)) nkv := make(map[string]interface{}, len(kv))
for k, v := range kv { for k, v := range kv {
nkv[k] = v nkv[k] = v
} }
@ -110,17 +109,25 @@ func (kv KV) Set(k string, v interface{}) KV {
return nkv return nkv
} }
// returns a key/value map which should not be written to. saves a map-cloning
// if KVer is a KV
func readOnlyKVM(kver KVer) map[string]interface{} {
if kver == nil {
return map[string]interface{}(nil)
} else if kv, ok := kver.(KV); ok {
return map[string]interface{}(kv)
}
return kver.KV()
}
// this may take in any amount of nil values, but should never return nil // this may take in any amount of nil values, but should never return nil
func mergeInto(kv KVer, kvs ...KVer) KV { func mergeInto(kv KVer, kvs ...KVer) map[string]interface{} {
if kv == nil { if kv == nil {
kv = KV(nil) // will return empty map when KV is called on it kv = KV(nil) // will return empty map when KV is called on it
} }
kvm := kv.KV() kvm := kv.KV()
for _, kv := range kvs { for _, innerKV := range kvs {
if kv == nil { for k, v := range readOnlyKVM(innerKV) {
continue
}
for k, v := range kv.KV() {
kvm[k] = v kvm[k] = v
} }
} }
@ -150,20 +157,20 @@ func MergeInto(kv KVer, kvs ...KVer) KVer {
return merger{base: kv, rest: kvs} return merger{base: kv, rest: kvs}
} }
func (m merger) KV() KV { func (m merger) KV() map[string]interface{} {
return mergeInto(m.base, m.rest...) return mergeInto(m.base, m.rest...)
} }
// Prefix prefixes the all keys returned from the given KVer with the given // Prefix prefixes the all keys returned from the given KVer with the given
// prefix string. // prefix string.
func Prefix(kv KVer, prefix string) KVer { func Prefix(kv KVer, prefix string) KVer {
return KVerFunc(func() KV { return KVerFunc(func() map[string]interface{} {
kvv := kv.KV() kvm := readOnlyKVM(kv)
newKVV := make(KV, len(kvv)) newKVM := make(map[string]interface{}, len(kvm))
for k, v := range kvv { for k, v := range kvm {
newKVV[prefix+k] = v newKVM[prefix+k] = v
} }
return newKVV return newKVM
}) })
} }

View File

@ -25,23 +25,23 @@ func TestKV(t *T) {
massert.Len(kv.KV(), 0), massert.Len(kv.KV(), 0),
)) ))
// test that the KV method returns a new KV instance // test that the KV method returns a copy
kv = KV{"foo": "a"} kv = KV{"foo": "a"}
kv2 := kv.KV() kvm := kv.KV()
kv["bur"] = "b" kv["bur"] = "b"
kv2["bar"] = "bb" kvm["bar"] = "bb"
massert.Fatal(t, massert.All( massert.Fatal(t, massert.All(
massert.Equal(KV{"foo": "a", "bur": "b"}, kv), massert.Equal(KV{"foo": "a", "bur": "b"}, kv),
massert.Equal(KV{"foo": "a", "bar": "bb"}, kv2), massert.Equal(map[string]interface{}{"foo": "a", "bar": "bb"}, kvm),
)) ))
// test that the Set method returns a new KV instance // test that the Set method returns a copy
kv = KV{"foo": "a"} kv = KV{"foo": "a"}
kv2 = kv.Set("bar", "wat") kvm = kv.Set("bar", "wat")
kv["bur"] = "ok" kv["bur"] = "ok"
massert.Fatal(t, massert.All( massert.Fatal(t, massert.All(
massert.Equal(KV{"foo": "a", "bur": "ok"}, kv), massert.Equal(KV{"foo": "a", "bur": "ok"}, kv),
massert.Equal(KV{"foo": "a", "bar": "wat"}, kv2), massert.Equal(map[string]interface{}{"foo": "a", "bar": "wat"}, kvm),
)) ))
} }
@ -144,7 +144,7 @@ func TestDefaultFormat(t *T) {
func TestMerge(t *T) { func TestMerge(t *T) {
assertMerge := func(exp KV, kvs ...KVer) massert.Assertion { assertMerge := func(exp KV, kvs ...KVer) massert.Assertion {
return massert.Equal(exp, Merge(kvs...).KV()) return massert.Equal(exp.KV(), Merge(kvs...).KV())
} }
massert.Fatal(t, massert.All( massert.Fatal(t, massert.All(
@ -178,8 +178,8 @@ func TestMerge(t *T) {
kv["a"] = "b" kv["a"] = "b"
massert.Fatal(t, massert.All( massert.Fatal(t, massert.All(
massert.Equal(KV{"a": "b"}, kv), massert.Equal(KV{"a": "b"}, kv),
massert.Equal(KV{"a": "b"}, kv.KV()), massert.Equal(map[string]interface{}{"a": "b"}, kv.KV()),
massert.Equal(KV{"a": "b"}, mergedKV.KV()), massert.Equal(map[string]interface{}{"a": "b"}, mergedKV.KV()),
)) ))
} }
} }
@ -189,8 +189,8 @@ func TestPrefix(t *T) {
prefixKV := Prefix(kv, "aa") prefixKV := Prefix(kv, "aa")
massert.Fatal(t, massert.All( massert.Fatal(t, massert.All(
massert.Equal(kv.KV(), KV{"foo": "bar"}), massert.Equal(map[string]interface{}{"foo": "bar"}, kv.KV()),
massert.Equal(prefixKV.KV(), KV{"aafoo": "bar"}), massert.Equal(map[string]interface{}{"aafoo": "bar"}, prefixKV.KV()),
massert.Equal(kv.KV(), KV{"foo": "bar"}), massert.Equal(map[string]interface{}{"foo": "bar"}, kv.KV()),
)) ))
} }

View File

@ -53,8 +53,8 @@ func MListen(ctx mctx.Context, network, defaultAddr string) net.Listener {
return l return l
} }
func (l *listener) KV() mlog.KV { func (l *listener) KV() map[string]interface{} {
return mlog.KV{"addr": l.Addr().String()} return map[string]interface{}{"addr": l.Addr().String()}
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////