feat: exchange-level log viewer on ExchangeDetail page
All checks were successful
CI / build (push) Successful in 1m0s
CI / cleanup-branch (push) Has been skipped
CI / docker (push) Successful in 49s
CI / deploy (push) Successful in 37s
CI / deploy-feature (push) Has been skipped

Index exchangeId from Camel MDC (camel.exchangeId) as a top-level
keyword field in OpenSearch log indices. Add exchangeId filter to
the log query API and frontend hook. Show a LogViewer on the
ExchangeDetail page filtered to that exchange's logs, with search
input and level filter pills.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-26 10:26:30 +01:00
parent f9bd492191
commit ea665ff411
5 changed files with 190 additions and 6 deletions

View File

@@ -32,6 +32,7 @@ public class LogQueryController {
@RequestParam(required = false) String agentId,
@RequestParam(required = false) String level,
@RequestParam(required = false) String query,
@RequestParam(required = false) String exchangeId,
@RequestParam(required = false) String from,
@RequestParam(required = false) String to,
@RequestParam(defaultValue = "200") int limit) {
@@ -42,7 +43,7 @@ public class LogQueryController {
Instant toInstant = to != null ? Instant.parse(to) : null;
List<LogEntryResponse> entries = logIndex.search(
application, agentId, level, query, fromInstant, toInstant, limit);
application, agentId, level, query, exchangeId, fromInstant, toInstant, limit);
return ResponseEntity.ok(entries);
}

View File

@@ -76,7 +76,8 @@ public class OpenSearchLogIndex {
.properties("threadName", Property.of(p -> p.keyword(k -> k)))
.properties("stackTrace", Property.of(p -> p.text(tx -> tx)))
.properties("agentId", Property.of(p -> p.keyword(k -> k)))
.properties("application", Property.of(p -> p.keyword(k -> k)))))));
.properties("application", Property.of(p -> p.keyword(k -> k)))
.properties("exchangeId", Property.of(p -> p.keyword(k -> k)))))));
log.info("OpenSearch log index template '{}' created", templateName);
}
} catch (IOException e) {
@@ -100,13 +101,17 @@ public class OpenSearchLogIndex {
}
public List<LogEntryResponse> search(String application, String agentId, String level,
String query, Instant from, Instant to, int limit) {
String query, String exchangeId,
Instant from, Instant to, int limit) {
try {
BoolQuery.Builder bool = new BoolQuery.Builder();
bool.must(Query.of(q -> q.term(t -> t.field("application").value(FieldValue.of(application)))));
if (agentId != null && !agentId.isEmpty()) {
bool.must(Query.of(q -> q.term(t -> t.field("agentId").value(FieldValue.of(agentId)))));
}
if (exchangeId != null && !exchangeId.isEmpty()) {
bool.must(Query.of(q -> q.term(t -> t.field("exchangeId").value(FieldValue.of(exchangeId)))));
}
if (level != null && !level.isEmpty()) {
bool.must(Query.of(q -> q.term(t -> t.field("level").value(FieldValue.of(level.toUpperCase())))));
}
@@ -205,6 +210,10 @@ public class OpenSearchLogIndex {
doc.put("mdc", entry.getMdc());
doc.put("agentId", agentId);
doc.put("application", application);
if (entry.getMdc() != null) {
String exId = entry.getMdc().get("camel.exchangeId");
if (exId != null) doc.put("exchangeId", exId);
}
return doc;
}
}