From ffe36aa28f97f3fc1dd1db7d5ccdbac33d412901 Mon Sep 17 00:00:00 2001 From: Tony Tran Date: Wed, 12 Aug 2026 15:24:15 +0700 Subject: [PATCH] add debug-raw --- usage-dashboard/usage-dashboard.py | 82 ++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/usage-dashboard/usage-dashboard.py b/usage-dashboard/usage-dashboard.py index c1c6f85..d9c4ac0 100644 --- a/usage-dashboard/usage-dashboard.py +++ b/usage-dashboard/usage-dashboard.py @@ -482,6 +482,83 @@ def debug_collect(): client.close() +def debug_raw(count=10, filter_str=""): + """Print raw payloads from the queue without writing to DB — useful for debugging providers like Grok/xAI.""" + import select as _select + cfg = load_config() + channel = cfg.get("queue_channel", "usage") + print(f"[debug-raw] Config: {cfg}", flush=True) + print(f"[debug-raw] Connecting to {cfg['cliproxy_host']}:{cfg['cliproxy_port']} ...", flush=True) + print(f"[debug-raw] Will collect up to {count} events" + (f" matching '{filter_str}'" if filter_str else ""), flush=True) + try: + client = RespClient(cfg["cliproxy_host"], cfg["cliproxy_port"], cfg["management_key"]) + except Exception as e: + print(f"[debug-raw] Connection FAILED: {e}", file=sys.stderr, flush=True) + return + print("[debug-raw] AUTH OK", flush=True) + try: + reply = client.subscribe(channel) + print(f"[debug-raw] SUBSCRIBE {channel!r} → {reply}", flush=True) + print(f"[debug-raw] Waiting for events from CLIProxy (timeout 30s)...", flush=True) + client.sock.settimeout(None) + + received = 0 + shown = 0 + deadline = time.time() + 30 + while shown < count: + remaining = deadline - time.time() + if remaining <= 0: + print(f"[debug-raw] Timeout — received {received} events, shown {shown} matching events.", flush=True) + if shown == 0: + print("[debug-raw] No matching events received. Make a request through CLIProxy and try again.", flush=True) + break + readable, _, _ = _select.select([client.sock], [], [], remaining) + if not readable: + print(f"[debug-raw] Timeout — received {received} events, shown {shown} matching events.", flush=True) + if shown == 0: + print("[debug-raw] No matching events received. Make a request through CLIProxy and try again.", flush=True) + break + data = client.read_message() + if data is None: + continue + # Skip heartbeat + try: + obj = json.loads(data) + if isinstance(obj, dict) and set(obj.keys()) == {"support_refresh"}: + continue + except Exception: + pass + received += 1 + # Apply filter + if filter_str: + try: + payload = json.loads(data) + provider = payload.get("provider", "") + model = payload.get("model", "") + if filter_str.lower() not in provider.lower() and filter_str.lower() not in model.lower(): + continue + except Exception: + pass + shown += 1 + print(f"\n[debug-raw] ===== Event {shown}/{count} (total received: {received}) =====", flush=True) + print(data, flush=True) + try: + payload = json.loads(data) + print(f"[debug-raw] Parsed keys: {list(payload.keys())}", flush=True) + print(f"[debug-raw] provider={payload.get('provider')} model={payload.get('model')} source={payload.get('source')}", flush=True) + tokens = payload.get("tokens") + if tokens: + print(f"[debug-raw] tokens={tokens}", flush=True) + except Exception as e: + print(f"[debug-raw] JSON parse error: {e}", file=sys.stderr, flush=True) + if shown == 0: + print("[debug-raw] No matching events received.", flush=True) + else: + print(f"\n[debug-raw] Finished — showed {shown} matching event(s) out of {received} total ✅", flush=True) + finally: + client.close() + + def collect_forever(): init_db() cfg = load_config() @@ -833,6 +910,9 @@ def main(): sub.add_parser("init", help="Initialise database and config") sub.add_parser("collect", help="Run collector loop (foreground)") sub.add_parser("debug", help="Test one poll cycle, print raw queue items (no DB write)") + debug_raw_p = sub.add_parser("debug-raw", help="Print raw payloads from queue (no DB write) — useful for Grok/xAI debugging") + debug_raw_p.add_argument("--count", type=int, default=10, help="Number of events to show") + debug_raw_p.add_argument("--filter", default="", help="Filter by provider/model substring") sub.add_parser("serve", help="Run HTTP server only (no collector)") start_p = sub.add_parser("start", help="Init + collect + serve in one command (recommended)") start_p.add_argument("--no-browser", action="store_true", help="Do not open browser automatically") @@ -849,6 +929,8 @@ def main(): collect_forever() elif args.cmd == "debug": debug_collect() + elif args.cmd == "debug-raw": + debug_raw(args.count, args.filter) elif args.cmd == "serve": serve() elif args.cmd == "start":