mediocre-go-lib/mlog/errctx.go

73 lines
2.0 KiB
Go

package mlog
import (
"context"
"fmt"
"path/filepath"
"github.com/ansel1/merry"
)
type kvKey int
// ErrWithKV embeds the merging of a set of KVs into an error, returning a new
// error instance. If the error already has a KV embedded in it then the
// returned error will have the merging of them all, with the given KVs taking
// precedence.
func ErrWithKV(err error, kvs ...KVer) merry.Error {
if err == nil {
return nil
}
merr := merry.WrapSkipping(err, 1)
var kv KV
if exKV := merry.Value(merr, kvKey(0)); exKV != nil {
kv = mergeInto(exKV.(KV), kvs...)
} else {
kv = Merge(kvs...).KV()
}
return merr.WithValue(kvKey(0), kv)
}
// ErrKV returns a KV which includes the KV embedded in the error by ErrWithKV,
// if any. The KV will also include an "err" field containing the output of
// err.Error(), and an "errSrc" field if the given error is a merry error which
// contains an embedded stacktrace.
func ErrKV(err error) KVer {
var kv KV
if kvi := merry.Value(err, kvKey(0)); kvi != nil {
kv = kvi.(KV)
} else {
kv = KV{}
}
kv["err"] = err.Error()
if fileFull, line := merry.Location(err); fileFull != "" {
file, dir := filepath.Base(fileFull), filepath.Dir(fileFull)
dir = filepath.Base(dir) // only want the first dirname, ie the pkg name
kv["errSrc"] = fmt.Sprintf("%s/%s:%d", dir, file, line)
}
return kv
}
// CtxWithKV embeds a KV into a Context, returning a new Context instance. If
// the Context already has a KV embedded in it then the returned error will have
// the merging of the two, with the given KVs taking precedence.
func CtxWithKV(ctx context.Context, kvs ...KVer) context.Context {
existingKV := ctx.Value(kvKey(0))
var kv KV
if existingKV != nil {
kv = mergeInto(existingKV.(KV), kvs...)
} else {
kv = Merge(kvs...).KV()
}
return context.WithValue(ctx, kvKey(0), kv)
}
// CtxKV returns a copy of the KV embedded in the Context by CtxWithKV
func CtxKV(ctx context.Context) KVer {
kv := ctx.Value(kvKey(0))
if kv == nil {
return KV{}
}
return kv.(KV)
}