Skip to content

Commit 35e462c

Browse files
merge fixcontext
2 parents a87a671 + 60f30f8 commit 35e462c

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

log15_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"net"
1010
"regexp"
1111
"runtime"
12+
"sync"
1213
"testing"
1314
"time"
1415
)
@@ -493,3 +494,44 @@ func TestCallerStackHandler(t *testing.T) {
493494
t.Fatalf("Wrong context value, got %s expected string matching %s", s, exp)
494495
}
495496
}
497+
498+
// tests that when logging concurrently to the same logger
499+
// from multiple goroutines that the calls are handled independently
500+
// this test tries to trigger a previous bug where concurrent calls could
501+
// corrupt each other's context values
502+
//
503+
// this test runs N concurrent goroutines each logging a fixed number of
504+
// records and a handler that buckets them based on the index passed in the context.
505+
// if the logger is not concurrent-safe then the values in the buckets will not all be the same
506+
//
507+
// https://github.com/inconshreveable/log15/pull/30
508+
func TestConcurrent(t *testing.T) {
509+
root := New()
510+
// this was the first value that triggered
511+
// go to allocate extra capacity in the logger's context slice which
512+
// was necessary to trigger the bug
513+
const ctxLen = 34
514+
l := root.New(make([]interface{}, ctxLen)...)
515+
const goroutines = 8
516+
var res [goroutines]int
517+
l.SetHandler(SyncHandler(FuncHandler(func(r *Record) error {
518+
res[r.Ctx[ctxLen+1].(int)]++
519+
return nil
520+
})))
521+
var wg sync.WaitGroup
522+
wg.Add(goroutines)
523+
for i := 0; i < goroutines; i++ {
524+
go func(idx int) {
525+
defer wg.Done()
526+
for j := 0; j < 10000; j++ {
527+
l.Info("test message", "goroutine_idx", idx)
528+
}
529+
}(i)
530+
}
531+
wg.Wait()
532+
for _, val := range res[:] {
533+
if val != 10000 {
534+
t.Fatalf("Wrong number of messages for context: %+v", res)
535+
}
536+
}
537+
}

logger.go

+10-2
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
100100
Time: time.Now(),
101101
Lvl: lvl,
102102
Msg: msg,
103-
Ctx: append(l.ctx, normalize(ctx)...),
103+
Ctx: newContext(l.ctx, ctx),
104104
KeyNames: RecordKeyNames{
105105
Time: timeKey,
106106
Msg: msgKey,
@@ -112,11 +112,19 @@ func (l *logger) write(msg string, lvl Lvl, ctx []interface{}) {
112112
}
113113

114114
func (l *logger) New(ctx ...interface{}) Logger {
115-
child := &logger{append(l.ctx, normalize(ctx)...), new(swapHandler)}
115+
child := &logger{newContext(l.ctx, ctx), new(swapHandler)}
116116
child.SetHandler(l.h)
117117
return child
118118
}
119119

120+
func newContext(prefix []interface{}, suffix []interface{}) []interface{} {
121+
normalizedSuffix := normalize(suffix)
122+
newCtx := make([]interface{}, len(prefix)+len(normalizedSuffix))
123+
n := copy(newCtx, prefix)
124+
copy(newCtx[n:], suffix)
125+
return newCtx
126+
}
127+
120128
func (l *logger) Debug(msg string, ctx ...interface{}) {
121129
l.write(msg, LvlDebug, ctx)
122130
}

0 commit comments

Comments
 (0)