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 34447423ef Add operation drilldown dashboard builder
34447423ef is described below

commit 34447423ef7121681fcc2b48f7654570c4e088f6
Author: Logic <[email protected]>
AuthorDate: Mon Jun 8 09:56:27 2026 +0800

    Add operation drilldown dashboard builder
---
 web-next/lib/signal-dashboards.ts | 247 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 247 insertions(+)

diff --git a/web-next/lib/signal-dashboards.ts 
b/web-next/lib/signal-dashboards.ts
index 47345bf63e..91591b26a2 100644
--- a/web-next/lib/signal-dashboards.ts
+++ b/web-next/lib/signal-dashboards.ts
@@ -399,6 +399,10 @@ type BuildSignalServiceOverviewDashboardInput = {
   live?: string;
 };
 
+type BuildSignalOperationDrilldownDashboardInput = 
BuildSignalServiceOverviewDashboardInput & {
+  operationName: string;
+};
+
 type ResolveSignalDashboardPreviewOptions = {
   timeRange?: SignalDashboardTimeRange;
   now?: number;
@@ -625,6 +629,7 @@ export function 
buildSignalDashboardVariablesFromDrafts(drafts: SignalDashboardP
     addDraftVariable(variables, 'hertzbeat.source', 
collectRouteParam(draft.route, 'source'), 'Signal source context from panel 
drafts');
     addDraftVariable(variables, 'hertzbeat.collector', 
collectRouteParam(draft.route, 'collector'), 'Collector context from panel 
drafts');
     addDraftVariable(variables, 'hertzbeat.template', 
collectRouteParam(draft.route, 'template'), 'Template context from panel 
drafts');
+    addDraftVariable(variables, 'operation.name', 
collectRouteParam(draft.route, 'operationName'), 'Operation context from panel 
drafts');
   }
   return [...variables.values()];
 }
@@ -1908,6 +1913,58 @@ function serviceOverviewVariableType(name: string): 
SignalDashboardVariableType
     : name.startsWith('hertzbeat.') ? 'dynamic' : 'textbox';
 }
 
+function operationDrilldownVariableType(name: string): 
SignalDashboardVariableType {
+  return name === 'operation.name' || name === 'service.name' || name === 
'service.namespace' || name === 'deployment.environment.name'
+    ? 'query'
+    : name.startsWith('hertzbeat.') ? 'dynamic' : 'textbox';
+}
+
+function operationMetricRoute(input: {
+  sourceRoute: string;
+  serviceName: string;
+  operationName: string;
+  query: string;
+  values: Record<string, string>;
+}) {
+  return serviceMetricRedRoute({
+    sourceRoute: input.sourceRoute,
+    serviceName: input.serviceName,
+    query: input.query,
+    values: {
+      filter: serviceMetricFilter({
+        sourceRoute: input.sourceRoute,
+        serviceName: input.serviceName,
+        clauses: [`operation="${input.operationName}"`]
+      }),
+      ...input.values
+    }
+  });
+}
+
+function operationTraceRoute(sourceRoute: string, serviceName: string, 
operationName: string, values: Record<string, string>) {
+  return routeWithSearchParams(serviceCompanionRoute({
+    sourceRoute,
+    signal: 'traces',
+    serviceName,
+    visualization: values.view === 'time-series' ? 'time-series' : 'table'
+  }), {
+    operationName,
+    ...values
+  });
+}
+
+function operationLogRoute(sourceRoute: string, serviceName: string, 
operationName: string, values: Record<string, string>) {
+  return routeWithSearchParams(serviceCompanionRoute({
+    sourceRoute,
+    signal: 'logs',
+    serviceName,
+    visualization: values.view === 'table' ? 'table' : 'list'
+  }), {
+    attributeFilter: `http.route:${operationName}`,
+    ...values
+  });
+}
+
 export function buildSignalServiceOverviewDashboard(input: 
BuildSignalServiceOverviewDashboardInput): SignalDashboard {
   const serviceName = input.serviceName.trim();
   if (!serviceName) {
@@ -1944,6 +2001,196 @@ export function 
buildSignalServiceOverviewDashboard(input: BuildSignalServiceOve
   );
 }
 
+export function buildSignalOperationDrilldownDashboard(input: 
BuildSignalOperationDrilldownDashboardInput): SignalDashboard {
+  const serviceName = input.serviceName.trim();
+  const operationName = input.operationName.trim();
+  if (!serviceName || !operationName) {
+    throw new Error('Operation drilldown dashboard requires a service name and 
operation name');
+  }
+  const serviceLabel = input.entityName?.trim() || serviceName;
+  const sourceRoute = routeWithSearchParams(serviceOverviewRoute({ ...input, 
serviceName }), {
+    operationName
+  });
+  const filterLabel = `operation.name=${operationName}`;
+  const drafts = [
+    createSignalDashboardPanelDraft({
+      signal: 'metrics',
+      title: `Operation drilldown latency p95: ${filterLabel}`,
+      description: `${filterLabel} · latency p95`,
+      visualization: 'graph',
+      route: operationMetricRoute({
+        sourceRoute,
+        serviceName,
+        operationName,
+        query: 'http.server.duration',
+        values: {
+          aggregation: 'p95',
+          groupBy: 'operation',
+          legendFormat: '{{operation}} - p95',
+          formula: 'A * 1000'
+        }
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-latency-p95',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'metrics',
+      title: `Operation drilldown request rate: ${filterLabel}`,
+      description: `${filterLabel} · request rate`,
+      visualization: 'graph',
+      route: operationMetricRoute({
+        sourceRoute,
+        serviceName,
+        operationName,
+        query: 'http_server_duration_milliseconds_count',
+        values: {
+          aggregation: 'sum',
+          temporalAggregation: 'rate',
+          groupBy: 'operation',
+          legendFormat: '{{operation}} - rps'
+        }
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-request-rate',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'metrics',
+      title: `Operation drilldown error rate: ${filterLabel}`,
+      description: `${filterLabel} · error rate`,
+      visualization: 'graph',
+      route: operationMetricRoute({
+        sourceRoute,
+        serviceName,
+        operationName,
+        query: 'http_server_duration_milliseconds_count',
+        values: {
+          filter: serviceMetricFilter({
+            sourceRoute,
+            serviceName,
+            clauses: [`operation="${operationName}"`, 
'status_code="STATUS_CODE_ERROR"']
+          }),
+          aggregation: 'sum',
+          temporalAggregation: 'rate',
+          groupBy: 'status_code',
+          legendFormat: '{{operation}} - errors'
+        }
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-error-rate',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'logs',
+      title: `Operation drilldown logs: ${filterLabel}`,
+      description: `${filterLabel} · logs`,
+      visualization: 'list',
+      route: operationLogRoute(sourceRoute, serviceName, operationName, {
+        view: 'list'
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-logs',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'logs',
+      title: `Operation drilldown log errors: ${filterLabel}`,
+      description: `${filterLabel} · log errors`,
+      visualization: 'table',
+      route: operationLogRoute(sourceRoute, serviceName, operationName, {
+        severityText: 'ERROR',
+        view: 'table'
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-log-errors',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'traces',
+      title: `Operation drilldown traces: ${filterLabel}`,
+      description: `${filterLabel} · traces`,
+      visualization: 'table',
+      route: operationTraceRoute(sourceRoute, serviceName, operationName, {
+        view: 'table'
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-traces',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'traces',
+      title: `Operation drilldown trace errors: ${filterLabel}`,
+      description: `${filterLabel} · trace errors`,
+      visualization: 'table',
+      route: operationTraceRoute(sourceRoute, serviceName, operationName, {
+        errorOnly: 'true',
+        view: 'table'
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-trace-errors',
+        serviceName,
+        operationName
+      }
+    }),
+    createSignalDashboardPanelDraft({
+      signal: 'traces',
+      title: `Operation drilldown exceptions: ${filterLabel}`,
+      description: `${filterLabel} · exceptions`,
+      visualization: 'list',
+      route: operationTraceRoute(sourceRoute, serviceName, operationName, {
+        template: 'service-exceptions',
+        errorOnly: 'true',
+        spanScope: 'all',
+        groupBy: 'exception.type',
+        groupOrder: 'error-count-desc',
+        groupLimit: '8',
+        view: 'list'
+      }),
+      payload: {
+        source: 'signal-dashboard-operation-drilldown',
+        templateKey: 'operation-exceptions',
+        serviceName,
+        operationName
+      }
+    })
+  ];
+  const dashboard = buildSignalDashboardCompositionFromDrafts({
+    dashboardKey: 
normalizeSignalDashboardKey(`service-${serviceName}-operation-${operationName}-drilldown`),
+    title: `${serviceLabel} ${operationName} operation drilldown`,
+    description: `Operation-level RED, logs, traces, and exceptions for 
${operationName} in ${serviceLabel}.`,
+    tags: ['service', 'operation', 'apm', 'metrics', 'logs', 'traces'],
+    drafts
+  });
+  return updateSignalDashboardVariables(
+    dashboard,
+    parseSignalDashboardVariables(dashboard).map(variable => ({
+      ...variable,
+      type: operationDrilldownVariableType(variable.name),
+      options: variable.value ? [variable.value] : variable.options
+    }))
+  );
+}
+
 function errorMessage(error: unknown) {
   return error instanceof Error ? error.message : 'Signal dashboard panel 
execution failed';
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to