log: improve module-oriented logging

To improve the output of module logging, we now include a path that
represents the modules that a context has passed through. This makes it
easy to tell if a log line came from a particular module hierarchy.

A helper function, `WithModule`, provides an easy way to mark a context
with a module and inject that module into the logger.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2016-08-02 16:41:49 -07:00
parent 41aadb3fb0
commit 5288d8f9fe

View file

@ -1,6 +1,8 @@
package log
import (
"path"
"github.com/Sirupsen/logrus"
"golang.org/x/net/context"
)
@ -16,7 +18,10 @@ var (
L = logrus.NewEntry(logrus.StandardLogger())
)
type loggerKey struct{}
type (
loggerKey struct{}
moduleKey struct{}
)
// WithLogger returns a new context with the provided logger. Use in
// combination with logger.WithField(s) for great effect.
@ -35,3 +40,42 @@ func GetLogger(ctx context.Context) *logrus.Entry {
return logger.(*logrus.Entry)
}
// WithModule adds the module to the context, appending it with a slash if a
// module already exists. A module is just an roughly correlated defined by the
// call tree for a given context.
//
// As an example, we might have a "node" module already part of a context. If
// this function is called with "tls", the new value of module will be
// "node/tls".
//
// Modules represent the call path. If the new module and last module are the
// same, a new module entry will not be created. If the new module and old
// older module are the same but separated by other modules, the cycle will be
// represented by the module path.
func WithModule(ctx context.Context, module string) context.Context {
parent := GetModulePath(ctx)
if parent != "" {
// don't re-append module when module is the same.
if path.Base(parent) == module {
return ctx
}
module = path.Join(parent, module)
}
ctx = WithLogger(ctx, GetLogger(ctx).WithField("module", module))
return context.WithValue(ctx, moduleKey{}, module)
}
// GetModulePath returns the module path for the provided context. If no module
// is set, an empty string is returned.
func GetModulePath(ctx context.Context) string {
module := ctx.Value(moduleKey{})
if module == nil {
return ""
}
return module.(string)
}