"""跑 core.toolfail.scan_tool_failures,打印近 N 天工具失败聚集 TOP。 用法:.venv/Scripts/python.exe scripts/diag_toolfail_scan.py [days] [top] """ import os import sys from pathlib import Path env = Path(__file__).resolve().parent.parent / ".env" for line in env.read_text(encoding="utf-8").splitlines(): s = line.strip() if s.startswith("ZCBOT_DB_URL=") and not s.startswith("#"): os.environ["ZCBOT_DB_URL"] = s.split("=", 1)[1].strip() sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from core.toolfail import scan_tool_failures # noqa: E402 days = float(sys.argv[1]) if len(sys.argv) > 1 else 7 top = int(sys.argv[2]) if len(sys.argv) > 2 else 10 # 用低阈值,拿到完整聚集再自己排 —— 巡检默认 min_count=5/min_tasks=2 # scan 内部已按 (count_24h, count) 降序 = 近24h活跃在前 clusters = scan_tool_failures(days=days, min_count=3, min_tasks=1) print(f"近 {days:g} 天:命中 {len(clusters)} 类聚集(阈值 count>=3, tasks>=1)\n") hdr = f"{'#':>2} {'tool':<14} {'kind':<10} {'cnt':>5} {'24h':>4} {'tsk':>4} {'usr':>4} signature" print(hdr) print("-" * len(hdr)) for i, c in enumerate(clusters[:top], 1): print( f"{i:>2} {c['tool'][:14]:<14} {c['kind']:<10} {c['count']:>5} " f"{c['count_24h']:>4} {c['task_count']:>4} {c['user_count']:>4} " f"{c['signature'][:80]}" ) print("\n===== 前 3 聚集详情 =====") for i, c in enumerate(clusters[:3], 1): print(f"\n--- #{i} [{c['tool']}/{c['kind']}] x{c['count']} " f"(近24h {c['count_24h']}, task {c['task_count']}, user {c['user_count']}) ---") print(f" 首次: {c['first_at']} 最近: {c['last_at']}") print(f" daily(旧→新): {c['daily']}") print(f" 签名: {c['signature']}") print(f" 样例: {c['sample'][:500]}")