dev
This commit is contained in:
86
domain-api/app/services/logs_service.py
Normal file
86
domain-api/app/services/logs_service.py
Normal 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
|
||||
Reference in New Issue
Block a user