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 03da23d1d5 Report actual related metric matchers
03da23d1d5 is described below

commit 03da23d1d5e61610e5b4059f186793661b43ba64
Author: Logic <[email protected]>
AuthorDate: Wed Jun 10 08:11:29 2026 +0800

    Report actual related metric matchers
---
 .../impl/OtlpIngestionWorkspaceServiceImpl.java    | 41 +++++++++---
 .../OtlpIngestionWorkspaceServiceImplTest.java     | 76 ++++++++++++++++++++++
 2 files changed, 109 insertions(+), 8 deletions(-)

diff --git 
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImpl.java
 
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImpl.java
index 95d7cfffc9..99ba05223e 100644
--- 
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImpl.java
+++ 
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImpl.java
@@ -1042,10 +1042,10 @@ public class OtlpIngestionWorkspaceServiceImpl 
implements OtlpIngestionWorkspace
         String step = resolvePromqlStep(start, end, null);
         List<OtlpRelatedMetricsDto.Candidate> available = new ArrayList<>();
         for (OtlpRelatedMetricsDto.Candidate candidate : candidates) {
-            for (String query : 
buildRelatedMetricAvailabilityQueries(candidate)) {
+            for (RelatedMetricAvailabilityProbe probe : 
buildRelatedMetricAvailabilityProbes(candidate)) {
                 MetricQueryRepository.PromqlRangeQueryResult result = 
metricQueryRepository.queryPromqlRange(
                         RELATED_METRICS_REF_ID,
-                        query,
+                        probe.query(),
                         start,
                         end,
                         step
@@ -1063,8 +1063,8 @@ public class OtlpIngestionWorkspaceServiceImpl implements 
OtlpIngestionWorkspace
                             candidate.getSource(),
                             candidate.getFamily(),
                             "promql-series",
-                            candidate.getMatchedLabels(),
-                            candidate.getResourceMatch()
+                            probe.matchedLabels(),
+                            probe.resourceMatch()
                     ));
                     break;
                 }
@@ -1076,7 +1076,7 @@ public class OtlpIngestionWorkspaceServiceImpl implements 
OtlpIngestionWorkspace
         return available;
     }
 
-    private List<String> 
buildRelatedMetricAvailabilityQueries(OtlpRelatedMetricsDto.Candidate 
candidate) {
+    private List<RelatedMetricAvailabilityProbe> 
buildRelatedMetricAvailabilityProbes(OtlpRelatedMetricsDto.Candidate candidate) 
{
         if (candidate == null || !StringUtils.hasText(candidate.getQuery())) {
             return List.of();
         }
@@ -1095,11 +1095,21 @@ public class OtlpIngestionWorkspaceServiceImpl 
implements OtlpIngestionWorkspace
             LinkedHashMap<String, String> httpRouteMatch = new 
LinkedHashMap<>(resourceMatch);
             httpRouteMatch.remove("operation_name");
             return List.of(
-                    buildRelatedMetricAvailabilityQuery(metricName, 
operationNameMatch),
-                    buildRelatedMetricAvailabilityQuery(metricName, 
httpRouteMatch)
+                    buildRelatedMetricAvailabilityProbe(metricName, candidate, 
operationNameMatch),
+                    buildRelatedMetricAvailabilityProbe(metricName, candidate, 
httpRouteMatch)
             );
         }
-        return List.of(buildRelatedMetricAvailabilityQuery(metricName, 
resourceMatch));
+        return List.of(buildRelatedMetricAvailabilityProbe(metricName, 
candidate, resourceMatch));
+    }
+
+    private RelatedMetricAvailabilityProbe 
buildRelatedMetricAvailabilityProbe(String metricName,
+                                                                               
OtlpRelatedMetricsDto.Candidate candidate,
+                                                                               
Map<String, String> resourceMatch) {
+        return new RelatedMetricAvailabilityProbe(
+                buildRelatedMetricAvailabilityQuery(metricName, resourceMatch),
+                matchedAvailabilityLabels(candidate, resourceMatch),
+                resourceMatch
+        );
     }
 
     private String buildRelatedMetricAvailabilityQuery(String metricName, 
Map<String, String> resourceMatch) {
@@ -1118,6 +1128,16 @@ public class OtlpIngestionWorkspaceServiceImpl 
implements OtlpIngestionWorkspace
         return "sum by (__name__) ({" + String.join(", ", matchers) + "})";
     }
 
