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 65b0dbacca Scope log queries by entity id
65b0dbacca is described below
commit 65b0dbacca2f5703f3387aeed8369ffa156f1fdf
Author: Logic <[email protected]>
AuthorDate: Tue Jun 9 20:32:51 2026 +0800
Scope log queries by entity id
---
.../logs/controller/LogQueryController.java | 35 ++++++++++++++--------
.../logs/controller/LogQueryControllerTest.java | 24 +++++++++++----
2 files changed, 40 insertions(+), 19 deletions(-)
diff --git
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/controller/LogQueryController.java
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/controller/LogQueryController.java
index c6a7b72266..9fa606eee7 100644
---
a/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/controller/LogQueryController.java
+++
b/hertzbeat-observability/src/main/java/org/apache/hertzbeat/observability/logs/controller/LogQueryController.java
@@ -89,7 +89,7 @@ public class LogQueryController {
@RequestParam(value = "hideInternal", required = false,
defaultValue = "false") boolean hideInternal,
@Parameter(description = "Hide demo infrastructure noise logs such
as kafka/load-generator when focusing on business requests", example = "true")
@RequestParam(value = "hideNoise", required = false, defaultValue
= "false") boolean hideNoise) {
- String scopedResourceFilter =
mergeEntityTypeResourceFilter(entityType, resourceFilter);
+ String scopedResourceFilter =
mergeEntityContextResourceFilter(entityId, entityType, resourceFilter);
Page<LogEntry> result = logQueryService.list(entityId, start, end,
traceId, spanId, severityNumber, severityText, search,
serviceName, serviceNamespace, environment,
scopedResourceFilter, attributeFilter,
pageIndex, pageSize, hideInternal, hideNoise);
@@ -130,7 +130,7 @@ public class LogQueryController {
@RequestParam(value = "hideInternal", required = false,
defaultValue = "false") boolean hideInternal,
@Parameter(description = "Hide demo infrastructure noise logs such
as kafka/load-generator when focusing on business requests", example = "true")
@RequestParam(value = "hideNoise", required = false, defaultValue
= "false") boolean hideNoise) {
- String scopedResourceFilter =
mergeEntityTypeResourceFilter(entityType, resourceFilter);
+ String scopedResourceFilter =
mergeEntityContextResourceFilter(entityId, entityType, resourceFilter);
return ResponseEntity.ok(Message.success(logQueryService.context(
entityId, logTimeUnixNano, start, end, serviceName,
serviceNamespace, environment,
scopedResourceFilter, attributeFilter, limit, direction,
cursorLogTimeUnixNano, hideInternal, hideNoise)));
@@ -172,7 +172,7 @@ public class LogQueryController {
@RequestParam(value = "hideInternal", required = false,
defaultValue = "false") boolean hideInternal,
@Parameter(description = "Hide demo infrastructure noise logs such
as kafka/load-generator when focusing on business requests", example = "true")
@RequestParam(value = "hideNoise", required = false, defaultValue
= "false") boolean hideNoise) {
- String scopedResourceFilter =
mergeEntityTypeResourceFilter(entityType, resourceFilter);
+ String scopedResourceFilter =
mergeEntityContextResourceFilter(entityId, entityType, resourceFilter);
return ResponseEntity.ok(Message.success(logQueryService.overviewStats(
entityId, start, end, traceId, spanId, severityNumber,
severityText, search,
serviceName, serviceNamespace, environment,
scopedResourceFilter, attributeFilter,
@@ -215,7 +215,7 @@ public class LogQueryController {
@RequestParam(value = "hideInternal", required = false,
defaultValue = "false") boolean hideInternal,
@Parameter(description = "Hide demo infrastructure noise logs such
as kafka/load-generator when focusing on business requests", example = "true")
@RequestParam(value = "hideNoise", required = false, defaultValue
= "false") boolean hideNoise) {
- String scopedResourceFilter =
mergeEntityTypeResourceFilter(entityType, resourceFilter);
+ String scopedResourceFilter =
mergeEntityContextResourceFilter(entityId, entityType, resourceFilter);
return
ResponseEntity.ok(Message.success(logQueryService.traceCoverageStats(
entityId, start, end, traceId, spanId, severityNumber,
severityText, search,
serviceName, serviceNamespace, environment,
scopedResourceFilter, attributeFilter,
@@ -258,7 +258,7 @@ public class LogQueryController {
@RequestParam(value = "hideInternal", required = false,
defaultValue = "false") boolean hideInternal,
@Parameter(description = "Hide demo infrastructure noise logs such
as kafka/load-generator when focusing on business requests", example = "true")
@RequestParam(value = "hideNoise", required = false, defaultValue
= "false") boolean hideNoise) {
- String scopedResourceFilter =
mergeEntityTypeResourceFilter(entityType, resourceFilter);
+ String scopedResourceFilter =
mergeEntityContextResourceFilter(entityId, entityType, resourceFilter);
return ResponseEntity.ok(Message.success(logQueryService.trendStats(
entityId, start, end, traceId, spanId, severityNumber,
severityText, search,
serviceName, serviceNamespace, environment,
scopedResourceFilter, attributeFilter,
@@ -309,26 +309,35 @@ public class LogQueryController {
@RequestParam(value = "hideInternal", required = false,
defaultValue = "false") boolean hideInternal,
@Parameter(description = "Hide demo infrastructure noise logs such
as kafka/load-generator when focusing on business requests", example = "true")
@RequestParam(value = "hideNoise", required = false, defaultValue
= "false") boolean hideNoise) {
- String scopedResourceFilter =
mergeEntityTypeResourceFilter(entityType, resourceFilter);
+ String scopedResourceFilter =
mergeEntityContextResourceFilter(entityId, entityType, resourceFilter);
return ResponseEntity.ok(Message.success(logQueryService.groupByStats(
entityId, start, end, traceId, spanId, severityNumber,
severityText, search,
serviceName, serviceNamespace, environment,
scopedResourceFilter, attributeFilter, groupBy,
limit, orderBy, minCount, hideInternal, hideNoise)));
}
- private String mergeEntityTypeResourceFilter(String entityType, String
resourceFilter) {
+ private String mergeEntityContextResourceFilter(Long entityId, String
entityType, String resourceFilter) {
String normalizedResourceFilter =
StringUtils.trimWhitespace(resourceFilter);
+ String scopedResourceFilter = normalizedResourceFilter;
+ if (entityId != null && entityId > 0 &&
(StringUtils.hasText(scopedResourceFilter)
+ ?
!scopedResourceFilter.contains(OtlpResourceSemanticAttributes.HERTZBEAT_ENTITY_ID)
+ : true)) {
+ String entityIdFilter =
OtlpResourceSemanticAttributes.HERTZBEAT_ENTITY_ID + "=\"" + entityId + "\"";
+ scopedResourceFilter = StringUtils.hasText(scopedResourceFilter)
+ ? scopedResourceFilter + " and " + entityIdFilter
+ : entityIdFilter;
+ }
String normalizedEntityType = StringUtils.trimWhitespace(entityType);
if (!StringUtils.hasText(normalizedEntityType) ||
!normalizedEntityType.matches("[A-Za-z0-9_.:-]+")) {
- return normalizedResourceFilter;
+ return scopedResourceFilter;
}
- if (StringUtils.hasText(normalizedResourceFilter)
- &&
normalizedResourceFilter.contains(OtlpResourceSemanticAttributes.HERTZBEAT_ENTITY_TYPE))
{
- return normalizedResourceFilter;
+ if (StringUtils.hasText(scopedResourceFilter)
+ &&
scopedResourceFilter.contains(OtlpResourceSemanticAttributes.HERTZBEAT_ENTITY_TYPE))
{
+ return scopedResourceFilter;
}
String entityTypeFilter =
OtlpResourceSemanticAttributes.HERTZBEAT_ENTITY_TYPE + "=\"" +
normalizedEntityType + "\"";
- return StringUtils.hasText(normalizedResourceFilter)
- ? normalizedResourceFilter + " and " + entityTypeFilter
+ return StringUtils.hasText(scopedResourceFilter)
+ ? scopedResourceFilter + " and " + entityTypeFilter
: entityTypeFilter;
}
}
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 66abfd8e21..cede67c0f2 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
@@ -300,7 +300,8 @@ class LogQueryControllerTest {
.resource(new HashMap<>(Map.of(
"service.name", "checkout",
"service.namespace", "payments",
- "deployment.environment.name", "prod")))
+ "deployment.environment.name", "prod",
+ "hertzbeat.entity_id", "42")))
.build();
LogEntry billingStagingLog = LogEntry.builder()
.timeUnixNano(1734005477640000000L)
@@ -311,11 +312,14 @@ class LogQueryControllerTest {
"service.namespace", "wrong-namespace",
"deployment.environment.name", "staging")))
.build();
+ Map<String, String> expectedResourceFilters =
Map.of("hertzbeat.entity_id", "42");
when(historyDataReader.countLogsByMultipleConditions(any(), any(),
any(), any(), any(), any(), any(),
- anySet(), eq(false), eq(null), eq("checkout"), eq("payments"),
eq("prod")))
+ anySet(), eq(false), eq(null), eq("checkout"), eq("payments"),
eq("prod"),
+ eq(expectedResourceFilters), eq(Map.of())))
.thenReturn(2L);
when(historyDataReader.queryLogsByMultipleConditionsWithPagination(any(),
any(), any(), any(), any(), any(),
- any(), eq(0), eq(20), anySet(), eq(false), eq(null),
eq("checkout"), eq("payments"), eq("prod")))
+ any(), eq(0), eq(20), anySet(), eq(false), eq(null),
eq("checkout"), eq("payments"), eq("prod"),
+ eq(expectedResourceFilters), eq(Map.of())))
.thenReturn(List.of(checkoutProdLog, billingStagingLog));
mockMvc.perform(MockMvcRequestBuilders.get("/api/logs/list")
@@ -363,7 +367,9 @@ class LogQueryControllerTest {
.priority(20)
.build()
));
- Map<String, String> expectedResourceFilters =
Map.of("service.version", "1.2.3");
+ Map<String, String> expectedResourceFilters = Map.of(
+ "service.version", "1.2.3",
+ "hertzbeat.entity_id", "42");
Map<String, String> expectedAttributeFilters = Map.of("http.route",
"/checkout");
when(historyDataReader.countLogsBySeverityBuckets(any(), any(), any(),
any(), any(), any(), any(),
anySet(), eq(false), org.mockito.ArgumentMatchers.isNull(),
eq("checkout"), eq("payments"), eq("prod"),
@@ -439,10 +445,13 @@ class LogQueryControllerTest {
"service.name", "checkout",
"service.namespace", "payments",
"deployment.environment.name", "prod",
- "service.version", "1.2.3")))
+ "service.version", "1.2.3",
+ "hertzbeat.entity_id", "42")))
.attributes(new HashMap<>(Map.of("http.route", "/checkout")))
.build();
- Map<String, String> expectedResourceFilters =
Map.of("service.version", "1.2.3");
+ Map<String, String> expectedResourceFilters = Map.of(
+ "service.version", "1.2.3",
+ "hertzbeat.entity_id", "42");
Map<String, String> expectedAttributeFilters = Map.of("http.route",
"/checkout");
when(historyDataReader.queryLogsByMultipleConditions(any(), any(),
any(), any(), any(), any(), any(),
anySet(), eq(false), org.mockito.ArgumentMatchers.isNull(),
eq("checkout"), eq("payments"), eq("prod"),
@@ -632,6 +641,7 @@ class LogQueryControllerTest {
.resource(new HashMap<>(java.util.Map.of(
"service.name", "checkout",
"service.version", "1.2.3",
+ "hertzbeat.entity_id", "42",
"hertzbeat.entity_type", "service",
"hertzbeat.workspace_id", "team-a")))
.attributes(new HashMap<>(java.util.Map.of("http.route",
"/checkout")))
@@ -639,6 +649,7 @@ class LogQueryControllerTest {
Map<String, String> expectedResourceFilters = Map.of(
"service.version", "1.2.3",
+ "hertzbeat.entity_id", "42",
"hertzbeat.entity_type", "service"
);
AuthTokenRequestContext.bindWorkspaceId("team-a");
@@ -652,6 +663,7 @@ class LogQueryControllerTest {
.thenReturn(List.of(filteredLog));
mockMvc.perform(MockMvcRequestBuilders.get("/api/logs/list")
+ .param("entityId", "42")
.param("entityType", "service")
.param("resourceFilter", "service.version=1.2.3")
.param("attributeFilter", "http.route:/checkout"))
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]