feat: add GET /routes/metrics/processors endpoint
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,8 @@ public class OpenApiConfig {
|
||||
"SearchResultExecutionSummary", "UserInfo",
|
||||
"ProcessorNode",
|
||||
"AppCatalogEntry", "RouteSummary", "AgentSummary",
|
||||
"RouteMetrics", "AgentEventResponse", "AgentInstanceResponse"
|
||||
"RouteMetrics", "AgentEventResponse", "AgentInstanceResponse",
|
||||
"ProcessorMetrics"
|
||||
);
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.cameleer3.server.app.controller;
|
||||
|
||||
import com.cameleer3.server.app.dto.ProcessorMetrics;
|
||||
import com.cameleer3.server.app.dto.RouteMetrics;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||
@@ -108,4 +109,56 @@ public class RouteMetricsController {
|
||||
|
||||
return ResponseEntity.ok(metrics);
|
||||
}
|
||||
|
||||
@GetMapping("/metrics/processors")
|
||||
@Operation(summary = "Get processor metrics",
|
||||
description = "Returns aggregated performance metrics per processor for the given route and time window")
|
||||
@ApiResponse(responseCode = "200", description = "Metrics returned")
|
||||
public ResponseEntity<List<ProcessorMetrics>> getProcessorMetrics(
|
||||
@RequestParam String routeId,
|
||||
@RequestParam(required = false) String appId,
|
||||
@RequestParam(required = false) Instant from,
|
||||
@RequestParam(required = false) Instant to) {
|
||||
|
||||
Instant toInstant = to != null ? to : Instant.now();
|
||||
Instant fromInstant = from != null ? from : toInstant.minus(24, ChronoUnit.HOURS);
|
||||
|
||||
var sql = new StringBuilder(
|
||||
"SELECT processor_id, processor_type, route_id, group_name, " +
|
||||
"SUM(total_count) AS total_count, " +
|
||||
"SUM(failed_count) AS failed_count, " +
|
||||
"CASE WHEN SUM(total_count) > 0 THEN SUM(duration_sum)::double precision / SUM(total_count) ELSE 0 END AS avg_duration_ms, " +
|
||||
"MAX(p99_duration) AS p99_duration_ms " +
|
||||
"FROM stats_1m_processor_detail " +
|
||||
"WHERE bucket >= ? AND bucket < ? AND route_id = ?");
|
||||
var params = new ArrayList<Object>();
|
||||
params.add(Timestamp.from(fromInstant));
|
||||
params.add(Timestamp.from(toInstant));
|
||||
params.add(routeId);
|
||||
|
||||
if (appId != null) {
|
||||
sql.append(" AND group_name = ?");
|
||||
params.add(appId);
|
||||
}
|
||||
sql.append(" GROUP BY processor_id, processor_type, route_id, group_name");
|
||||
sql.append(" ORDER BY SUM(total_count) DESC");
|
||||
|
||||
List<ProcessorMetrics> metrics = jdbc.query(sql.toString(), (rs, rowNum) -> {
|
||||
long totalCount = rs.getLong("total_count");
|
||||
long failedCount = rs.getLong("failed_count");
|
||||
double errorRate = failedCount > 0 ? (double) failedCount / totalCount : 0.0;
|
||||
return new ProcessorMetrics(
|
||||
rs.getString("processor_id"),
|
||||
rs.getString("processor_type"),
|
||||
rs.getString("route_id"),
|
||||
rs.getString("group_name"),
|
||||
totalCount,
|
||||
failedCount,
|
||||
rs.getDouble("avg_duration_ms"),
|
||||
rs.getDouble("p99_duration_ms"),
|
||||
errorRate);
|
||||
}, params.toArray());
|
||||
|
||||
return ResponseEntity.ok(metrics);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.cameleer3.server.app.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
public record ProcessorMetrics(
|
||||
@NotNull String processorId,
|
||||
@NotNull String processorType,
|
||||
@NotNull String routeId,
|
||||
@NotNull String appId,
|
||||
long totalCount,
|
||||
long failedCount,
|
||||
double avgDurationMs,
|
||||
double p99DurationMs,
|
||||
double errorRate
|
||||
) {}
|
||||
Reference in New Issue
Block a user