diff --git a/logging/interface.go b/logging/interface.go index 43a49b8..054925a 100644 --- a/logging/interface.go +++ b/logging/interface.go @@ -18,6 +18,7 @@ type LoggerInterface interface { Verbosef(fmt string, msg ...interface{}) WithContext(ctx context.Context) LoggerInterface + AugmentFromContext(ctx context.Context, values ...string) (LoggerInterface, context.Context) } // ParamsFn is a function that returns a slice of interface{} diff --git a/logging/levels.go b/logging/levels.go index 7fbcb0a..017559e 100644 --- a/logging/levels.go +++ b/logging/levels.go @@ -120,6 +120,15 @@ func (l *LevelFilteredLoggerWrapper) WithContext(ctx context.Context) LoggerInte } } +// AugmentFromContext +func (l *LevelFilteredLoggerWrapper) AugmentFromContext(ctx context.Context, values ...string) (LoggerInterface, context.Context) { + extLogger, ctx := l.delegate.AugmentFromContext(ctx, values...) + return &LevelFilteredLoggerWrapper{ + delegate: extLogger, + level: l.level, + }, ctx +} + var _ LoggerInterface = (*LevelFilteredLoggerWrapper)(nil) var levels map[string]int = map[string]int{ diff --git a/logging/levels_test.go b/logging/levels_test.go index dffa30c..8ca0546 100644 --- a/logging/levels_test.go +++ b/logging/levels_test.go @@ -217,6 +217,9 @@ func (l *mockedLogger) Verbose(msg ...interface{}) { l.msgs["Verbose" func (l *mockedLogger) WithContext(ctx context.Context) LoggerInterface { panic("unimplemented") } +func (l *mockedLogger) AugmentFromContext(ctx context.Context, values ...string) (LoggerInterface, context.Context) { + panic("unimplemented") +} func writelog(logger *ExtendedLevelFilteredLoggerWrapper) { logger.ErrorFn("hello %s", func() []interface{} { return []interface{}{"world"} }) diff --git a/logging/logging.go b/logging/logging.go index 5ffc432..af6e714 100644 --- a/logging/logging.go +++ b/logging/logging.go @@ -128,6 +128,21 @@ func (l *Logger) WithContext(ctx context.Context) LoggerInterface { } } +// AugmentFromContext +func (l *Logger) AugmentFromContext(ctx context.Context, values ...string) (LoggerInterface, context.Context) { + if len(values)%2 == 1 { + return nil, nil + } + newContextData := NewContext() + for i := 0; i < len(values); i += 2 { + newContextData = newContextData.WithTag(values[i], values[i+1]) + } + contextData := Merge(l.contextData, newContextData) + ctx = context.WithValue(ctx, ContextKey{}, contextData) + + return l.WithContext(ctx), ctx +} + func normalizeOptions(options *LoggerOptions) *LoggerOptions { var toRet *LoggerOptions if options == nil { diff --git a/logging/logging_test.go b/logging/logging_test.go index e589cab..d384e9b 100644 --- a/logging/logging_test.go +++ b/logging/logging_test.go @@ -6,6 +6,8 @@ import ( "log" "testing" "time" + + "github.com/stretchr/testify/assert" ) func TestLoggerContext(t *testing.T) { @@ -14,6 +16,7 @@ func TestLoggerContext(t *testing.T) { mW := &MockWriter{} mW.On("Write", []byte(fmt.Sprintf("DEBUG - %s test\n", asFormat))).Once().Return(0, nil) mW.On("Write", []byte(fmt.Sprintf("DEBUG - %s [txID=tx] test\n", asFormat))).Once().Return(0, nil) + mW.On("Write", []byte(fmt.Sprintf("DEBUG - %s [orgID=org, txID=tx, userID=user] test\n", asFormat))).Once().Return(0, nil) logger := NewLogger(&LoggerOptions{ StandardLoggerFlags: log.Ldate, LogLevel: LevelVerbose, @@ -30,6 +33,13 @@ func TestLoggerContext(t *testing.T) { bg2 := context.WithValue(bg, ContextKey{}, info) loggerWithContext := logger.WithContext(bg2) loggerWithContext.Debug("test") + + logger, ctx := loggerWithContext.AugmentFromContext(bg2, "orgID", "org", "userID", "user") + logger.Debug("test") + ctxData := ctx.Value(ContextKey{}).(*ContextData) + assert.Equal(t, "org", ctxData.Get("orgID")) + assert.Equal(t, "tx", ctxData.Get("txID")) + assert.Equal(t, "user", ctxData.Get("userID")) } func TestLoggerWrapper(t *testing.T) { diff --git a/logging/mocks.go b/logging/mocks.go index 85ab542..3f1549c 100644 --- a/logging/mocks.go +++ b/logging/mocks.go @@ -67,6 +67,12 @@ func (l *MockLogger) WithContext(ctx context.Context) LoggerInterface { return args.Get(0).(LoggerInterface) } +// AugmentFromContext implements logging.LoggerInterface. +func (l *MockLogger) AugmentFromContext(ctx context.Context, values ...string) (LoggerInterface, context.Context) { + args := l.Called(ctx, values) + return args.Get(0).(LoggerInterface), args.Get(1).(context.Context) +} + type MockWriter struct { mock.Mock }