Kaynağa Gözat

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 9 saat önce
ebeveyn
işleme
249b38e156
2 değiştirilmiş dosya ile 18 ekleme ve 8 silme
  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