Skip to content

Commit

Permalink
fix race conditions in scope manager when uninitialized (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
basvanbeek authored Sep 8, 2023
1 parent dd4cb87 commit d763473
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 5 deletions.
22 changes: 17 additions & 5 deletions scope/scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ func (s *scope) With(keyValuePairs ...interface{}) telemetry.Logger {
sc.kvs = append(sc.kvs, k, keyValuePairs[i+1])
}
}
lock.Lock()
uninitialized[s.name] = append(uninitialized[s.name], sc)
lock.Unlock()

return sc
}
Expand All @@ -147,7 +149,9 @@ func (s *scope) Context(ctx context.Context) telemetry.Logger {

sc := s.Clone()
sc.(*scope).ctx = ctx
lock.Lock()
uninitialized[s.name] = append(uninitialized[s.name], sc.(*scope))
lock.Unlock()
return sc
}

Expand All @@ -159,7 +163,9 @@ func (s *scope) Metric(m telemetry.Metric) telemetry.Logger {

sc := s.Clone()
sc.(*scope).metric = m
lock.Lock()
uninitialized[s.name] = append(uninitialized[s.name], sc.(*scope))
lock.Unlock()
return sc
}

Expand Down Expand Up @@ -226,7 +232,7 @@ func Register(name, description string) Scope {
name = strings.ToLower(strings.Trim(name, "\r\n\t "))
sc, ok := scopes[name]
if !ok {
level := int32(DefaultLevel())
level := int32(defaultLevel())
sc = &scope{
name: name,
description: description,
Expand All @@ -249,11 +255,10 @@ func Register(name, description string) Scope {

// Find a scoped logger by its name.
func Find(name string) (Scope, bool) {
lock.Lock()
defer lock.Unlock()

name = strings.ToLower(strings.Trim(name, "\r\n\t "))
lock.Lock()
s, ok := scopes[name]
lock.Unlock()
return s, ok
}

Expand Down Expand Up @@ -303,7 +308,7 @@ func PrintRegistered() {
fmt.Printf("- %-*s [%-5s] %s\n",
pad,
"default",
DefaultLevel().String(),
defaultLevel().String(),
"",
)
for _, n := range names {
Expand Down Expand Up @@ -343,6 +348,13 @@ func SetDefaultLevel(lvl telemetry.Level) {

// DefaultLevel returns the logging level used for new scopes.
func DefaultLevel() telemetry.Level {
lock.Lock()
defer lock.Unlock()

return defaultLevel()
}

func defaultLevel() telemetry.Level {
if defaultLogger != nil {
return defaultLogger.Level()
}
Expand Down
34 changes: 34 additions & 0 deletions scope/scope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,46 @@ import (
"errors"
"fmt"
"io"
"strconv"
"sync"
"testing"

"github.com/tetratelabs/telemetry"
"github.com/tetratelabs/telemetry/function"
)

func TestParallel(t *testing.T) {
logger := Register("root", "root scope")
ctx := context.Background()
wg := sync.WaitGroup{}
routines := 100
wg.Add(4 * routines)
m := &mockMetric{}
for i := 0; i < routines; i++ {
scopeName := strconv.Itoa(i - i%2)
go func() {
l := logger.Context(ctx).Metric(m).With("key", "value")
l.Debug("test log line")
wg.Done()
}()
go func() {
Register(scopeName, "test scope")
wg.Done()
}()
go func() {
lvl := DefaultLevel()
logger.Debug(strconv.Itoa(int(lvl)))
wg.Done()
}()
go func() {
SetDefaultLevel(telemetry.LevelInfo)
wg.Done()
}()
}
wg.Wait()
cleanup()
}

func TestLogger(t *testing.T) {
emitter := func(w io.Writer) function.Emit {
return func(level telemetry.Level, msg string, err error, values function.Values) {
Expand Down

0 comments on commit d763473

Please sign in to comment.