Fix data race between logger.Init and GetLogger.
CI / check-and-test (pull_request) Successful in 20s

Copy the global logger pointer under the mutex and publish a fully built instance so concurrent tests and handleConnection logging are race-free.
This commit is contained in:
s1d3sw1ped_bot
2026-08-31 23:56:43 +00:00
parent e12142633a
commit fa89d7c126
+26 -17
View File
@@ -27,28 +27,24 @@ type Config struct {
Compress bool `yaml:"compress"` // compress backup files Compress bool `yaml:"compress"` // compress backup files
} }
// Init initializes the global logger with the given configuration func newLogger(config Config) (*logrus.Logger, error) {
func Init(config Config) error { l := logrus.New()
mu.Lock()
defer mu.Unlock()
Log = logrus.New()
// Set log level // Set log level
level, err := logrus.ParseLevel(config.Level) level, err := logrus.ParseLevel(config.Level)
if err != nil { if err != nil {
level = logrus.InfoLevel level = logrus.InfoLevel
} }
Log.SetLevel(level) l.SetLevel(level)
// Set log format with sanitization // Set log format with sanitization
switch config.Format { switch config.Format {
case "json": case "json":
Log.SetFormatter(&SanitizedJSONFormatter{ l.SetFormatter(&SanitizedJSONFormatter{
TimestampFormat: "2006-01-02 15:04:05", TimestampFormat: "2006-01-02 15:04:05",
}) })
default: default:
Log.SetFormatter(&SanitizedTextFormatter{ l.SetFormatter(&SanitizedTextFormatter{
FullTimestamp: true, FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05", TimestampFormat: "2006-01-02 15:04:05",
}) })
@@ -59,36 +55,49 @@ func Init(config Config) error {
// Ensure directory exists // Ensure directory exists
dir := filepath.Dir(config.File) dir := filepath.Dir(config.File)
if err := os.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0755); err != nil {
return err return nil, err
} }
// Open log file with secure permissions (owner read/write only) // Open log file with secure permissions (owner read/write only)
file, err := os.OpenFile(config.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600) file, err := os.OpenFile(config.File, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
if err != nil { if err != nil {
return err return nil, err
} }
// Set output to both file and stdout // Set output to both file and stdout
Log.SetOutput(io.MultiWriter(file, os.Stdout)) l.SetOutput(io.MultiWriter(file, os.Stdout))
} else { } else {
Log.SetOutput(os.Stdout) l.SetOutput(os.Stdout)
} }
return l, nil
}
// Init initializes the global logger with the given configuration
func Init(config Config) error {
l, err := newLogger(config)
if err != nil {
return err
}
mu.Lock()
Log = l
mu.Unlock()
return nil return nil
} }
// GetLogger returns the global logger instance // GetLogger returns the global logger instance
func GetLogger() *logrus.Logger { func GetLogger() *logrus.Logger {
mu.RLock() mu.RLock()
if Log != nil { l := Log
mu.RUnlock() mu.RUnlock()
return Log if l != nil {
return l
} }
mu.RUnlock()
// Initialize with default config if not already initialized // Initialize with default config if not already initialized
once.Do(func() { once.Do(func() {
Init(Config{ _ = Init(Config{
Level: "info", Level: "info",
Format: "text", Format: "text",
File: "", File: "",