From d5ca3fa894db3618e7397b24cc70d015f898e37b Mon Sep 17 00:00:00 2001 From: Wes Tarle Date: Mon, 9 Mar 2026 12:40:14 -0400 Subject: [PATCH] feat(callctx): pass logger to downstream via context --- v2/callctx/callctx.go | 19 +++++++++++++++++++ v2/callctx/callctx_test.go | 22 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/v2/callctx/callctx.go b/v2/callctx/callctx.go index b28df61d0..60e6cce23 100644 --- a/v2/callctx/callctx.go +++ b/v2/callctx/callctx.go @@ -35,6 +35,7 @@ package callctx import ( "context" "fmt" + "log/slog" ) const ( @@ -125,3 +126,21 @@ func TelemetryFromContext(ctx context.Context, key string) (string, bool) { val, ok := ctx.Value(telemetryKey(key)).(string) return val, ok } + +// loggerKey is a private type used to store/retrieve the logger context value. +type loggerContextKey string + +const loggerCKey = loggerContextKey("logger") + +// WithLogger injects a slog.Logger into the context. This logger will be +// extracted by the client library or transport wrappers to emit logs. +func WithLogger(ctx context.Context, logger *slog.Logger) context.Context { + return context.WithValue(ctx, loggerCKey, logger) +} + +// LoggerFromContext extracts a slog.Logger from the context. +// The returned bool indicates whether a logger was found. +func LoggerFromContext(ctx context.Context) (*slog.Logger, bool) { + logger, ok := ctx.Value(loggerCKey).(*slog.Logger) + return logger, ok +} diff --git a/v2/callctx/callctx_test.go b/v2/callctx/callctx_test.go index bbf9efbc3..c1287500e 100644 --- a/v2/callctx/callctx_test.go +++ b/v2/callctx/callctx_test.go @@ -30,7 +30,9 @@ package callctx import ( + "bytes" "context" + "log/slog" "sync" "testing" @@ -122,3 +124,23 @@ func TestSetHeaders_race(t *testing.T) { } wg.Wait() } + +func TestLoggerFromContext(t *testing.T) { + ctx := context.Background() + + // Should not find a logger in an empty context + l, ok := LoggerFromContext(ctx) + if ok || l != nil { + t.Errorf("LoggerFromContext(ctx) = %v, %v; want nil, false", l, ok) + } + + // Should extract the exact logger that was injected + var logOutput bytes.Buffer + injectedLogger := slog.New(slog.NewTextHandler(&logOutput, nil)) + ctx = WithLogger(ctx, injectedLogger) + + extractedLogger, ok := LoggerFromContext(ctx) + if !ok || extractedLogger != injectedLogger { + t.Errorf("LoggerFromContext(ctx) = %v, %v; want %v, true", extractedLogger, ok, injectedLogger) + } +}