浏览代码

fix(logger): reuse the open log rotator when InitLogger runs again

Every InitLogger call built a new lumberjack rotator and dropped the old
one without closing it, leaking a handle on 3xui.log per call, and
loggers still writing through an old rotator kept it alive. On Windows
the open handles block deleting the file, so
TestInitLoggerConcurrentWithLogging failed its t.TempDir cleanup there.
InitLogger now reuses the open rotator for the same path and closes it
only when the path changes, and the test closes the logger it opened.
Neither half is enough alone: with only one of them the test stays red
on Windows.
MHSanaei 7 小时之前
父节点
当前提交
249b38e156
共有 2 个文件被更改,包括 18 次插入 和 8 次删除
  1. 17 8
      internal/logger/logger.go
  2. 1 0
      internal/logger/logger_test.go

+ 17 - 8
internal/logger/logger.go

@@ -93,8 +93,22 @@ func initFileBackend() logging.Backend {
 		return nil
 	}
 
-	logPath := filepath.Join(logDir, logFileName)
-	rotate := &lumberjack.Logger{
+	backend := logging.NewLogBackend(fileRotateFor(filepath.Join(logDir, logFileName)), "", 0)
+	return logging.NewBackendFormatter(backend, newFormatter(true))
+}
+
+// fileRotateFor reuses the open rotator for logPath: a re-init that swapped in a
+// new one would leave the old one holding the file, and loggers still writing to it.
+func fileRotateFor(logPath string) *lumberjack.Logger {
+	fileRotateMu.Lock()
+	defer fileRotateMu.Unlock()
+	if fileRotate != nil && fileRotate.Filename == logPath {
+		return fileRotate
+	}
+	if fileRotate != nil {
+		_ = fileRotate.Close()
+	}
+	fileRotate = &lumberjack.Logger{
 		Filename:   logPath,
 		MaxSize:    maxLogFileMB,
 		MaxBackups: maxLogBackups,
@@ -102,12 +116,7 @@ func initFileBackend() logging.Backend {
 		LocalTime:  true,
 		Compress:   compressRotated,
 	}
-	fileRotateMu.Lock()
-	fileRotate = rotate
-	fileRotateMu.Unlock()
-
-	backend := logging.NewLogBackend(rotate, "", 0)
-	return logging.NewBackendFormatter(backend, newFormatter(true))
+	return fileRotate
 }
 
 // newFormatter creates a log formatter with optional timestamp.

+ 1 - 0
internal/logger/logger_test.go

@@ -36,6 +36,7 @@ func TestGetLogs_ReturnsAtMostC(t *testing.T) {
 // logging — CI caught that as a data race between InitLogger and Warningf.
 func TestInitLoggerConcurrentWithLogging(t *testing.T) {
 	t.Setenv("XUI_LOG_FOLDER", t.TempDir())
+	t.Cleanup(CloseLogger)
 
 	stop := make(chan struct{})
 	var logging sync.WaitGroup