Fix data race between logger.Init and GetLogger.
CI / check-and-test (pull_request) Successful in 20s
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:
+26
-17
@@ -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: "",
|
||||||
|
|||||||
Reference in New Issue
Block a user