Skip to content

Commit

Permalink
Copy fields map if it exists in order to not affect parent context
Browse files Browse the repository at this point in the history
  • Loading branch information
deansg committed May 21, 2024
1 parent 47d6f7c commit 891c0e0
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 2 deletions.
14 changes: 12 additions & 2 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,20 @@ func WithValue(parent context.Context, key string, val any) context.Context {
panic("cannot create context from nil parent")
}
if v, ok := parent.Value(fields).(*sync.Map); ok {
v.Store(key, val)
return context.WithValue(parent, fields, v)
mapCopy := copySyncMap(v)
mapCopy.Store(key, val)
return context.WithValue(parent, fields, mapCopy)
}
v := &sync.Map{}
v.Store(key, val)
return context.WithValue(parent, fields, v)
}

func copySyncMap(m *sync.Map) *sync.Map {
var cp sync.Map
m.Range(func(k, v interface{}) bool {
cp.Store(k, v)
return true
})
return &cp
}
27 changes: 27 additions & 0 deletions handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package slogcontext

import (
"context"
"encoding/json"
"io"
"log/slog"
"os"
"strings"
"testing"
)

Expand All @@ -25,6 +27,22 @@ func TestHandler(t *testing.T) {
logger.ErrorContext(ctx, "this is an error")
}

func TestHandler_WithValue_ShouldNotAffectParent(t *testing.T) {
stringBuilder := strings.Builder{}
handler := NewHandler(slog.NewJSONHandler(&stringBuilder, nil))
logger := slog.New(handler)
ctx := WithValue(context.Background(), "k1", "v1")
WithValue(ctx, "k2", "v2")

logger.InfoContext(ctx, "this is an log")

logMessage := jsonToMap(t, stringBuilder.String())
_, ok := logMessage["k2"]
if ok {
t.Errorf("Log message shouldn't contain key added to different context")
}
}

func TestHandlerConcurrent(t *testing.T) {
ctx := WithValue(context.Background(), "number", 12)
ctx = WithValue(ctx, "string", "data")
Expand Down Expand Up @@ -60,3 +78,12 @@ func BenchmarkHandler(b *testing.B) {
logger.ErrorContext(ctx, "this is an error")
}
}

func jsonToMap(t *testing.T, jsonStr string) map[string]any {
result := make(map[string]any)
err := json.Unmarshal([]byte(jsonStr), &result)
if err != nil {
t.Errorf("Failed serializing log message into a map: %v", err)
}
return result
}

0 comments on commit 891c0e0

Please sign in to comment.