Merge branch 'pratik/otel-phase9-metric-gap-fill' into pratik/otel-phase10-workload-validation

This commit is contained in:
Pratik Mankawde
2026-08-04 14:55:59 +01:00
2 changed files with 65 additions and 13 deletions

View File

@@ -1545,11 +1545,11 @@
"h": 1,
"w": 24,
"x": 0,
"y": 115
"y": 121
},
"collapsed": false,
"panels": [],
"id": 27
"id": 38
},
{
"title": "Job Queue Backlog and Deferred by Type",
@@ -1559,7 +1559,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 116
"y": 122
},
"options": {
"tooltip": {
@@ -1608,7 +1608,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 116
"y": 122
},
"options": {
"tooltip": {
@@ -1649,7 +1649,7 @@
"h": 1,
"w": 24,
"x": 0,
"y": 124
"y": 130
},
"collapsed": false,
"panels": [],
@@ -1663,7 +1663,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 125
"y": 131
},
"options": {
"tooltip": {
@@ -1735,7 +1735,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 125
"y": 131
},
"options": {
"tooltip": {
@@ -1784,7 +1784,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 133
"y": 139
},
"options": {
"tooltip": {
@@ -1844,7 +1844,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 133
"y": 139
},
"options": {
"tooltip": {
@@ -1893,7 +1893,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 141
"y": 147
},
"options": {
"tooltip": {
@@ -1949,7 +1949,7 @@
"h": 8,
"w": 12,
"x": 12,
"y": 141
"y": 147
},
"options": {
"tooltip": {
@@ -1998,7 +1998,7 @@
"h": 8,
"w": 12,
"x": 0,
"y": 149
"y": 155
},
"options": {
"tooltip": {

View File

@@ -1,8 +1,10 @@
#!/usr/bin/env python3
"""Dashboard lint: cumulative metrics must be rate()-wrapped; tier filters present."""
"""Dashboard lint: cumulative metrics rate()-wrapped; tier filters; sane panel grid."""
import json, re, sys
GRID_COLUMNS = 24
# Prometheus gauges that hold a CUMULATIVE total -> must be rate()/increase()-wrapped.
CUMULATIVE_PREFIXES = (
"total_bytes_",
@@ -55,6 +57,55 @@ def iter_panels(dash):
yield sub
def check_layout(path, dash):
"""Duplicate panel ids and grid collisions -- both break Grafana's loader.
Grafana keys panels by id when it builds the dashboard model, so two panels
sharing an id make the load non-deterministic. Overlapping gridPos rectangles
have no valid layout. Only top-level panels are checked: panels nested inside
a collapsed row do not occupy the outer grid.
"""
errs = []
top = dash.get("panels", []) or []
seen_ids = {}
for p in top:
pid = p.get("id")
if pid is None:
continue
if pid in seen_ids:
errs.append(
f"{path}: duplicate panel id {pid}: "
f"[{seen_ids[pid]}] and [{p.get('title', '<untitled>')}]"
)
else:
seen_ids[pid] = p.get("title", "<untitled>")
# Mark every grid cell each panel covers; a second claim on a cell is a collision.
owner = {}
for p in top:
g = p.get("gridPos") or {}
x, y = g.get("x", 0), g.get("y", 0)
w, h = g.get("w", 0), g.get("h", 0)
title = p.get("title", "<untitled>")
if x + w > GRID_COLUMNS:
errs.append(
f"{path} [{title}]: spans past the {GRID_COLUMNS}-column grid (x={x}, w={w})"
)
clashed = set()
for cy in range(y, y + h):
for cx in range(x, min(x + w, GRID_COLUMNS)):
prev = owner.get((cy, cx))
if prev is None:
owner[(cy, cx)] = title
elif prev not in clashed:
clashed.add(prev)
errs.append(
f"{path} [{title}]: grid overlap with [{prev}] at y={cy} x={cx}"
)
return errs
def expr_is_wrapped(expr):
return (
"rate(" in expr
@@ -70,6 +121,7 @@ def check(path, forbid_5m):
dash = json.load(open(path))
except Exception as e:
return [f"{path}: INVALID JSON: {e}"]
errs += check_layout(path, dash)
for p in iter_panels(dash):
title = p.get("title", "<untitled>")
for tg in p.get("targets", []) or []: