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
+27 -18
View File
@@ -27,28 +27,24 @@ type Config struct {
Compress bool `yaml:"compress"` // compress backup files
}
// Init initializes the global logger with the given configuration
func Init(config Config) error {
mu.Lock()
defer mu.Unlock()
Log = logrus.New()
func newLogger(config Config) (*logrus.Logger, error) {
l := logrus.New()
// Set log level
level, err := logrus.ParseLevel(config.Level)
if err != nil {
level = logrus.InfoLevel
}
Log.SetLevel(level)
l.SetLevel(level)
// Set log format with sanitization
switch config.Format {
case "json":
Log.SetFormatter(&SanitizedJSONFormatter{
l.SetFormatter(&SanitizedJSONFormatter{
TimestampFormat: "2006-01-02 15:04:05",
})
default:
Log.SetFormatter(&SanitizedTextFormatter{
l.SetFormatter(&SanitizedTextFormatter{
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
})
@@ -59,36 +55,49 @@ func Init(config Config) error {
// Ensure directory exists
dir := filepath.Dir(config.File)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
return nil, err
}
// 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)
if err != nil {
return err
return nil, err
}
// Set output to both file and stdout
Log.SetOutput(io.MultiWriter(file, os.Stdout))
l.SetOutput(io.MultiWriter(file, os.Stdout))
} 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
}
// GetLogger returns the global logger instance
func GetLogger() *logrus.Logger {
mu.RLock()
if Log != nil {
mu.RUnlock()
return Log
}
l := Log
mu.RUnlock()
if l != nil {
return l
}
// Initialize with default config if not already initialized
once.Do(func() {
Init(Config{
_ = Init(Config{
Level: "info",
Format: "text",
File: "",