fix(exec): guard default logger access

Co-authored-by: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-04-04 07:15:04 +00:00
parent 3ac213a058
commit 588f4e173b
2 changed files with 36 additions and 1 deletions

View file

@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"testing"
"time"
@ -138,6 +139,29 @@ func TestSetDefaultLogger(t *testing.T) {
}
}
func TestDefaultLogger_IsConcurrentSafe(t *testing.T) {
original := exec.DefaultLogger()
defer exec.SetDefaultLogger(original)
logger := &mockLogger{}
var wg sync.WaitGroup
for i := 0; i < 32; i++ {
wg.Add(2)
go func() {
defer wg.Done()
exec.SetDefaultLogger(logger)
}()
go func() {
defer wg.Done()
_ = exec.DefaultLogger()
}()
}
wg.Wait()
assert.NotNil(t, exec.DefaultLogger())
}
func TestCommand_UsesDefaultLogger(t *testing.T) {
original := exec.DefaultLogger()
defer exec.SetDefaultLogger(original)

View file

@ -1,5 +1,7 @@
package exec
import "sync"
// Logger interface for command execution logging.
// Compatible with pkg/log.Logger and other structured loggers.
type Logger interface {
@ -26,7 +28,10 @@ func (NopLogger) Error(string, ...any) {}
var _ Logger = NopLogger{}
var defaultLogger Logger = NopLogger{}
var (
defaultLoggerMu sync.RWMutex
defaultLogger Logger = NopLogger{}
)
// SetDefaultLogger sets the package-level default logger.
// Commands without an explicit logger will use this.
@ -35,6 +40,9 @@ var defaultLogger Logger = NopLogger{}
//
// exec.SetDefaultLogger(logger)
func SetDefaultLogger(l Logger) {
defaultLoggerMu.Lock()
defer defaultLoggerMu.Unlock()
if l == nil {
l = NopLogger{}
}
@ -47,5 +55,8 @@ func SetDefaultLogger(l Logger) {
//
// logger := exec.DefaultLogger()
func DefaultLogger() Logger {
defaultLoggerMu.RLock()
defer defaultLoggerMu.RUnlock()
return defaultLogger
}