mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-08-30 04:27:40 +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
|