From 2f0bb62903d58e4b4c0265f321b9a505b86d4810 Mon Sep 17 00:00:00 2001 From: obchain Date: Mon, 4 May 2026 12:54:43 +0530 Subject: [PATCH] fix(grafana): source $chain template var from scanner_positions (closes #424) `charon_listener_blocks_received_total` only emits when the listener subcommand runs in `listen` mode. In `replay` mode, the metric is empty so `label_values()` returns nothing, leaving the `$chain` template variable empty. Every panel that filters `chain=~"$chain"` then renders $0 / empty, including the predicted-profit stat panel (line 226) which during today's demo showed $0 even though the underlying metric `charon_executor_profit_usd_cents_sum{chain="bnb"}` correctly reported 3952448 (= $39,524.48). Switch the variable source to `charon_scanner_positions`, a gauge emitted unconditionally on every scanner tick (set in three branches of charon-cli/src/main.rs: empty scan set, fetch_positions failure, and normal path). Replay invokes the same run_block_pipeline that emits these gauges, so `chain="bnb"` is always present on first scrape. Verified against a live replay: profit panel populates at $39,524.48 once `--hold-secs 1800` keeps the exporter alive for Prometheus to scrape. --- deploy/grafana/charon.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deploy/grafana/charon.json b/deploy/grafana/charon.json index 79e4d88..0438ba4 100644 --- a/deploy/grafana/charon.json +++ b/deploy/grafana/charon.json @@ -570,15 +570,15 @@ "allValue": ".*", "current": { "selected": true, "text": "All", "value": "$__all" }, "datasource": { "type": "prometheus", "uid": "${datasource}" }, - "definition": "label_values(charon_listener_blocks_received_total, chain)", - "description": "Chain label. Sourced from the listener counter (#328) — climbs the moment the websocket subscription delivers `new_heads`, so panels populate immediately on connect rather than waiting for the first pipeline tick.", + "definition": "label_values(charon_scanner_positions, chain)", + "description": "Chain label. Sourced from charon_scanner_positions which emits in both listen and replay modes (listener counter only emits in listen). Falls back to allValue=.* if the source is empty.", "hide": 0, "includeAll": true, "label": "Chain", "multi": true, "name": "chain", "options": [], - "query": { "query": "label_values(charon_listener_blocks_received_total, chain)", "refId": "StandardVariableQuery" }, + "query": { "query": "label_values(charon_scanner_positions, chain)", "refId": "StandardVariableQuery" }, "refresh": 2, "regex": "", "skipUrlSync": false,