This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new 0ab4ae6e4 fix(metrics): make two dashboard panels report what their
titles promise (#5421)
0ab4ae6e4 is described below
commit 0ab4ae6e456f4019b49a06aba0176f495abf986e
Author: 烤化の初雪 <[email protected]>
AuthorDate: Fri Oct 9 16:25:46 2026 +0800
fix(metrics): make two dashboard panels report what their titles promise
(#5421)
Two Grafana panels answered a different question than their titles asked.
- Overview "Broker Count" used a bare
`count(rocketmq_messages_in_total{...})`, which counts
timeseries rather than brokers; it now counts the distinct broker label.
(#5421)
- DLQ "DLQ Resend Count (1m)" used `rate(...[1m])`, a per-second rate,
under a title promising a
one-minute count; it now uses `increase(...[1m])`. (#5422)
The generator (`gen_grafana_dashboards.py`) and the committed dashboards
are updated together.
`test_gen_grafana_dashboards.py` 8 tests green, and the generator output
matches the committed JSON.
Folded in #5422 (same author, same generator and dashboard files).
---
server/scripts/gen_grafana_dashboards.py | 4 +-
server/scripts/test_gen_grafana_dashboards.py | 65 +++++++++++++++++++++-
.../src/main/resources/grafana/rocketmq-dlq.json | 2 +-
.../main/resources/grafana/rocketmq-overview.json | 2 +-
4 files changed, 68 insertions(+), 5 deletions(-)
diff --git a/server/scripts/gen_grafana_dashboards.py
b/server/scripts/gen_grafana_dashboards.py
index 775918fd5..aefc48962 100644
--- a/server/scripts/gen_grafana_dashboards.py
+++ b/server/scripts/gen_grafana_dashboards.py
@@ -173,7 +173,7 @@ specs.append((
stat_panel(3, "Total Topics", "count(count by (topic)
(rocketmq_messages_in_total{cluster=\"$cluster\"}))", 6, 8),
stat_panel(4, "Total Consumer Groups", "count(count by (group)
(rocketmq_messages_out_total{cluster=\"$cluster\"}))", 6, 8),
stat_panel(5, "Producer Count",
"max(rocketmq_producer_count{cluster=\"$cluster\"})", 6, 8),
- stat_panel(6, "Broker Count",
"count(rocketmq_messages_in_total{cluster=\"$cluster\"})", 6, 8),
+ stat_panel(6, "Broker Count", "count(count by (broker)
(rocketmq_messages_in_total{cluster=\"$cluster\"}))", 6, 8),
],
))
@@ -272,7 +272,7 @@ specs.append((
"rocketmq-dlq", "RocketMQ DLQ & Retry",
"Dead-letter queue resend volume and latency.",
[
- ts_panel(1, "DLQ Resend Count (1m)",
"rate(rocketmq_dlq_resend_count{cluster=\"$cluster\"}[1m])", 12, 0,
"{{topic}}"),
+ ts_panel(1, "DLQ Resend Count (1m)",
"increase(rocketmq_dlq_resend_count{cluster=\"$cluster\"}[1m])", 12, 0,
"{{topic}}"),
ts_panel(2, "DLQ Resend Latency",
"rocketmq_dlq_resend_latency{cluster=\"$cluster\"}", 12, 0, "{{topic}}", "s"),
],
))
diff --git a/server/scripts/test_gen_grafana_dashboards.py
b/server/scripts/test_gen_grafana_dashboards.py
index 17fcac5d3..bbb36b400 100644
--- a/server/scripts/test_gen_grafana_dashboards.py
+++ b/server/scripts/test_gen_grafana_dashboards.py
@@ -17,18 +17,31 @@
################################################################################
"""Regression tests for the Grafana dashboard asset generator."""
+import json
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
-from gen_grafana_dashboards import gauge_panel, layout_panels
+from gen_grafana_dashboards import gauge_panel, layout_panels, specs
+
+DASHBOARD_DIR = Path(__file__).resolve().parent.parent / "src" / "main" /
"resources" / "grafana"
def panel(width, height):
return {"gridPos": {"w": width, "h": height, "x": 99, "y": 99}}
+def shipped_panel_expr(uid, title):
+ """Expression a shipped dashboard asset renders in the panel named
``title``."""
+ with open(DASHBOARD_DIR / f"{uid}.json", encoding="utf-8") as handle:
+ dashboard = json.load(handle)
+ for item in dashboard["panels"]:
+ if item["title"] == title:
+ return item["targets"][0]["expr"]
+ raise AssertionError(f"panel {title!r} missing from {uid}")
+
+
class LayoutPanelsTest(unittest.TestCase):
def test_packs_panels_by_width_and_advances_by_tallest_panel(self):
@@ -58,6 +71,56 @@ class LayoutPanelsTest(unittest.TestCase):
layout_panels([panel(12, 0)])
+class OverviewPanelsTest(unittest.TestCase):
+
+ def specs_by_uid(self):
+ return {spec[0]: spec for spec in specs}
+
+ def test_broker_count_counts_brokers_not_series(self):
+ overview = self.specs_by_uid()["rocketmq-overview"]
+ panels = {item["title"]: item for item in overview[3]}
+ expr = panels["Broker Count"]["targets"][0]["expr"]
+
+ # rocketmq_messages_in_total carries both broker and topic labels -
the same dashboard
+ # derives its $broker and $topic template variables from them - so a
bare count() returns
+ # one series per broker/topic pair and reads hundreds on a two-broker
cluster. The
+ # neighbouring "Total Topics" panel already counts with count(count by
(topic) (...)).
+ self.assertEqual(
+ 'count(count by (broker)
(rocketmq_messages_in_total{cluster="$cluster"}))',
+ expr,
+ )
+
+ def test_shipped_overview_dashboard_matches_the_generator(self):
+ overview = self.specs_by_uid()["rocketmq-overview"]
+ panels = {item["title"]: item for item in overview[3]}
+
+ self.assertEqual(
+ panels["Broker Count"]["targets"][0]["expr"],
+ shipped_panel_expr("rocketmq-overview", "Broker Count"),
+ )
+
+
+class ShippedDashboardPanelsTest(unittest.TestCase):
+
+ def test_dlq_resend_count_panel_counts_over_the_window(self):
+ # The panel title and its "short" unit promise a count over the 1m
window, but rate()
+ # renders resends per second - 60x below the number a reader takes
from the title. The
+ # sibling "Reject Count (1m)" panel in the same bundle already uses
increase(...[1m]).
+ self.assertEqual(
+ 'increase(rocketmq_dlq_resend_count{cluster="$cluster"}[1m])',
+ shipped_panel_expr("rocketmq-dlq", "DLQ Resend Count (1m)"),
+ )
+
+ def test_shipped_dlq_dashboard_matches_the_generator(self):
+ dlq = {spec[0]: spec for spec in specs}["rocketmq-dlq"]
+ panels = {item["title"]: item for item in dlq[3]}
+
+ self.assertEqual(
+ panels["DLQ Resend Count (1m)"]["targets"][0]["expr"],
+ shipped_panel_expr("rocketmq-dlq", "DLQ Resend Count (1m)"),
+ )
+
+
class GaugePanelTest(unittest.TestCase):
def test_places_minimum_in_field_defaults(self):
diff --git a/server/src/main/resources/grafana/rocketmq-dlq.json
b/server/src/main/resources/grafana/rocketmq-dlq.json
index c6bddd963..35d30d915 100644
--- a/server/src/main/resources/grafana/rocketmq-dlq.json
+++ b/server/src/main/resources/grafana/rocketmq-dlq.json
@@ -98,7 +98,7 @@
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
- "expr": "rate(rocketmq_dlq_resend_count{cluster=\"$cluster\"}[1m])",
+ "expr":
"increase(rocketmq_dlq_resend_count{cluster=\"$cluster\"}[1m])",
"legendFormat": "{{topic}}",
"refId": "A"
}
diff --git a/server/src/main/resources/grafana/rocketmq-overview.json
b/server/src/main/resources/grafana/rocketmq-overview.json
index 2f7da454a..15119330d 100644
--- a/server/src/main/resources/grafana/rocketmq-overview.json
+++ b/server/src/main/resources/grafana/rocketmq-overview.json
@@ -313,7 +313,7 @@
"type": "prometheus",
"uid": "${DS_PROMETHEUS}"
},
- "expr": "count(rocketmq_messages_in_total{cluster=\"$cluster\"})",
+ "expr": "count(count by (broker)
(rocketmq_messages_in_total{cluster=\"$cluster\"}))",
"refId": "A"
}
]