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 0e1c69e54f Preserve metrics alert draft signal context
0e1c69e54f is described below

commit 0e1c69e54fe5cb3cd4f1653e6429b5b96f81736b
Author: Logic <[email protected]>
AuthorDate: Wed Jun 10 08:48:13 2026 +0800

    Preserve metrics alert draft signal context
---
 web-next/lib/otlp-metrics/view-model.test.ts | 17 +++++++++++++++++
 web-next/lib/otlp-metrics/view-model.ts      | 11 ++++++++++-
 2 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/web-next/lib/otlp-metrics/view-model.test.ts 
b/web-next/lib/otlp-metrics/view-model.test.ts
index 41b0c6435c..86d9628eb4 100644
--- a/web-next/lib/otlp-metrics/view-model.test.ts
+++ b/web-next/lib/otlp-metrics/view-model.test.ts
@@ -911,6 +911,7 @@ describe('otlp metrics view model', () => {
       {
         traceId: 'trace-1',
         spanId: 'span-1',
+        operationName: 'POST /checkout',
         query: 'http.server.duration',
         filter: 'service.name="checkout"',
         formula: 'rate(http.server.duration[5m])',
@@ -1004,6 +1005,7 @@ describe('otlp metrics view model', () => {
     expect(alertParams.get('intent')).toBe('create');
     expect(alertParams.get('entityId')).toBe('7');
     expect(alertParams.get('serviceName')).toBe('checkout');
+    expect(alertParams.get('operationName')).toBe('POST /checkout');
     expect(alertParams.get('environment')).toBe('prod');
     expect(alertParams.get('timeRange')).toBe('last-1h');
     expect(alertParams.get('source')).toBe('otlp');
@@ -1013,6 +1015,12 @@ describe('otlp metrics view model', () => {
     expect(alertParams.get('alertDatasource')).toBe('promql');
     
expect(alertParams.get('alertQuery')).toContain('query=http.server.duration');
     
expect(alertParams.get('alertQuery')).toContain('filter=service.name="checkout"');
+    expect(alertParams.get('alertQuery')).toContain('entityId=7');
+    expect(alertParams.get('alertQuery')).toContain('entityName=Checkout API');
+    
expect(alertParams.get('alertQuery')).toContain('serviceNamespace=payments');
+    expect(alertParams.get('alertQuery')).toContain('operationName=POST 
/checkout');
+    expect(alertParams.get('alertQuery')).toContain('traceId=trace-1');
+    expect(alertParams.get('alertQuery')).toContain('spanId=span-1');
 
     const handlingUrl = new URL(result.alertHandlingHref, 
'https://example.com');
     expect(handlingUrl.pathname).toBe('/alert');
@@ -1040,6 +1048,7 @@ describe('otlp metrics view model', () => {
     expect(dashboardHref.searchParams.get('panelDatasource')).toBe('promql');
     
expect(dashboardHref.searchParams.get('panelQuery')).toContain('query=http.server.duration');
     
expect(dashboardHref.searchParams.get('panelQuery')).toContain('filter=service.name="checkout"');
+    
expect(dashboardHref.searchParams.get('panelQuery')).toContain('operationName=POST
 /checkout');
   });
 
   it('lets a selected metric series drive service, entity, logs, traces, and 
alert handoffs', () => {
@@ -1076,6 +1085,7 @@ describe('otlp metrics view model', () => {
           'deployment.environment.name': 'prod-east',
           trace_id: 'trace-series-42',
           span_id: 'span-series-42',
+          http_route: '/inventory/{id}',
           'hertzbeat.entity_id': '42',
           'hertzbeat.entity_name': 'Inventory API',
           'hertzbeat.collector': 'collector-b',
@@ -1096,6 +1106,7 @@ describe('otlp metrics view model', () => {
     expect(logParams.get('environment')).toBe('prod-east');
     expect(logParams.get('traceId')).toBe('trace-series-42');
     expect(logParams.get('spanId')).toBe('span-series-42');
+    expect(logParams.get('operationName')).toBe('/inventory/{id}');
     expect(logParams.get('collector')).toBe('collector-b');
     expect(logParams.get('template')).toBe('fastapi');
 
@@ -1105,6 +1116,7 @@ describe('otlp metrics view model', () => {
     expect(traceParams.get('environment')).toBe('prod-east');
     expect(traceParams.get('traceId')).toBe('trace-series-42');
     expect(traceParams.get('spanId')).toBe('span-series-42');
+    expect(traceParams.get('operationName')).toBe('/inventory/{id}');
     expect(traceParams.get('entityId')).toBe('42');
 
     const entityHref = new URL(result.entityHref, 'https://example.com');
@@ -1116,6 +1128,11 @@ describe('otlp metrics view model', () => {
     expect(alertHandlingHref.searchParams.get('search')).toBe('inventory');
     expect(alertHandlingHref.searchParams.get('entityId')).toBe('42');
     
expect(alertHandlingHref.searchParams.get('serviceName')).toBe('inventory');
+    
expect(alertHandlingHref.searchParams.get('operationName')).toBe('/inventory/{id}');
+
+    const alertRulesHref = new URL(result.alertRulesHref, 
'https://example.com');
+    
expect(alertRulesHref.searchParams.get('operationName')).toBe('/inventory/{id}');
+    
expect(alertRulesHref.searchParams.get('alertQuery')).toContain('operationName=/inventory/{id}');
   });
 
   it('opens trace-linked metric logs as history records without an extra text 
search filter', () => {
diff --git a/web-next/lib/otlp-metrics/view-model.ts 
b/web-next/lib/otlp-metrics/view-model.ts
index c82769cf3f..53fa2ff451 100644
--- a/web-next/lib/otlp-metrics/view-model.ts
+++ b/web-next/lib/otlp-metrics/view-model.ts
@@ -145,8 +145,14 @@ export function buildMetricsAlertRuleDraft(
     ['filter', query.filter],
     ['aggregation', query.aggregation],
     ['groupBy', query.groupBy],
+    ['entityId', query.entityId || routeContext.entityId],
+    ['entityName', query.entityName || routeContext.entityName],
     ['serviceName', query.serviceName || routeContext.serviceName],
-    ['environment', query.environment || routeContext.environment]
+    ['serviceNamespace', query.serviceNamespace || 
routeContext.serviceNamespace],
+    ['operationName', query.operationName || routeContext.operationName],
+    ['environment', query.environment || routeContext.environment],
+    ['traceId', query.traceId || routeContext.traceId],
+    ['spanId', query.spanId || routeContext.spanId]
   ]
     .map(([key, value]) => {
       const normalized = compactAlertDraftValue(value);
@@ -185,6 +191,7 @@ function buildMetricSeriesSignalContext(series: 
OtlpMetricSeriesView | null | un
     serviceName: readSeriesLabel(series, 'service.name', 'service_name', 
'serviceName'),
     serviceNamespace: readSeriesLabel(series, 'service.namespace', 
'service_namespace', 'serviceNamespace'),
     environment: readSeriesLabel(series, 'deployment.environment.name', 
'deployment_environment_name', 'deployment_environment', 'environment'),
+    operationName: readSeriesLabel(series, 'operationName', 'operation_name', 
'operation', 'http.route', 'http_route'),
     traceId: readSeriesLabel(series, 'traceId', 'trace_id', 'trace.id', 
'trace_id_hex'),
     spanId: readSeriesLabel(series, 'spanId', 'span_id', 'span.id', 
'span_id_hex'),
     collector: readSeriesLabel(series, 'hertzbeat.collector', 
'hertzbeat_collector', 'collector'),
@@ -960,6 +967,7 @@ export function buildMetricsHandoffLinks(
   const end = query.end || (data.context?.end != null ? 
String(data.context.end) : routeContext.end);
   const traceId = firstText(selectedContext.traceId, query.traceId, 
routeContext.traceId);
   const spanId = firstText(selectedContext.spanId, query.spanId, 
routeContext.spanId);
+  const operationName = firstText(selectedContext.operationName, 
query.operationName, routeContext.operationName);
   const signalContext: SignalRouteContext = {
     ...routeContext,
     ...query,
@@ -971,6 +979,7 @@ export function buildMetricsHandoffLinks(
     timeRange: routeContext.timeRange,
     traceId,
     spanId,
+    operationName,
     source: routeContext.source || 'otlp',
     collector: selectedContext.collector || query.collector || 
routeContext.collector,
     template: selectedContext.template || query.template || 
routeContext.template,


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

Reply via email to