Skip to content

Commit 4eb92d9

Browse files
committed
fix logger rotation
1 parent 0eead15 commit 4eb92d9

1 file changed

Lines changed: 50 additions & 4 deletions

File tree

utils/logger_helper.py

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,52 @@ def trace(self, message, *args, **kws):
2929

3030
class WindowsSafeRotatingFileHandler(RotatingFileHandler):
3131
"""A RotatingFileHandler that handles Windows file locking gracefully."""
32+
33+
def shouldRollover(self, record):
34+
retry_after = getattr(self, "_rollover_retry_after", 0)
35+
if retry_after and time.monotonic() < retry_after:
36+
return False
37+
return super().shouldRollover(record)
38+
39+
def _rollover_to_timestamped_file(self):
40+
if getattr(self, "stream", None) is not None:
41+
try:
42+
self.stream.close()
43+
finally:
44+
self.stream = None
45+
46+
if not os.path.exists(self.baseFilename):
47+
self.stream = self._open()
48+
return None
49+
50+
timestamp = int(time.time() * 1000)
51+
fallback_path = f"{self.baseFilename}.{timestamp}.rollover"
52+
suffix = 1
53+
while os.path.exists(fallback_path):
54+
fallback_path = f"{self.baseFilename}.{timestamp}.{suffix}.rollover"
55+
suffix += 1
56+
57+
self.rotate(self.baseFilename, fallback_path)
58+
if not self.delay:
59+
self.stream = self._open()
60+
return fallback_path
3261

3362
def doRollover(self):
3463
"""Perform rollover with retry logic for Windows file locking issues."""
3564
if sys.platform != "win32":
3665
return super().doRollover()
3766

3867
max_retries = 3
68+
_last_err = None
3969
for attempt in range(max_retries):
4070
try:
4171
super().doRollover()
72+
self._rollover_retry_after = 0
4273
return
43-
except PermissionError:
74+
except PermissionError as _perm_err:
75+
_last_err = _perm_err
4476
if attempt < max_retries - 1:
45-
import time
46-
time.sleep(0.1)
77+
time.sleep(0.1 * (attempt + 1))
4778
except Exception as _other_err:
4879
_last_err = _other_err
4980
# Non-permission errors on Windows usually mean a stuck
@@ -63,6 +94,21 @@ def doRollover(self):
6394
)
6495
except Exception:
6596
pass
97+
try:
98+
fallback_path = self._rollover_to_timestamped_file()
99+
if fallback_path:
100+
self._rollover_retry_after = 0
101+
try:
102+
sys.stderr.write(
103+
f"[WindowsSafeRotatingFileHandler] fallback rollover "
104+
f"used {fallback_path!r} for {self.baseFilename!r}\n"
105+
)
106+
except Exception:
107+
pass
108+
return
109+
except Exception as _fallback_err:
110+
_last_err = _fallback_err
111+
66112
# All retries failed. The stock RotatingFileHandler.doRollover
67113
# closes `self.stream` BEFORE attempting the rename, so a failed
68114
# rotation leaves the handler with a closed FD. Subsequent
@@ -72,7 +118,7 @@ def doRollover(self):
72118
# went dark while the app kept running for several more minutes.
73119
# Make the failure visible AND guarantee we keep a live stream,
74120
# even if that means appending to the already-oversized file.
75-
_last_err = locals().get("_last_err", None)
121+
self._rollover_retry_after = time.monotonic() + 30.0
76122
try:
77123
sys.stderr.write(
78124
f"[WindowsSafeRotatingFileHandler] rollover FAILED for "

0 commit comments

Comments
 (0)