fix: stamp environment on agent_events rows
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m28s
CI / docker (push) Successful in 1m13s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 43s

The agent_events table has an `environment` column and AgentEventsController
filters on it, but the INSERT never populated it — every row got the
column default ('default'). Result: Timeline on the Application Runtime
page was empty whenever the user's selected env was anything other than
'default'.

Thread env through the write path:
- AgentEventRepository.insert + AgentEventService.recordEvent gain an
  `environment` param; delete the no-env query overload (unused).
- ClickHouseAgentEventRepository.insert writes the column (falls back to
  'default' on null to match column DEFAULT).
- All 5 callers source env from the agent registry (AgentInfo.environmentId)
  or the registration request body; AgentLifecycleMonitor, deregister,
  command ack, event ingestion, register/re-register.
- Integration test updated for the new signatures.

Pre-existing rows in deployed CH will still report environment='default'.
New events from this build forward will carry the correct env. Backfill
(UPDATE ... FROM apps) is left as a manual DB step if historical timeline
is needed for non-default envs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-17 10:30:56 +02:00
parent 5807cfd807
commit 62dd71b860
8 changed files with 35 additions and 41 deletions

View File

@@ -55,7 +55,8 @@ public class AgentLifecycleMonitor {
if (before != null && before != agent.state()) {
String eventType = mapTransitionEvent(before, agent.state());
if (eventType != null) {
agentEventService.recordEvent(agent.instanceId(), agent.applicationId(), eventType,
agentEventService.recordEvent(agent.instanceId(), agent.applicationId(),
agent.environmentId(), eventType,
agent.displayName() + " " + before + " -> " + agent.state());
serverMetrics.recordAgentTransition(eventType);
}

View File

@@ -223,7 +223,8 @@ public class AgentCommandController {
if (body != null && body.status() != null) {
AgentInfo agent = registryService.findById(id);
String application = agent != null ? agent.applicationId() : "unknown";
agentEventService.recordEvent(id, application, "COMMAND_" + body.status(),
String environment = agent != null ? agent.environmentId() : null;
agentEventService.recordEvent(id, application, environment, "COMMAND_" + body.status(),
"Command " + commandId + ": " + body.message());
log.debug("Command {} ack from agent {}: {} - {}", commandId, id, body.status(), body.message());
}

View File

@@ -143,12 +143,12 @@ public class AgentRegistrationController {
if (reRegistration) {
log.info("Agent re-registered: {} (application={}, routes={}, capabilities={})",
request.instanceId(), application, routeIds.size(), capabilities.keySet());
agentEventService.recordEvent(request.instanceId(), application, "RE_REGISTERED",
agentEventService.recordEvent(request.instanceId(), application, environmentId, "RE_REGISTERED",
"Agent re-registered with " + routeIds.size() + " routes");
} else {
log.info("Agent registered: {} (application={}, routes={})",
request.instanceId(), application, routeIds.size());
agentEventService.recordEvent(request.instanceId(), application, "REGISTERED",
agentEventService.recordEvent(request.instanceId(), application, environmentId, "REGISTERED",
"Agent registered: " + request.instanceId());
}
@@ -315,8 +315,9 @@ public class AgentRegistrationController {
return ResponseEntity.notFound().build();
}
String applicationId = agent.applicationId();
String environment = agent.environmentId();
registryService.deregister(id);
agentEventService.recordEvent(id, applicationId, "DEREGISTERED", "Agent deregistered");
agentEventService.recordEvent(id, applicationId, environment, "DEREGISTERED", "Agent deregistered");
auditService.log(id, "agent_deregister", AuditCategory.AGENT, id, null, AuditResult.SUCCESS, httpRequest);
return ResponseEntity.ok().build();
}

View File

@@ -71,9 +71,10 @@ public class EventIngestionController {
AgentInfo agent = registryService.findById(instanceId);
String applicationId = agent != null ? agent.applicationId() : "";
String environment = agent != null ? agent.environmentId() : null;
for (AgentEvent event : events) {
agentEventService.recordEvent(instanceId, applicationId,
agentEventService.recordEvent(instanceId, applicationId, environment,
event.getEventType(),
event.getDetails() != null ? event.getDetails().toString() : null);

View File

@@ -18,7 +18,7 @@ import java.util.List;
public class ClickHouseAgentEventRepository implements AgentEventRepository {
private static final String INSERT_SQL =
"INSERT INTO agent_events (tenant_id, instance_id, application_id, event_type, detail) VALUES (?, ?, ?, ?, ?)";
"INSERT INTO agent_events (tenant_id, instance_id, application_id, environment, event_type, detail) VALUES (?, ?, ?, ?, ?, ?)";
private static final String SELECT_BASE =
"SELECT 0 AS id, instance_id, application_id, event_type, detail, timestamp FROM agent_events WHERE tenant_id = ?";
@@ -32,13 +32,9 @@ public class ClickHouseAgentEventRepository implements AgentEventRepository {
}
@Override
public void insert(String instanceId, String applicationId, String eventType, String detail) {
jdbc.update(INSERT_SQL, tenantId, instanceId, applicationId, eventType, detail);
}
@Override
public List<AgentEventRecord> query(String applicationId, String instanceId, Instant from, Instant to, int limit) {
return query(applicationId, instanceId, null, from, to, limit);
public void insert(String instanceId, String applicationId, String environment, String eventType, String detail) {
jdbc.update(INSERT_SQL, tenantId, instanceId, applicationId,
environment != null ? environment : "default", eventType, detail);
}
@Override