a
This commit is contained in:
parent
fc128f98b4
commit
3154dd5518
|
|
@ -277,7 +277,8 @@ def parse_supervisor_status(raw: str) -> Tuple[bool, Optional[int], str]:
|
||||||
def tail_supervisor(program: str, stream: str = "stderr", lines: int = 120) -> str:
|
def tail_supervisor(program: str, stream: str = "stderr", lines: int = 120) -> str:
|
||||||
"""
|
"""
|
||||||
读取 supervisor 进程最近日志(stdout/stderr)。
|
读取 supervisor 进程最近日志(stdout/stderr)。
|
||||||
supervisorctl tail -<n> <program> [stdout|stderr]
|
⚠️ 修复:优先直接读取日志文件,避免 XML-RPC 编码错误。
|
||||||
|
如果 supervisorctl tail 失败(编码错误),回退到直接读取文件。
|
||||||
"""
|
"""
|
||||||
s = (stream or "stderr").strip().lower()
|
s = (stream or "stderr").strip().lower()
|
||||||
if s not in {"stdout", "stderr"}:
|
if s not in {"stdout", "stderr"}:
|
||||||
|
|
@ -287,13 +288,38 @@ def tail_supervisor(program: str, stream: str = "stderr", lines: int = 120) -> s
|
||||||
n = 20
|
n = 20
|
||||||
if n > 500:
|
if n > 500:
|
||||||
n = 500
|
n = 500
|
||||||
return run_supervisorctl(["tail", f"-{n}", str(program), s])
|
|
||||||
|
# 优先尝试通过 supervisorctl tail(正常情况)
|
||||||
|
try:
|
||||||
|
return run_supervisorctl(["tail", f"-{n}", str(program), s])
|
||||||
|
except Exception as e:
|
||||||
|
# 如果 supervisorctl tail 失败(可能是编码错误),尝试直接读取日志文件
|
||||||
|
error_msg = str(e)
|
||||||
|
if "UnicodeDecodeError" in error_msg or "utf-8" in error_msg.lower() or "codec" in error_msg.lower():
|
||||||
|
# 尝试从程序名解析 account_id(例如 auto_sys_acc4 -> 4)
|
||||||
|
try:
|
||||||
|
m = re.match(r"^auto_sys_acc(\d+)$", program)
|
||||||
|
if m:
|
||||||
|
account_id = int(m.group(1))
|
||||||
|
project_root = _get_project_root()
|
||||||
|
log_dir, out_log, err_log = expected_trading_log_paths(project_root, account_id)
|
||||||
|
# 根据 stream 选择对应的日志文件
|
||||||
|
log_file = out_log if s == "stdout" else err_log
|
||||||
|
if log_file.exists():
|
||||||
|
# 直接读取文件,使用宽松的编码处理
|
||||||
|
return _tail_text_file(log_file, lines=n)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 如果所有尝试都失败,返回错误信息(但不要抛出异常,避免影响主流程)
|
||||||
|
return f"[读取日志失败: {error_msg}]"
|
||||||
|
|
||||||
|
|
||||||
def _tail_text_file(path: Path, lines: int = 200, max_bytes: int = 64 * 1024) -> str:
|
def _tail_text_file(path: Path, lines: int = 200, max_bytes: int = 64 * 1024) -> str:
|
||||||
"""
|
"""
|
||||||
读取文本文件末尾(用于 supervisor spawn error 等场景,program stderr 可能为空)。
|
读取文本文件末尾(用于 supervisor spawn error 等场景,program stderr 可能为空)。
|
||||||
尽量只读最后 max_bytes,避免大文件占用内存。
|
尽量只读最后 max_bytes,避免大文件占用内存。
|
||||||
|
⚠️ 修复:使用更宽松的编码处理,支持中文等多字节字符。
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
p = Path(path)
|
p = Path(path)
|
||||||
|
|
@ -305,7 +331,21 @@ def _tail_text_file(path: Path, lines: int = 200, max_bytes: int = 64 * 1024) ->
|
||||||
if size > read_size:
|
if size > read_size:
|
||||||
f.seek(-read_size, os.SEEK_END)
|
f.seek(-read_size, os.SEEK_END)
|
||||||
data = f.read()
|
data = f.read()
|
||||||
text = data.decode("utf-8", errors="ignore")
|
|
||||||
|
# ⚠️ 修复:尝试多种编码,优先 UTF-8,失败则尝试常见中文编码
|
||||||
|
text = None
|
||||||
|
encodings = ["utf-8", "gbk", "gb2312", "gb18030", "latin1"]
|
||||||
|
for enc in encodings:
|
||||||
|
try:
|
||||||
|
text = data.decode(enc, errors="strict")
|
||||||
|
break
|
||||||
|
except (UnicodeDecodeError, LookupError):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# 如果所有编码都失败,使用 errors="ignore" 强制解码(会丢失部分字符但不会报错)
|
||||||
|
if text is None:
|
||||||
|
text = data.decode("utf-8", errors="ignore")
|
||||||
|
|
||||||
# 仅保留最后 N 行
|
# 仅保留最后 N 行
|
||||||
parts = text.splitlines()
|
parts = text.splitlines()
|
||||||
if not parts:
|
if not parts:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user