Skip to content

Commit 1218917

Browse files
committed
fix: loggers created with With() now inherit level changes on the parent
With() copies the Logger struct by value, which gave the wrapped logger its own independent int64 for the log level. Subsequent SetLevel calls on the parent had no effect on any wrapped child. Fix: change the level field to *int64. New loggers allocate a fresh int64; With() copies the pointer, so parent and all children share the same memory cell. SetLevel anywhere in the hierarchy is visible everywhere. Fixes #184
1 parent 4bff402 commit 1218917

5 files changed

Lines changed: 24 additions & 12 deletions

File tree

logger.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type Logger struct {
2929

3030
isDiscard uint32
3131

32-
level int64
32+
level *int64
3333
prefix string
3434
timeFunc TimeFunction
3535
timeFormat string
@@ -58,7 +58,7 @@ func (l *Logger) Log(level Level, msg any, keyvals ...any) {
5858
}
5959

6060
// check if the level is allowed
61-
if atomic.LoadInt64(&l.level) > int64(level) {
61+
if atomic.LoadInt64(l.level) > int64(level) {
6262
return
6363
}
6464

@@ -233,16 +233,12 @@ func (l *Logger) SetReportCaller(report bool) {
233233

234234
// GetLevel returns the current level.
235235
func (l *Logger) GetLevel() Level {
236-
l.mu.RLock()
237-
defer l.mu.RUnlock()
238-
return Level(l.level)
236+
return Level(atomic.LoadInt64(l.level))
239237
}
240238

241239
// SetLevel sets the current level.
242240
func (l *Logger) SetLevel(level Level) {
243-
l.mu.Lock()
244-
defer l.mu.Unlock()
245-
atomic.StoreInt64(&l.level, int64(level))
241+
atomic.StoreInt64(l.level, int64(level))
246242
}
247243

248244
// GetPrefix returns the current prefix.

logger_121.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const slogKindGroup = slog.KindGroup
2424
//
2525
// Implements slog.Handler.
2626
func (l *Logger) Enabled(_ context.Context, level slog.Level) bool {
27-
return atomic.LoadInt64(&l.level) <= int64(level)
27+
return atomic.LoadInt64(l.level) <= int64(level)
2828
}
2929

3030
// Handle handles the Record. It will only be called if Enabled returns true.

logger_no121.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const slogKindGroup = slog.KindGroup
2525
//
2626
// Implements slog.Handler.
2727
func (l *Logger) Enabled(_ context.Context, level slog.Level) bool {
28-
return atomic.LoadInt64(&l.level) <= int64(level)
28+
return atomic.LoadInt64(l.level) <= int64(level)
2929
}
3030

3131
// Handle handles the Record. It will only be called if Enabled returns true.

logger_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,3 +287,18 @@ func TestCustomLevel(t *testing.T) {
287287
l.Logf(level500, "foo")
288288
assert.Equal(t, "foo\n", buf.String())
289289
}
290+
291+
func TestWithInheritsLevel(t *testing.T) {
292+
var buf bytes.Buffer
293+
l := New(colorprofile.NewWriter(&buf, os.Environ()))
294+
l.SetLevel(InfoLevel)
295+
l.SetReportTimestamp(false)
296+
l.SetReportCaller(false)
297+
298+
wrapped := l.With("k", "v")
299+
300+
// Level raised on parent after wrapped logger created — child must see it.
301+
l.SetLevel(DebugLevel)
302+
wrapped.Debug("debug msg")
303+
assert.Equal(t, "DEBU debug msg k=v\n", buf.String())
304+
}

pkg.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ func New(w io.Writer) *Logger {
4545

4646
// NewWithOptions returns a new logger using the provided options.
4747
func NewWithOptions(w io.Writer, o Options) *Logger {
48+
lvl := int64(o.Level)
4849
l := &Logger{
4950
b: bytes.Buffer{},
5051
mu: &sync.RWMutex{},
5152
helpers: &sync.Map{},
52-
level: int64(o.Level),
53+
level: &lvl,
5354
reportTimestamp: o.ReportTimestamp,
5455
reportCaller: o.ReportCaller,
5556
prefix: o.Prefix,
@@ -64,7 +65,7 @@ func NewWithOptions(w io.Writer, o Options) *Logger {
6465
l.SetOutput(w)
6566
// Detect color profile from the writer and environment.
6667
l.SetColorProfile(colorprofile.Detect(w, os.Environ()))
67-
l.SetLevel(Level(l.level))
68+
l.SetLevel(Level(*l.level))
6869
l.SetStyles(DefaultStyles())
6970

7071
if l.callerFormatter == nil {

0 commit comments

Comments
 (0)