feat(logs): widen source filter to multi-value OR list

Replaces LogSearchRequest.source (String) with sources (List<String>)
and emits 'source IN (...)' when non-empty. LogQueryController parses
?source=a,b,c the same way it parses ?level=a,b,c.
This commit is contained in:
hsiegeln
2026-04-17 11:48:10 +02:00
parent e8d6cc5b5d
commit 769752a327
4 changed files with 69 additions and 9 deletions

View File

@@ -323,4 +323,52 @@ class ClickHouseLogStoreIT {
String.class);
assertThat(customVal).isEqualTo("custom-value");
}
@Test
void search_bySources_singleValue_filtersCorrectly() {
Instant now = Instant.parse("2026-03-31T12:00:00Z");
// "source" column is populated by indexBatch via LogEntry.getSource(); default is "app" when null.
// Force one row to "container" via a direct insert to avoid coupling to LogEntry constructor.
store.indexBatch("agent-1", "my-app", List.of(
entry(now, "INFO", "logger", "app msg", "t1", null, null)
));
jdbc.update("INSERT INTO logs (tenant_id, environment, timestamp, application, instance_id, level, " +
"logger_name, message, thread_name, stack_trace, exchange_id, mdc, source) VALUES " +
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"default", "default", java.sql.Timestamp.from(now.plusSeconds(1)), "my-app", "agent-1",
"INFO", "logger", "container msg", "t1", "", "", java.util.Map.of(), "container");
LogSearchResponse result = store.search(new LogSearchRequest(
null, null, "my-app", null, null, null, null,
List.of("container"), null, null, null, 100, "desc"));
assertThat(result.data()).hasSize(1);
assertThat(result.data().get(0).message()).isEqualTo("container msg");
}
@Test
void search_bySources_multiValue_joinsAsOr() {
Instant now = Instant.parse("2026-03-31T12:00:00Z");
store.indexBatch("agent-1", "my-app", List.of(
entry(now, "INFO", "logger", "app msg", "t1", null, null)
));
jdbc.update("INSERT INTO logs (tenant_id, environment, timestamp, application, instance_id, level, " +
"logger_name, message, thread_name, stack_trace, exchange_id, mdc, source) VALUES " +
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"default", "default", java.sql.Timestamp.from(now.plusSeconds(1)), "my-app", "agent-1",
"INFO", "logger", "container msg", "t1", "", "", java.util.Map.of(), "container");
jdbc.update("INSERT INTO logs (tenant_id, environment, timestamp, application, instance_id, level, " +
"logger_name, message, thread_name, stack_trace, exchange_id, mdc, source) VALUES " +
"(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"default", "default", java.sql.Timestamp.from(now.plusSeconds(2)), "my-app", "agent-1",
"INFO", "logger", "agent msg", "t1", "", "", java.util.Map.of(), "agent");
LogSearchResponse result = store.search(new LogSearchRequest(
null, null, "my-app", null, null, null, null,
List.of("app", "container"), null, null, null, 100, "desc"));
assertThat(result.data()).hasSize(2);
assertThat(result.data()).extracting(LogEntryResult::message)
.containsExactlyInAnyOrder("app msg", "container msg");
}
}