From 6c055d0255c16ccfe0fc2ced5780ede9df8d6c80 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Sun, 28 Oct 2018 15:59:49 -0400 Subject: [PATCH] m: WIP on moving the child logic out of mcfg.Cfg and into contexts --- m/ctx.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ m/ctx_test.go | 39 +++++++++++++++++++++++++++ m/m.go | 5 ++-- 3 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 m/ctx.go create mode 100644 m/ctx_test.go diff --git a/m/ctx.go b/m/ctx.go new file mode 100644 index 0000000..279e232 --- /dev/null +++ b/m/ctx.go @@ -0,0 +1,73 @@ +package m + +import ( + "context" + "sync" +) + +type ctxKey int + +const ( + ctxStateKey ctxKey = iota +) + +type ctxState struct { + path []string + l sync.RWMutex + children map[string]context.Context +} + +func newCtxState() *ctxState { + return &ctxState{ + children: map[string]context.Context{}, + } +} + +// Ctx returns a new context which can be used as the root context for all +// purposes in this framework. +func Ctx() context.Context { + return context.WithValue(context.Background(), ctxStateKey, newCtxState()) +} + +func getCtxState(ctx context.Context) *ctxState { + s, _ := ctx.Value(ctxStateKey).(*ctxState) + if s == nil { + panic("non-conforming context used") + } + return s +} + +// Path returns the sequence of names which were used to produce this context +// via the ChildOf function. +func Path(ctx context.Context) []string { + return getCtxState(ctx).path +} + +// Children returns all children of this context which have been created by +// ChildOf, mapped by their name. +func Children(ctx context.Context) map[string]context.Context { + s := getCtxState(ctx) + out := map[string]context.Context{} + s.l.RLock() + defer s.l.RUnlock() + for name, childCtx := range s.children { + out[name] = childCtx + } + return out +} + +// ChildOf creates a child of the given context with the given name and returns +// it. The Path of the returned context will be the path of the parent with its +// name appended to it. The Children function can be called on the parent to +// retrieve all children which have been made using this function. +func ChildOf(ctx context.Context, name string) context.Context { + s, childS := getCtxState(ctx), newCtxState() + s.l.Lock() + defer s.l.Unlock() + childS.path = make([]string, 0, len(s.path)+1) + childS.path = append(childS.path, s.path...) + childS.path = append(childS.path, name) + childCtx := context.WithValue(ctx, ctxStateKey, childS) + s.children[name] = childCtx + return childCtx +} diff --git a/m/ctx_test.go b/m/ctx_test.go new file mode 100644 index 0000000..19b5d69 --- /dev/null +++ b/m/ctx_test.go @@ -0,0 +1,39 @@ +package m + +import ( + "context" + . "testing" + + "github.com/mediocregopher/mediocre-go-lib/mtest/massert" +) + +func TestContext(t *T) { + ctx := Ctx() + ctx1 := ChildOf(ctx, "1") + ctx1a := ChildOf(ctx1, "a") + ctx1b := ChildOf(ctx1, "b") + ctx2 := ChildOf(ctx, "2") + + massert.Fatal(t, massert.All( + massert.Len(Path(ctx), 0), + massert.Equal(Path(ctx1), []string{"1"}), + massert.Equal(Path(ctx1a), []string{"1", "a"}), + massert.Equal(Path(ctx1b), []string{"1", "b"}), + massert.Equal(Path(ctx2), []string{"2"}), + )) + + massert.Fatal(t, massert.All( + massert.Equal( + map[string]context.Context{"1": ctx1, "2": ctx2}, + Children(ctx), + ), + massert.Equal( + map[string]context.Context{"a": ctx1a, "b": ctx1b}, + Children(ctx1), + ), + massert.Equal( + map[string]context.Context{}, + Children(ctx2), + ), + )) +} diff --git a/m/m.go b/m/m.go index e52ad2d..fbe6ef0 100644 --- a/m/m.go +++ b/m/m.go @@ -36,12 +36,13 @@ func CfgSource() mcfg.Source { // If the cfg is nil then mlog.DefaultLogger is returned. func Log(cfg *mcfg.Cfg, kvs ...mlog.KVer) *mlog.Logger { fn := cfg.FullName() - l := mlog.DefaultLogger.WithWriteFn(func(w io.Writer, msg mlog.Message) error { + l := mlog.DefaultLogger.Clone() + l.SetWriteFn(func(w io.Writer, msg mlog.Message) error { msg.Msg = "(" + fn + ") " + msg.Msg return mlog.DefaultWriteFn(w, msg) }) if len(kvs) > 0 { - l = l.WithKV(kvs...) + l.AddKV(kvs...) } return l }