diff options
Diffstat (limited to 'logger/log.go')
-rw-r--r-- | logger/log.go | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/logger/log.go b/logger/log.go new file mode 100644 index 0000000..a47d27d --- /dev/null +++ b/logger/log.go @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: 2020 Ethel Morgan +// +// SPDX-License-Identifier: MIT + +package logger + +import ( + "context" + "fmt" + "sync" + + log "github.com/sirupsen/logrus" +) + +type ( + // log, ctx := logger.FromContext(ctx) + // log.WithField("error", err).Warninging(...) + // log.AddField("transport", udn) + // log.Info(...) + Logger interface { + // AddField adds a field to the current logger. + AddField(name string, value interface{}) + + // WithField forks a logger, adding context. + WithField(name string, value interface{}) Logger + + // WithError is a convenience method for one-off forks to log error messages under the key "error". + WithError(err error) Logger + + // Fork returns a copy of the Logger and a fork of the context.Context to pass through. + Fork(context.Context) (Logger, context.Context) + + Debug(string) + Info(string) + Warning(string) + Error(string) + Fatal(string) + } + + logger struct { + mu sync.Mutex + values map[string]interface{} + } + + // contextKey is a separate type to prevent collisions with other packages. + contextKey int +) + +const ( + loggerKey contextKey = iota +) + +func FromContext(ctx context.Context) (Logger, context.Context) { + maybeLogger := ctx.Value(loggerKey) + + if maybeLogger == nil { + l := Background() + return l, context.WithValue(ctx, loggerKey, l) + } + + if l, ok := maybeLogger.(*logger); ok { + return l, ctx + } + + panic(fmt.Sprintf("expected logger in context, found %+v", maybeLogger)) +} +func Background() Logger { + return &logger{ + values: map[string]interface{}{}, + } +} + +func (l *logger) AddField(name string, value interface{}) { + l.mu.Lock() + defer l.mu.Unlock() + + // TODO: check it doesn't exist already? + l.values[name] = value +} +func (l *logger) WithField(name string, value interface{}) Logger { + clone, _ := l.Fork(context.Background()) + clone.AddField(name, value) + return clone +} +func (l *logger) WithError(err error) Logger { + return l.WithField("error", err) +} + +func (l *logger) Fork(ctx context.Context) (Logger, context.Context) { + l.mu.Lock() + defer l.mu.Unlock() + + clone := &logger{ + values: map[string]interface{}{}, + } + for k, v := range l.values { + clone.values[k] = v + } + return clone, context.WithValue(ctx, loggerKey, clone) +} + +func (l *logger) Debug(message string) { + l.mu.Lock() + defer l.mu.Unlock() + + log.WithFields(log.Fields(l.values)).Debug(message) +} +func (l *logger) Info(message string) { + l.mu.Lock() + defer l.mu.Unlock() + + log.WithFields(log.Fields(l.values)).Info(message) +} +func (l *logger) Warning(message string) { + l.mu.Lock() + defer l.mu.Unlock() + + log.WithFields(log.Fields(l.values)).Warning(message) +} +func (l *logger) Error(message string) { + l.mu.Lock() + defer l.mu.Unlock() + + log.WithFields(log.Fields(l.values)).Error(message) +} +func (l *logger) Fatal(message string) { + l.mu.Lock() + defer l.mu.Unlock() + + log.WithFields(log.Fields(l.values)).Fatal(message) +} |