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 6527b579b3 Support log trend IN filters
6527b579b3 is described below
commit 6527b579b3728cb38e062d196eff1c7417bd2a6f
Author: Logic <[email protected]>
AuthorDate: Tue Jun 9 21:12:02 2026 +0800
Support log trend IN filters
---
.../logs/service/impl/LogQueryServiceImpl.java | 17 +++---
.../logs/controller/LogQueryControllerTest.java | 71 ++++++++++++++++++++++
2 files changed, 81 insertions(+), 7 deletions(-)
diff --git
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/service/impl/LogQueryServiceImpl.java
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/service/impl/LogQueryServiceImpl.java
index 495d85f0c5..4bac5a6a2d 100644
---
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/service/impl/LogQueryServiceImpl.java
+++
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/service/impl/LogQueryServiceImpl.java
@@ -320,8 +320,8 @@ public class LogQueryServiceImpl implements LogQueryService
{
String serviceName, String
serviceNamespace, String environment,
String resourceFilter, String
attributeFilter,
boolean hideInternal, boolean
hideNoise) {
- Map<String, String> resourceFilters =
parseLogAttributeFilter(resourceFilter);
- Map<String, String> attributeFilters =
parseLogAttributeFilter(attributeFilter);
+ Map<String, String> resourceFilters =
parseLogAttributeFilter(resourceFilter, true);
+ Map<String, String> attributeFilters =
parseLogAttributeFilter(attributeFilter, true);
return trendStatsWithFilters(start, end, traceId, spanId,
severityNumber, severityText, search,
serviceName, serviceNamespace, environment, resourceFilters,
attributeFilters, hideInternal, hideNoise);
}
@@ -334,8 +334,8 @@ public class LogQueryServiceImpl implements LogQueryService
{
boolean hideInternal, boolean
hideNoise) {
LogServiceContext context =
resolveEntityFirstLogServiceContext(entityId, serviceName, serviceNamespace,
environment);
Map<String, String> resourceFilters = removeEntityScopeResourceFilters(
- context, parseLogAttributeFilter(resourceFilter));
- Map<String, String> attributeFilters =
parseLogAttributeFilter(attributeFilter);
+ context, parseLogAttributeFilter(resourceFilter, true));
+ Map<String, String> attributeFilters =
parseLogAttributeFilter(attributeFilter, true);
return trendStatsWithFilters(start, end, traceId, spanId,
severityNumber, severityText, search,
context.serviceName(), context.serviceNamespace(),
context.environment(), resourceFilters, attributeFilters,
hideInternal, hideNoise);
@@ -347,9 +347,12 @@ public class LogQueryServiceImpl implements
LogQueryService {
Map<String, String>
resourceFilters,
Map<String, String>
attributeFilters,
boolean hideInternal,
boolean hideNoise) {
- Map<String, Long> aggregate = readHourlyStats(start, end, traceId,
spanId, severityNumber,
- severityText, search, serviceName, serviceNamespace,
environment, resourceFilters, attributeFilters,
- hideInternal, hideNoise);
+ Map<String, Long> aggregate = null;
+ if (!hasComplexAttributeFilters(resourceFilters, attributeFilters)) {
+ aggregate = readHourlyStats(start, end, traceId, spanId,
severityNumber,
+ severityText, search, serviceName, serviceNamespace,
environment, resourceFilters, attributeFilters,
+ hideInternal, hideNoise);
+ }
if (aggregate != null) {
Map<String, Object> result = new HashMap<>();
result.put("hourlyStats", aggregate);
diff --git
a/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/logs/controller/LogQueryControllerTest.java
b/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/logs/controller/LogQueryControllerTest.java
index 3a168f4758..6c83fabc10 100644
---
a/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/logs/controller/LogQueryControllerTest.java
+++
b/hertzbeat-observability/src/test/java/org/apache/hertzbeat/observability/logs/controller/LogQueryControllerTest.java
@@ -29,6 +29,10 @@ import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static
org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -1448,6 +1452,73 @@ class LogQueryControllerTest {
.andExpect(jsonPath("$.data.hourlyStats").isMap());
}
+ @Test
+ void testTrendStatsAppliesInAndNotInFiltersWithRowFallback() throws
Exception {
+ long bucketTimeUnixNano = 1734005477630000000L;
+ String bucketKey = LocalDateTime.ofInstant(
+ Instant.ofEpochMilli(bucketTimeUnixNano / 1_000_000L),
+ ZoneId.systemDefault())
+ .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00"));
+ LogEntry stableLog = LogEntry.builder()
+ .timeUnixNano(bucketTimeUnixNano)
+ .severityText("INFO")
+ .body("stable checkout trend")
+ .resource(new HashMap<>(Map.of(
+ "service.name", "checkout",
+ "service.version", "1.2.3",
+ "host.name", "checkout-1")))
+ .attributes(new HashMap<>(Map.of("http.route", "/checkout")))
+ .build();
+ LogEntry secondStableLog = LogEntry.builder()
+ .timeUnixNano(bucketTimeUnixNano + 1_000_000L)
+ .severityText("ERROR")
+ .body("second checkout trend")
+ .resource(new HashMap<>(Map.of(
+ "service.name", "checkout",
+ "service.version", "1.2.4",
+ "host.name", "checkout-2")))
+ .attributes(new HashMap<>(Map.of("http.route", "/checkout")))
+ .build();
+ LogEntry canaryLog = LogEntry.builder()
+ .timeUnixNano(bucketTimeUnixNano + 2_000_000L)
+ .severityText("WARN")
+ .body("canary checkout trend")
+ .resource(new HashMap<>(Map.of(
+ "service.name", "checkout",
+ "service.version", "1.2.3",
+ "host.name", "checkout-canary")))
+ .attributes(new HashMap<>(Map.of("http.route", "/checkout")))
+ .build();
+ LogEntry cartLog = LogEntry.builder()
+ .timeUnixNano(bucketTimeUnixNano + 3_000_000L)
+ .severityText("INFO")
+ .body("cart checkout trend")
+ .resource(new HashMap<>(Map.of(
+ "service.name", "checkout",
+ "service.version", "1.2.4",
+ "host.name", "checkout-3")))
+ .attributes(new HashMap<>(Map.of("http.route", "/cart")))
+ .build();
+ when(historyDataReader.queryLogsByMultipleConditions(any(), any(),
any(),
+ any(), any(), any(), any())).thenReturn(List.of(stableLog,
secondStableLog, canaryLog, cartLog));
+
+ mockMvc.perform(MockMvcRequestBuilders.get("/api/logs/stats/trend")
+ .param("resourceFilter", "service.version IN ('1.2.3',
'1.2.4') "
+ + "and host.name NOT IN ('checkout-canary')")
+ .param("attributeFilter", "http.route IN
('/checkout')"))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.code").value((int)
CommonConstants.SUCCESS_CODE))
+ .andExpect(jsonPath("$.data.hourlyStats.length()").value(1))
+ .andExpect(jsonPath("$.data.hourlyStats['" + bucketKey +
"']").value(2));
+
+ verify(historyDataReader).queryLogsByMultipleConditions(any(), any(),
any(),
+ any(), any(), any(), any());
+ verify(historyDataReader, never()).countLogsByHour(any(), any(),
any(), any(), any(), any(), any(),
+ anySet(), eq(false), any(), any(), any(), any(),
+ org.mockito.ArgumentMatchers.<Map<String, String>>any(),
+ org.mockito.ArgumentMatchers.<Map<String, String>>any());
+ }
+
@Test
void testTrendStatsUsesStorageAggregateWhenAvailable() throws Exception {
when(historyDataReader.countLogsByHour(any(), any(), any(), any(),
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]