mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-05-07 13:52:42 +08:00
85 lines
2.3 KiB
Python
85 lines
2.3 KiB
Python
from __future__ import annotations
|
||
|
||
import io
|
||
import logging
|
||
import sys
|
||
import threading
|
||
from logging.handlers import RotatingFileHandler
|
||
from pathlib import Path
|
||
|
||
|
||
class RotatingLineStream(io.TextIOBase):
|
||
"""
|
||
将 stdout/stderr 按行写入滚动日志文件。
|
||
|
||
这里不复用业务 logger,避免 stdout 日志再次回流到控制台或普通业务日志文件,
|
||
同时保证启动阶段的 print/uvicorn 输出也能按配置滚动。
|
||
"""
|
||
|
||
def __init__(self, log_file: Path, max_bytes: int, backup_count: int):
|
||
super().__init__()
|
||
self._buffer = ""
|
||
self._lock = threading.Lock()
|
||
|
||
logger_name = f"moviepilot-stdio::{log_file}"
|
||
self._logger = logging.getLogger(logger_name)
|
||
self._logger.setLevel(logging.INFO)
|
||
self._logger.propagate = False
|
||
self._logger.handlers.clear()
|
||
|
||
handler = RotatingFileHandler(
|
||
filename=str(log_file),
|
||
maxBytes=max_bytes,
|
||
backupCount=backup_count,
|
||
encoding="utf-8",
|
||
)
|
||
handler.setFormatter(logging.Formatter("%(message)s"))
|
||
self._logger.addHandler(handler)
|
||
|
||
@property
|
||
def encoding(self) -> str:
|
||
return "utf-8"
|
||
|
||
def writable(self) -> bool:
|
||
return True
|
||
|
||
def isatty(self) -> bool:
|
||
return False
|
||
|
||
def write(self, message: str) -> int:
|
||
if not message:
|
||
return 0
|
||
|
||
with self._lock:
|
||
self._buffer += message.replace("\r\n", "\n")
|
||
while "\n" in self._buffer:
|
||
line, self._buffer = self._buffer.split("\n", 1)
|
||
self._logger.info(line)
|
||
return len(message)
|
||
|
||
def flush(self) -> None:
|
||
with self._lock:
|
||
if self._buffer:
|
||
self._logger.info(self._buffer)
|
||
self._buffer = ""
|
||
for handler in self._logger.handlers:
|
||
handler.flush()
|
||
|
||
|
||
def configure_rotating_stdio(
|
||
*, log_file: Path, max_bytes: int, backup_count: int
|
||
) -> RotatingLineStream:
|
||
"""
|
||
将当前进程的 stdout/stderr 统一重定向到同一个滚动日志流。
|
||
"""
|
||
|
||
log_file.parent.mkdir(parents=True, exist_ok=True)
|
||
stream = RotatingLineStream(
|
||
log_file=log_file,
|
||
max_bytes=max_bytes,
|
||
backup_count=backup_count,
|
||
)
|
||
sys.stdout = stream
|
||
sys.stderr = stream
|
||
return stream
|