This commit is contained in:
Your Name
2026-04-16 13:05:07 +08:00
commit 32efff1670
99 changed files with 9974 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
from __future__ import annotations
import json
from datetime import datetime
from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile
from app.core.files import runtime_root, tail_lines
from app.services.detect_service import get_detect_status
from app.services.runtime_status_service import get_runtime_status
from app.services.settings_service import get_settings_payload
def _tail_api_runtime_log(filename: str, max_lines: int = 80) -> list[str]:
path = Path(__file__).resolve().parents[2] / "runtime" / "logs" / filename
if not path.exists():
return []
with path.open("r", encoding="utf-8", errors="replace") as handle:
return handle.read().splitlines()[-max_lines:]
def latest_logs() -> dict:
worker_lines = tail_lines("detect_worker.log", max_lines=80)
desktop_lines = tail_lines("logs/app.log", max_lines=60)
api_stdout_lines = _tail_api_runtime_log("domain-api.stdout.log", max_lines=60)
api_stderr_lines = _tail_api_runtime_log("domain-api.stderr.log", max_lines=60)
api_lines = api_stderr_lines + api_stdout_lines + desktop_lines
summary = "未发现显著异常"
level = "info"
if any("Redis订阅失败" in line for line in worker_lines):
summary = "检测端存在 Redis 订阅读超时重连,需要后续继续优化订阅策略。"
level = "warning"
elif any("无可用代理" in line for line in worker_lines):
summary = "代理池存在无可用代理情况,检测端当前可能回落直连或等待代理。"
level = "warning"
elif any("Traceback" in line or "ERROR:" in line for line in api_lines):
summary = "API 运行日志中发现异常堆栈,请优先检查 domain-api stderr 日志。"
level = "warning"
return {
"worker": worker_lines,
"api": api_lines,
"diagnostics": {
"summary": summary,
"level": level,
},
}
def build_diagnostic_bundle() -> tuple[Path, str]:
payload = latest_logs()
generated_at = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
bundle_dir = runtime_root() / "diagnostics"
bundle_dir.mkdir(parents=True, exist_ok=True)
zip_path = bundle_dir / f"diagnostic_bundle_{timestamp}.zip"
settings_payload = get_settings_payload()
detect_status = get_detect_status()
runtime_status = get_runtime_status()
with ZipFile(zip_path, "w", compression=ZIP_DEFLATED) as archive:
archive.writestr(
"summary.json",
json.dumps(
{
"generated_at": generated_at,
"diagnostics": payload["diagnostics"],
"runtime_status": runtime_status,
"detect_status": detect_status,
},
ensure_ascii=False,
indent=2,
default=str,
),
)
archive.writestr(
"settings_snapshot.json",
json.dumps(settings_payload, ensure_ascii=False, indent=2, default=str),
)
archive.writestr("logs/worker.log", "\n".join(payload["worker"]))
archive.writestr("logs/api.log", "\n".join(payload["api"]))
return zip_path, zip_path.name