Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXVi2GMQ7bR5EmbUFdDj7N
39 lines
2.1 KiB
Python
Executable File
39 lines
2.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Runs every dashboard query twice: straight against Prometheus, and through Grafana's /api/ds/query with the
|
|
provisioned datasource (what a panel really does). Prints one line per panel query and exits non-zero if any
|
|
query errors or returns no series. Usage: verify-dashboard.py [output-file]"""
|
|
import base64, json, pathlib, sys, time, urllib.parse, urllib.request
|
|
|
|
root = pathlib.Path(__file__).resolve().parent.parent
|
|
dash = json.loads((root / "dashboards" / "spring-ai-observability.json").read_text())
|
|
auth = "Basic " + base64.b64encode(b"admin:admin").decode()
|
|
|
|
def get(url, data=None, headers=None):
|
|
req = urllib.request.Request(url, data=data, headers=headers or {})
|
|
with urllib.request.urlopen(req, timeout=30) as r:
|
|
return json.loads(r.read())
|
|
|
|
lines, bad = [], 0
|
|
now = int(time.time())
|
|
lines.append(f"{'panel':<58} {'prom series':>11} {'grafana frames':>14}")
|
|
for p in dash["panels"]:
|
|
for t in p["targets"]:
|
|
q = urllib.parse.urlencode({"query": t["expr"]})
|
|
prom = get("http://127.0.0.1:9090/api/v1/query?" + q)
|
|
n_prom = len(prom["data"]["result"]) if prom["status"] == "success" else -1
|
|
body = json.dumps({"queries": [{"refId": t["refId"], "datasource": t["datasource"], "expr": t["expr"], "instant": False,
|
|
"range": True, "interval": "", "intervalMs": 5000, "maxDataPoints": 200}],
|
|
"from": str((now - 600) * 1000), "to": str(now * 1000)}).encode()
|
|
gf = get("http://127.0.0.1:3000/api/ds/query", body, {"Content-Type": "application/json", "Authorization": auth})
|
|
res = gf["results"][t["refId"]]
|
|
n_gf = -1 if "error" in res else len(res.get("frames", []))
|
|
name = f"{p['title'][:48]} [{t['refId']}]"
|
|
lines.append(f"{name:<58} {n_prom:>11} {n_gf:>14}")
|
|
if n_prom < 1 or n_gf < 1:
|
|
bad += 1
|
|
out = "\n".join(lines)
|
|
print(out)
|
|
if len(sys.argv) > 1:
|
|
pathlib.Path(sys.argv[1]).write_text("# Every dashboard query, run against Prometheus and through Grafana's query API after scripts/load.sh\n\n" + out + "\n")
|
|
sys.exit(1 if bad else 0)
|