#!/usr/bin/env python3 """Summarize LLM_CONNECT_* records from a DeerFlow backend log.""" from __future__ import annotations import argparse import re import sys from pathlib import Path RUN_RE = re.compile(r"run_id=([^ ]+)") VALUE_RE = re.compile(r"(first_chunk_ms|total_ms)=([^ ]+)") def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("log", nargs="?", type=Path, help="Log file; omit to read stdin") args = parser.parse_args() text = args.log.read_text(encoding="utf-8", errors="replace") if args.log else sys.stdin.read() calls: dict[str, dict[str, str]] = {} for line in text.splitlines(): if "LLM_" not in line: continue run_match = RUN_RE.search(line) if not run_match: continue run_id = run_match.group(1) row = calls.setdefault(run_id, {"run_id": run_id, "status": "started"}) if "LLM_CONNECT_OK" in line: row["status"] = "connected" if "LLM_REQUEST_DONE" in line: row["status"] = "success" if "LLM_REQUEST_FAILED" in line: row["status"] = "failed" for key, value in VALUE_RE.findall(line): row[key] = value print("run_id status first_chunk_ms total_ms") for row in calls.values(): print( row["run_id"], row.get("status", "-"), row.get("first_chunk_ms", "-"), row.get("total_ms", "-"), ) succeeded = sum(row.get("status") == "success" for row in calls.values()) failed = sum(row.get("status") == "failed" for row in calls.values()) unfinished = len(calls) - succeeded - failed print(f"SUMMARY calls={len(calls)} success={succeeded} failed={failed} unfinished={unfinished}") return 0 if __name__ == "__main__": raise SystemExit(main())