diff --git a/pkg/log/levels.go b/pkg/log/levels.go index 9c2b36d0b..55359ae69 100644 --- a/pkg/log/levels.go +++ b/pkg/log/levels.go @@ -14,13 +14,13 @@ const ( // DebugEnabled reports whether debug-level messages are currently logged. func DebugEnabled() bool { - return sugar.Desugar().Core().Enabled(zapcore.DebugLevel) + return sugar.Load().Desugar().Core().Enabled(zapcore.DebugLevel) } // LevelString returns the lowest enabled log level as a lowercase string // (e.g. "debug", "info", "warn", "error", "fatal"). func LevelString() string { - core := sugar.Desugar().Core() + core := sugar.Load().Desugar().Core() for _, l := range []zapcore.Level{ zapcore.DebugLevel, zapcore.InfoLevel, diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 6a3a403fd..d54776534 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -2,18 +2,17 @@ package log import ( "os" + "sync/atomic" "go.uber.org/zap" "go.uber.org/zap/zapcore" "golang.org/x/term" ) -// sugar is the package-level sugared logger. All package functions delegate to it. -var sugar *zap.SugaredLogger +var sugar atomic.Pointer[zap.SugaredLogger] func init() { - // Default: silent until Init() is called. - sugar = zap.NewNop().Sugar() + sugar.Store(zap.NewNop().Sugar()) } // Config holds logger configuration parsed from CLI flags. @@ -35,7 +34,7 @@ func Init(cfg Config) { zap.AddStacktrace(zapcore.FatalLevel), } logger := zap.New(core, opts...) - sugar = logger.Sugar() + sugar.Store(logger.Sugar()) } func resolveLevel(cfg Config) zapcore.Level { @@ -86,30 +85,29 @@ func plainEncoderConfig() zapcore.EncoderConfig { // Underlying returns the raw *zap.Logger for advanced use cases. func Underlying() *zap.Logger { - return sugar.Desugar() + return sugar.Load().Desugar() } // Sync flushes any buffered log entries. Call before process exit. func Sync() error { - return sugar.Desugar().Sync() + return sugar.Load().Desugar().Sync() } // --- Package-level logging functions --- -func Debugf(format string, args ...any) { sugar.Debugf(format, args...) } -func Infof(format string, args ...any) { sugar.Infof(format, args...) } -func Warnf(format string, args ...any) { sugar.Warnf(format, args...) } -func Errorf(format string, args ...any) { sugar.Errorf(format, args...) } -func Fatalf(format string, args ...any) { sugar.Fatalf(format, args...) } - -func Debug(args ...any) { sugar.Debug(args...) } -func Info(args ...any) { sugar.Info(args...) } -func Warn(args ...any) { sugar.Warn(args...) } -func Error(args ...any) { sugar.Error(args...) } -func Fatal(args ...any) { sugar.Fatal(args...) } - -// Structured logging. -func Debugw(msg string, keysAndValues ...any) { sugar.Debugw(msg, keysAndValues...) } -func Infow(msg string, keysAndValues ...any) { sugar.Infow(msg, keysAndValues...) } -func Warnw(msg string, keysAndValues ...any) { sugar.Warnw(msg, keysAndValues...) } -func Errorw(msg string, keysAndValues ...any) { sugar.Errorw(msg, keysAndValues...) } +func Debugf(format string, args ...any) { sugar.Load().Debugf(format, args...) } +func Infof(format string, args ...any) { sugar.Load().Infof(format, args...) } +func Warnf(format string, args ...any) { sugar.Load().Warnf(format, args...) } +func Errorf(format string, args ...any) { sugar.Load().Errorf(format, args...) } +func Fatalf(format string, args ...any) { sugar.Load().Fatalf(format, args...) } + +func Debug(args ...any) { sugar.Load().Debug(args...) } +func Info(args ...any) { sugar.Load().Info(args...) } +func Warn(args ...any) { sugar.Load().Warn(args...) } +func Error(args ...any) { sugar.Load().Error(args...) } +func Fatal(args ...any) { sugar.Load().Fatal(args...) } + +func Debugw(msg string, keysAndValues ...any) { sugar.Load().Debugw(msg, keysAndValues...) } +func Infow(msg string, keysAndValues ...any) { sugar.Load().Infow(msg, keysAndValues...) } +func Warnw(msg string, keysAndValues ...any) { sugar.Load().Warnw(msg, keysAndValues...) } +func Errorw(msg string, keysAndValues ...any) { sugar.Load().Errorw(msg, keysAndValues...) } diff --git a/pkg/log/testing.go b/pkg/log/testing.go index f96a52bbc..8624a1a68 100644 --- a/pkg/log/testing.go +++ b/pkg/log/testing.go @@ -13,10 +13,10 @@ import ( // Log output is captured by t.Log() and only shown on test failure. func InitTest(t testing.TB) { t.Helper() - prev := sugar + prev := sugar.Load() logger := zaptest.NewLogger(t) - sugar = logger.Sugar() - t.Cleanup(func() { sugar = prev }) + sugar.Store(logger.Sugar()) + t.Cleanup(func() { sugar.Store(prev) }) } // InitTestObserved replaces the package-level logger with an observable @@ -24,9 +24,9 @@ func InitTest(t testing.TB) { // assert that specific log messages were emitted. func InitTestObserved(t testing.TB, level zapcore.Level) *observer.ObservedLogs { t.Helper() - prev := sugar + prev := sugar.Load() core, logs := observer.New(level) - sugar = zap.New(core).Sugar() - t.Cleanup(func() { sugar = prev }) + sugar.Store(zap.New(core).Sugar()) + t.Cleanup(func() { sugar.Store(prev) }) return logs } diff --git a/pkg/log/writer.go b/pkg/log/writer.go index ea38950fd..4fa7d7b22 100644 --- a/pkg/log/writer.go +++ b/pkg/log/writer.go @@ -16,7 +16,7 @@ func Writer(level int) io.WriteCloser { return &levelWriter{ sink: w, level: zapLevel, - core: sugar.Desugar().Core(), + core: sugar.Load().Desugar().Core(), } }