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
func (pk PublicKey) KV() mlog.KV {
return mlog.KV{"publicKey": pk.String()}
func (pk PublicKey) KV() map[string]interface{} {
return map[string]interface{}{"publicKey": pk.String()}
}
// 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
func (pk PrivateKey) KV() mlog.KV {
return mlog.KV{"privateKey": pk.String()}
func (pk PrivateKey) KV() map[string]interface{} {
return map[string]interface{}{"privateKey": pk.String()}
}
// 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
func (s Signature) KV() mlog.KV {
return mlog.KV{"sig": s.String()}
func (s Signature) KV() map[string]interface{} {
return map[string]interface{}{"sig": s.String()}
}
// 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
func (u UUID) KV() mlog.KV {
return mlog.KV{"uuid": u.String()}
func (u UUID) KV() map[string]interface{} {
return map[string]interface{}{"uuid": u.String()}
}
// 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
// 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 {
KV() KV
KV() map[string]interface{}
}
// 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.
func (kvf KVerFunc) KV() KV {
func (kvf KVerFunc) KV() map[string]interface{} {
return kvf()
}
// KV is a set of key/value pairs which provides context for a log entry by a
// KVer. KV is itself also a KVer.
// KV is a KVer which returns a copy of itself when KV is called.
type KV map[string]interface{}
// KV implements the KVer method by returning a copy of the KV
func (kv KV) KV() KV {
nkv := make(KV, len(kv))
// KV implements the KVer method by returning a copy of itself.
func (kv KV) KV() map[string]interface{} {
nkv := make(map[string]interface{}, len(kv))
for k, v := range kv {
nkv[k] = v
}
@ -110,17 +109,25 @@ func (kv KV) Set(k string, v interface{}) KV {
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
func mergeInto(kv KVer, kvs ...KVer) KV {
func mergeInto(kv KVer, kvs ...KVer) map[string]interface{} {
if kv == nil {
kv = KV(nil) // will return empty map when KV is called on it
}
kvm := kv.KV()
for _, kv := range kvs {
if kv == nil {
continue
}
for k, v := range kv.KV() {
for _, innerKV := range kvs {
for k, v := range readOnlyKVM(innerKV) {
kvm[k] = v
}
}
@ -150,20 +157,20 @@ func MergeInto(kv KVer, kvs ...KVer) KVer {
return merger{base: kv, rest: kvs}
}
func (m merger) KV() KV {
func (m merger) KV() map[string]interface{} {
return mergeInto(m.base, m.rest...)
}
// Prefix prefixes the all keys returned from the given KVer with the given
// prefix string.
func Prefix(kv KVer, prefix string) KVer {
return KVerFunc(func() KV {
kvv := kv.KV()
newKVV := make(KV, len(kvv))
for k, v := range kvv {
newKVV[prefix+k] = v
return KVerFunc(func() map[string]interface{} {
kvm := readOnlyKVM(kv)
newKVM := make(map[string]interface{}, len(kvm))
for k, v := range kvm {
newKVM[prefix+k] = v
}
return newKVV
return newKVM
})
}

View File

@ -25,23 +25,23 @@ func TestKV(t *T) {
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"}
kv2 := kv.KV()
kvm := kv.KV()
kv["bur"] = "b"
kv2["bar"] = "bb"
kvm["bar"] = "bb"
massert.Fatal(t, massert.All(
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"}
kv2 = kv.Set("bar", "wat")
kvm = kv.Set("bar", "wat")
kv["bur"] = "ok"
massert.Fatal(t, massert.All(
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) {
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(
@ -178,8 +178,8 @@ func TestMerge(t *T) {
kv["a"] = "b"
massert.Fatal(t, massert.All(
massert.Equal(KV{"a": "b"}, kv),
massert.Equal(KV{"a": "b"}, kv.KV()),
massert.Equal(KV{"a": "b"}, mergedKV.KV()),
massert.Equal(map[string]interface{}{"a": "b"}, kv.KV()),
massert.Equal(map[string]interface{}{"a": "b"}, mergedKV.KV()),
))
}
}
@ -189,8 +189,8 @@ func TestPrefix(t *T) {
prefixKV := Prefix(kv, "aa")
massert.Fatal(t, massert.All(
massert.Equal(kv.KV(), KV{"foo": "bar"}),
massert.Equal(prefixKV.KV(), KV{"aafoo": "bar"}),
massert.Equal(kv.KV(), KV{"foo": "bar"}),
massert.Equal(map[string]interface{}{"foo": "bar"}, kv.KV()),
massert.Equal(map[string]interface{}{"aafoo": "bar"}, prefixKV.KV()),
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
}
func (l *listener) KV() mlog.KV {
return mlog.KV{"addr": l.Addr().String()}
func (l *listener) KV() map[string]interface{} {
return map[string]interface{}{"addr": l.Addr().String()}
}
////////////////////////////////////////////////////////////////////////////////