This is an automated email from the ASF dual-hosted git repository.
zqr10159 pushed a commit to branch 2.0.0
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/2.0.0 by this push:
new a7b4cb4aca Preserve RPC service in metric drilldowns
a7b4cb4aca is described below
commit a7b4cb4aca384d389daee3ee446704075540c30a
Author: Logic <[email protected]>
AuthorDate: Tue Jun 9 18:48:57 2026 +0800
Preserve RPC service in metric drilldowns
---
web-next/lib/signal-dashboards.test.ts | 58 ++++++++++++++++++++++++++++++++++
web-next/lib/signal-dashboards.ts | 11 ++++++-
2 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/web-next/lib/signal-dashboards.test.ts
b/web-next/lib/signal-dashboards.test.ts
index 9f9d507166..eca9f67102 100644
--- a/web-next/lib/signal-dashboards.test.ts
+++ b/web-next/lib/signal-dashboards.test.ts
@@ -2271,6 +2271,64 @@ describe('signal dashboards API client', () => {
}));
});
+ it('builds RPC metric point handoffs with service and method operation
context', () => {
+ const [rpcMetricsPlan] = buildSignalDashboardExecutionPlans({
+ dashboardKey: 'rpc-sync',
+ title: 'RPC sync dashboard',
+ description: 'Runtime sync',
+ tags: 'metrics',
+ layout: '[]',
+ widgets: JSON.stringify([
+ {
+ id: 'rpc-metrics-panel',
+ signal: 'metrics',
+ title: 'RPC latency',
+ visualization: 'time-series',
+ route:
'/ingestion/otlp/metrics?query=rpc.server.duration&serviceName=checkout&groupBy=rpc.service,rpc.method'
+ }
+ ])
+ });
+ const rpcMetricsDescriptor =
buildSignalDashboardPanelRuntimeRenderDescriptor(rpcMetricsPlan, {
+ panelId: 'rpc-metrics-panel',
+ state: 'ready',
+ primaryUrl: rpcMetricsPlan.primaryUrl,
+ data: {
+ stats: { totalSeries: 1, nonEmptySeries: 1 },
+ results: {
+ frames: [{
+ schema: {
+ labels: {
+ __name__: 'rpc.server.duration',
+ 'service.name': 'checkout',
+ 'service.namespace': 'payments',
+ 'rpc.service': 'payments.CheckoutService',
+ 'rpc.method': 'Authorize'
+ }
+ },
+ data: [[1000, 32], [2000, 45]]
+ }]
+ }
+ }
+ });
+
+ const syncTooltip = buildSignalDashboardRuntimeSyncTooltip(
+ [rpcMetricsDescriptor],
+ '2000',
+ { timeRange: { start: '1000', end: '3000' }, returnTo:
'/dashboard?start=1000&end=3000' }
+ );
+
+ expect(syncTooltip.rows[0]).toEqual(expect.objectContaining({
+ panelId: 'rpc-metrics-panel',
+ signal: 'metrics',
+ source: 'metrics-point',
+ serviceName: 'checkout',
+ serviceNamespace: 'payments',
+ operationName: 'payments.CheckoutService/Authorize',
+ relatedSignal: 'traces',
+ relatedHandoffHref:
'/trace/manage?view=list&spanScope=all&serviceName=checkout&serviceNamespace=payments&operationName=payments.CheckoutService%2FAuthorize&returnTo=%2Fdashboard%3Fstart%3D1000%26end%3D3000&start=1000&end=3000'
+ }));
+ });
+
it('creates panel drafts from runtime evidence rows with source context', ()
=> {
const draft = createSignalDashboardPanelDraftFromRuntimeEvidence({
row: {
diff --git a/web-next/lib/signal-dashboards.ts
b/web-next/lib/signal-dashboards.ts
index 6afe43bdc1..0c8d8090fb 100644
--- a/web-next/lib/signal-dashboards.ts
+++ b/web-next/lib/signal-dashboards.ts
@@ -3394,6 +3394,15 @@ function metricLabelValue(labels: Record<string,
string>, names: string[]) {
return '';
}
+function metricOperationName(labels: Record<string, string>) {
+ const explicitOperationName = metricLabelValue(labels, ['operation',
'operationName', 'operation_name', 'http.route']);
+ if (explicitOperationName) return explicitOperationName;
+ const rpcMethod = metricLabelValue(labels, ['rpc.method', 'rpc_method']);
+ if (!rpcMethod) return '';
+ const rpcService = metricLabelValue(labels, ['rpc.service', 'rpc_service']);
+ return rpcService ? `${rpcService}/${rpcMethod}` : rpcMethod;
+}
+
function metricResourceFilter(key: string, value: string) {
if (!key || !value) return '';
return `${key}=${value}`;
@@ -3448,7 +3457,7 @@ function syncTooltipMetricRelatedHandoff(
const serviceNamespace = metricLabelValue(labels, ['service.namespace',
'serviceNamespace', 'service_namespace']);
const dbSystem = metricLabelValue(labels, ['db.system', 'dbSystem',
'db_system']);
const externalAddress = metricLabelValue(labels,
['external.service.address', 'externalServiceAddress',
'external_service_address', 'server.address', 'net.peer.name']);
- const operationName = metricLabelValue(labels, ['operation',
'operationName', 'operation_name', 'http.route', 'rpc.method']);
+ const operationName = metricOperationName(labels);
const resourceFilter = dbSystem
? metricResourceFilter('db.system', dbSystem)
: externalAddress ? metricResourceFilter('external.service.address',
externalAddress) : '';
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]