Vastai-ConnectHub/app/core/log_capture.py

83 lines
2.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import logging
from contextlib import contextmanager
from typing import Callable, Iterator
class SafeBufferingHandler(logging.Handler):
"""
只用于“尽力捕获”运行日志:
- emit 内部全 try/except任何异常都吞掉绝不影响任务执行
- 有最大字节限制,超过后写入截断标记并停止追加
"""
def __init__(self, *, max_bytes: int = 200_000, level: int = logging.INFO) -> None:
super().__init__(level=level)
self.max_bytes = max_bytes
self._buf: list[str] = []
self._size_bytes = 0
self._truncated = False
def emit(self, record: logging.LogRecord) -> None: # noqa: D401
try:
if self._truncated:
return
try:
msg = self.format(record)
except Exception:
return
line = msg + "\n"
try:
b = line.encode("utf-8", errors="replace")
except Exception:
return
if self._size_bytes + len(b) > self.max_bytes:
self._buf.append("[TRUNCATED] run_log exceeded max_bytes\n")
self._truncated = True
return
self._buf.append(line)
self._size_bytes += len(b)
except Exception:
# 双保险:任何异常都不能冒泡
return
def get_text(self) -> str:
try:
return "".join(self._buf)
except Exception:
return ""
@contextmanager
def capture_logs(*, max_bytes: int = 200_000) -> Iterator[Callable[[], str]]:
"""
捕获当前进程root logger输出的日志文本。
任何问题都不应影响业务执行。
"""
root = logging.getLogger()
handler = SafeBufferingHandler(max_bytes=max_bytes)
handler.setLevel(logging.INFO)
handler.setFormatter(
logging.Formatter(fmt="%(asctime)s %(levelname)s %(name)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
)
try:
root.addHandler(handler)
except Exception:
# 无法挂载则降级为空
yield lambda: ""
return
try:
yield handler.get_text
finally:
try:
root.removeHandler(handler)
except Exception:
pass