m: WIP on moving the child logic out of mcfg.Cfg and into contexts
This commit is contained in:
parent
5c85969bc7
commit
6c055d0255
73
m/ctx.go
Normal file
73
m/ctx.go
Normal file
@ -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
|
||||||
|
}
|
39
m/ctx_test.go
Normal file
39
m/ctx_test.go
Normal file
@ -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),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
5
m/m.go
5
m/m.go
@ -36,12 +36,13 @@ func CfgSource() mcfg.Source {
|
|||||||
// If the cfg is nil then mlog.DefaultLogger is returned.
|
// If the cfg is nil then mlog.DefaultLogger is returned.
|
||||||
func Log(cfg *mcfg.Cfg, kvs ...mlog.KVer) *mlog.Logger {
|
func Log(cfg *mcfg.Cfg, kvs ...mlog.KVer) *mlog.Logger {
|
||||||
fn := cfg.FullName()
|
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
|
msg.Msg = "(" + fn + ") " + msg.Msg
|
||||||
return mlog.DefaultWriteFn(w, msg)
|
return mlog.DefaultWriteFn(w, msg)
|
||||||
})
|
})
|
||||||
if len(kvs) > 0 {
|
if len(kvs) > 0 {
|
||||||
l = l.WithKV(kvs...)
|
l.AddKV(kvs...)
|
||||||
}
|
}
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user