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 bd5edde109 Match trace operation filters against child spans
bd5edde109 is described below

commit bd5edde10958f7bcbc6732d94da3583510944060
Author: Logic <[email protected]>
AuthorDate: Wed Jun 10 08:57:58 2026 +0800

    Match trace operation filters against child spans
---
 .../service/impl/EntityTraceQueryServiceImpl.java  | 16 +++++++++-
 .../impl/EntityTraceQueryServiceImplTest.java      | 34 ++++++++++++++++++++++
 2 files changed, 49 insertions(+), 1 deletion(-)

diff --git 
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImpl.java
 
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImpl.java
index 37fb8d810c..d164ff0136 100644
--- 
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImpl.java
+++ 
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImpl.java
@@ -1074,7 +1074,7 @@ public class EntityTraceQueryServiceImpl implements 
EntityTraceQueryService {
                 && 
!environment.equalsIgnoreCase(trace.getResourceAttributes().get("deployment.environment.name")))
 {
             return false;
         }
-        if (StringUtils.hasText(operationName) && 
!operationName.equalsIgnoreCase(trace.getRootSpanName())) {
+        if (!matchesTraceOperation(trace, operationName)) {
             return false;
         }
         if (minDurationNanos != null && (trace.getDurationNanos() == null || 
trace.getDurationNanos() < minDurationNanos)) {
@@ -1090,6 +1090,20 @@ public class EntityTraceQueryServiceImpl implements 
EntityTraceQueryService {
                 && matchesSpanAttributeFilters(trace, attributeFilters);
     }
 
+    private boolean matchesTraceOperation(TraceAggregate trace, String 
operationName) {
+        String normalizedOperationName = 
StringUtils.trimWhitespace(operationName);
+        if (!StringUtils.hasText(normalizedOperationName)) {
+            return true;
+        }
+        if (normalizedOperationName.equalsIgnoreCase(trace.getRootSpanName())) 
{
+            return true;
+        }
+        return trace.spans.stream()
+                .map(TraceSpanNodeDto::getSpanName)
+                .filter(StringUtils::hasText)
+                .anyMatch(normalizedOperationName::equalsIgnoreCase);
+    }
+
     private String normalizeSpanScope(String spanScope) {
         String normalized = StringUtils.trimWhitespace(spanScope);
         if (!StringUtils.hasText(normalized)) {
diff --git 
a/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImplTest.java
 
b/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImplTest.java
index c02d55340f..f561c4d8fd 100644
--- 
a/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImplTest.java
+++ 
b/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/traces/service/impl/EntityTraceQueryServiceImplTest.java
@@ -541,6 +541,40 @@ class EntityTraceQueryServiceImplTest {
                 org.mockito.ArgumentMatchers.<Map<String, Set<String>>>any(), 
eq(true));
     }
 
+    @Test
+    void queryTraceListMatchesOperationNameAgainstChildSpansWithRowFallback() {
+        long now = System.currentTimeMillis();
+        long start = now - 120_000;
+        long end = now;
+        when(traceQueryRepository.queryRecentTraceRows(
+                eq(1500), eq(start), eq(end), eq("checkout-service"), 
org.mockito.ArgumentMatchers.isNull(),
+                org.mockito.ArgumentMatchers.isNull(), eq("SELECT cart"),
+                org.mockito.ArgumentMatchers.isNull(), 
org.mockito.ArgumentMatchers.isNull(),
+                org.mockito.ArgumentMatchers.isNull(), 
org.mockito.ArgumentMatchers.<Map<String, Set<String>>>any(),
+                eq(true))).thenReturn(List.of(
+                traceRow("trace-cart", "span-root", null, "GET /checkout", 
"checkout-service", "STATUS_CODE_OK",
+                        now - 10_000, 5_000_000L,
+                        Map.of("service.name", "checkout-service")),
+                traceRow("trace-cart", "span-child", "span-root", "SELECT 
cart", "checkout-service", "STATUS_CODE_OK",
+                        now - 9_000, 1_000_000L,
+                        Map.of("service.name", "checkout-service"))
+        ));
+
+        var page = entityTraceQueryService.queryTraceList(null, start, end, 
null,
+                false, "checkout-service", null, null,
+                null, "SELECT cart", null, null, 0, 20, true);
+
+        assertEquals(1, page.getTotalElements());
+        assertEquals("trace-cart", page.getContent().getFirst().getTraceId());
+        assertEquals("GET /checkout", 
page.getContent().getFirst().getRootSpanName());
+        verify(traceQueryRepository).queryRecentTraceRows(
+                eq(1500), eq(start), eq(end), eq("checkout-service"), 
org.mockito.ArgumentMatchers.isNull(),
+                org.mockito.ArgumentMatchers.isNull(), eq("SELECT cart"),
+                org.mockito.ArgumentMatchers.isNull(), 
org.mockito.ArgumentMatchers.isNull(),
+                org.mockito.ArgumentMatchers.isNull(), 
org.mockito.ArgumentMatchers.<Map<String, Set<String>>>any(),
+                eq(true));
+    }
+
     @Test
     void 
queryTraceListPushesWorkspaceTimeEnvironmentAndEntityFiltersToRepository() {
         long now = System.currentTimeMillis();


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

Reply via email to