diff --git a/cmd/totp-proxy/main.go b/cmd/totp-proxy/main.go index c2a6032..7607067 100644 --- a/cmd/totp-proxy/main.go +++ b/cmd/totp-proxy/main.go @@ -29,7 +29,7 @@ import ( ) func main() { - ctx := mctx.New() + ctx := m.NewServiceCtx() logger := mlog.From(ctx) cookieName := mcfg.String(ctx, "cookie-name", "_totp_proxy", "String to use as the name for cookies") cookieTimeout := mcfg.Duration(ctx, "cookie-timeout", mtime.Duration{1 * time.Hour}, "Timeout for cookies") diff --git a/m/m.go b/m/m.go index 4e639a9..23ef500 100644 --- a/m/m.go +++ b/m/m.go @@ -24,11 +24,33 @@ func CfgSource() mcfg.Source { } } -// TODO Create a function, `NewService() mctx.Context` which preloads the -// context with log-level param. Will one day also add debug server. Problem -// comes because mlog isn't quite designed right and setting log-level from -// config won't propagate changes to child contexts which have already called -// mlog.From. +// NewServiceCtx returns a Context which should be used as the root Context when +// creating long running services, such as an RPC service or database. +// +// The returned Context will automatically handle setting up global +// configuration parameters like "log-level", as well as an http endpoint where +// debug information about the running process can be accessed. +// +// TODO set up the debug endpoint. +func NewServiceCtx() mctx.Context { + ctx := mctx.New() + + // set up log level handling + logLevelStr := mcfg.String(ctx, "log-level", "info", "Maximum log level which will be printed.") + mrun.OnStart(ctx, func(mctx.Context) error { + logLevel := mlog.LevelFromString(*logLevelStr) + if logLevel == nil { + return merr.New("invalid log level", "log-level", *logLevelStr) + } + mlog.CtxSetAll(ctx, func(_ mctx.Context, logger *mlog.Logger) *mlog.Logger { + logger.SetMaxLevel(logLevel) + return logger + }) + return nil + }) + + return ctx +} // Run performs the work of populating configuration parameters, triggering the // start event, waiting for an interrupt, and then triggering the stop event. diff --git a/m/m_test.go b/m/m_test.go new file mode 100644 index 0000000..f20288a --- /dev/null +++ b/m/m_test.go @@ -0,0 +1,48 @@ +package m + +import ( + "encoding/json" + . "testing" + + "github.com/mediocregopher/mediocre-go-lib/mcfg" + "github.com/mediocregopher/mediocre-go-lib/mctx" + "github.com/mediocregopher/mediocre-go-lib/mlog" + "github.com/mediocregopher/mediocre-go-lib/mrun" + "github.com/mediocregopher/mediocre-go-lib/mtest/massert" +) + +func TestServiceCtx(t *T) { + t.Run("log-level", func(t *T) { + ctx := NewServiceCtx() + + // pull the Logger out of the ctx and set the Handler on it, so we can check + // the log level + var msgs []mlog.Message + logger := mlog.From(ctx) + logger.SetHandler(func(msg mlog.Message) error { + msgs = append(msgs, msg) + return nil + }) + + // create a child Context before running to ensure it the change propagates + // correctly. + ctxA := mctx.ChildOf(ctx, "A") + + params := mcfg.ParamValues{{Name: "log-level", Value: json.RawMessage(`"DEBUG"`)}} + if err := mcfg.Populate(ctx, params); err != nil { + t.Fatal(err) + } else if err := mrun.Start(ctx); err != nil { + t.Fatal(err) + } + + mlog.From(ctxA).Info("foo") + mlog.From(ctxA).Debug("bar") + massert.Fatal(t, massert.All( + massert.Len(msgs, 2), + massert.Equal(msgs[0].Level.String(), "INFO"), + massert.Equal(msgs[0].Description.String(), "(/A) foo"), + massert.Equal(msgs[1].Level.String(), "DEBUG"), + massert.Equal(msgs[1].Description.String(), "(/A) bar"), + )) + }) +}