+    private List<String> 
matchedAvailabilityLabels(OtlpRelatedMetricsDto.Candidate candidate, 
Map<String, String> resourceMatch) {
+        if (candidate == null || 
CollectionUtils.isEmpty(candidate.getMatchedLabels()) || 
CollectionUtils.isEmpty(resourceMatch)) {
+            return List.of();
+        }
+        Set<String> resourceLabels = resourceMatch.keySet();
+        return candidate.getMatchedLabels().stream()
+                .filter(resourceLabels::contains)
+                .toList();
+    }
+
     private void addRelatedMetricCandidate(LinkedHashMap<String, 
OtlpRelatedMetricsDto.Candidate> candidates,
                                            String query,
                                            String source,
@@ -2791,4 +2811,9 @@ public class OtlpIngestionWorkspaceServiceImpl implements 
OtlpIngestionWorkspace
                                          OtlpMetricsConsoleDto.Stats stats,
                                          String errorMessage) {
     }
+
+    private record RelatedMetricAvailabilityProbe(String query,
+                                                  List<String> matchedLabels,
+                                                  Map<String, String> 
resourceMatch) {
+    }
 }
diff --git 
a/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImplTest.java
 
b/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImplTest.java
index 8f0c232bc6..ddaa9e1d8d 100644
--- 
a/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImplTest.java
+++ 
b/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/ingestion/service/impl/OtlpIngestionWorkspaceServiceImplTest.java
@@ -1168,6 +1168,82 @@ class OtlpIngestionWorkspaceServiceImplTest {
                         && "POST 
/checkout".equals(candidate.getResourceMatch().get("http_route"))));
     }
 
+    @Test
+    void relatedMetricsReportsActualOperationAvailabilityMatcher() {
+        observabilitySignalIntakeGateway.recordOtlpMetricIntake(
+                Map.of(
+                        "service.name", "checkout",
+                        "service.namespace", "commerce",
+                        "deployment.environment.name", "prod"
+                ),
+                2_000L,
+                "http.server.duration",
+                "histogram",
+                "ms",
+                14.0,
+                Map.of()
+        );
+        
when(workspaceQueryGateway.findEntityById(42L)).thenReturn(java.util.Optional.empty());
+        
when(workspaceQueryGateway.findIdentitiesByEntityId(42L)).thenReturn(List.of());
+        when(metricQueryRepository.hasPromqlExecutor()).thenReturn(true);
+        when(metricQueryRepository.queryPromqlRange(
+                anyString(),
+                anyString(),
+                anyLong(),
+                anyLong(),
+                anyString()
+        )).thenAnswer(invocation -> {
+            String refId = invocation.getArgument(0);
+            String query = invocation.getArgument(1);
+            if ("otlp-related-metrics-inventory".equals(refId)) {
+                return promqlSuccess(new 
DatasourceQueryData("otlp-related-metrics-inventory", 200, null, List.of()));
+            }
+            if (query.contains("__name__=\"http_server_duration\"")
+                    && query.contains("http_route=\"POST /checkout\"")
+                    && !query.contains("operation_name=\"POST /checkout\"")) {
+                return promqlSuccess(new DatasourceQueryData(
+                        "otlp-related-metrics",
+                        200,
+                        null,
+                        List.of(new DatasourceQueryData.SchemaData(
+                                new DatasourceQueryData.MetricSchema(
+                                        List.of(
+                                                new 
DatasourceQueryData.MetricField("__ts__", "time", null),
+                                                new 
DatasourceQueryData.MetricField("__value__", "number", null)
+                                        ),
+                                        Map.of("__name__", 
"http_server_duration"),
+                                        Map.of()
+                                ),
+                                Collections.singletonList(new Object[] 
{2_000L, 14.0})
+                        ))
+                ));
+            }
+            return promqlSuccess(new 
DatasourceQueryData("otlp-related-metrics", 200, null, List.of()));
+        });
+
+        OtlpRelatedMetricsDto related = 
otlpIngestionWorkspaceService.getRelatedMetrics(
+                42L,
+                "service",
+                1_000L,
+                2_000L,
+                "checkout",
+                "commerce",
+                "prod",
+                null,
+                "POST /checkout",
+                "8"
+        );
+
+        assertFalse(related.getCandidates().isEmpty());
+        OtlpRelatedMetricsDto.Candidate candidate = 
related.getCandidates().getFirst();
+        assertEquals("http_server_duration", candidate.getQuery());
+        assertEquals("promql-series", candidate.getReason());
+        assertTrue(candidate.getMatchedLabels().contains("http_route"));
+        assertFalse(candidate.getMatchedLabels().contains("operation_name"));
+        assertEquals("POST /checkout", 
candidate.getResourceMatch().get("http_route"));
+        
assertFalse(candidate.getResourceMatch().containsKey("operation_name"));
+    }
+
     @Test
     void relatedMetricsPrefersPromqlAvailableCandidatesWhenExecutorExists() {
         observabilitySignalIntakeGateway.recordOtlpMetricIntake(


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

Reply via email to