Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkg/log/levels.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
46 changes: 22 additions & 24 deletions pkg/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 {
Expand Down Expand Up @@ -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...) }
12 changes: 6 additions & 6 deletions pkg/log/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,20 @@ 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
// logger at the given level. The returned ObservedLogs can be used to
// 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
}
2 changes: 1 addition & 1 deletion pkg/log/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}

Expand Down
Loading