将Go标准库日志重定向到logrus是否线程安全?
log.SetOutput(gLog.logrus.Writer()) thread-safe? Question
I'm using logrus for structured logging in my Go project, with the following setup:
// Global variable for logging var gLog = &Logger{moduleName: ModuleName, logrus: logrus.New()} type Logger struct { moduleName string logrus *logrus.Logger } func SetupGlobalLogger(logPrefix string, logMode string) error { if logMode == "file" { logFilePath := fmt.Sprintf("var/%s.log", vite.Environment()) file, err := os.OpenFile(logFilePath, logFileFlags, logFilePermission) if err != nil { return err } gLog.logrus.SetOutput(file) // redirect logs written using standard log library to same place as logrus log.SetOutput(gLog.logrus.Writer()) log.Println(vite.MarkInfo, "redirect log to file:", logFilePath) } return nil }
My project uses standard library log statements like log.Println() in many places, which I've redirected to logrus using log.SetOutput(gLog.logrus.Writer()). I'm wondering:
- Is this redirection operation thread-safe?
- Will there be issues when one goroutine executes
log.Println()while another runsgLog.logrus.Info()or other logrus methods?
Answer
Great question! Let's break down the thread safety here step by step:
1. Logrus is inherently thread-safe
The logrus.Logger instance uses an internal sync.Mutex to guard all write operations. Whether you call logrus methods directly (like Info(), Print()) or write to the Writer() returned by the logger, the same mutex will be acquired to ensure only one goroutine is writing logs at a time. This prevents interleaved or corrupted log entries from concurrent logrus calls.
2. The standard log package is also thread-safe
Go's built-in log package has its own internal sync.Mutex that protects operations like Println(). When you redirect its output to logrus's writer, every call to log.Println() will first acquire this standard log mutex before writing to the logrus writer.
3. Concurrent calls to log.Println() and logrus methods are safe
When one goroutine runs log.Println() and another runs gLog.logrus.Info():
- The
log.Println()goroutine will hold the standard log mutex, then call the logrus writer'sWritemethod. This method will in turn acquire logrus's internal mutex to write the log entry. - The
gLog.logrus.Info()goroutine will directly acquire logrus's mutex (waiting if it's already held by the other goroutine).
Since these are two separate mutexes (one from the standard log package, one from logrus), there's no risk of deadlock. All log writes (whether from standard log or direct logrus calls) are ultimately serialized by logrus's mutex, so you won't see messy, interleaved log lines.
A quick note on async logging
If you've configured logrus to use asynchronous hooks or output (e.g., AsyncHook), you'll want to double-check the thread safety of those components. But for the default synchronous setup you've shown, everything is safe.
内容的提问来源于stack exchange,提问作者Yogesh

