Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 12x 2x 2x 2x 2x 2x 2x 10x 10x 10x 12x 1x 1x 1x 1x 1x 1x 9x 9x 9x 12x 9x 9x 12x 12x 1x 1x 1x 1x 8x 8x 8x 8x 8x 8x 8x 8x 8x 8x 12x 12x 1x 1x | /**
* Performance Aggregation API
*
* GET /api/admin/monitoring/performance/aggregate
*
* Returns aggregated performance metrics grouped by various dimensions.
*/
export const dynamic = 'force-dynamic';
import { NextRequest, NextResponse } from 'next/server';
import { getAggregatedMetrics, type AggregationResult } from '@/lib/monitoring/performanceQueries';
import { logger } from '@/lib/logging';
import {
withAdmin,
withErrorHandling,
successResponse,
errorResponse,
type ApiSuccessResponse,
type ApiErrorResponse,
} from '@/lib/api';
/**
* GET handler for aggregated metrics
*/
async function handleGet(
request: NextRequest
): Promise<NextResponse<ApiSuccessResponse<AggregationResult> | ApiErrorResponse>> {
const { searchParams } = new URL(request.url);
// Parse query parameters
const groupBy = searchParams.get('groupBy');
const metric = searchParams.get('metric') || 'count';
const timeRange = searchParams.get('timeRange') || '24h';
const limit = searchParams.get('limit');
// Validate groupBy (required)
const validGroupBy = ['path', 'method', 'statusCode', 'hour', 'day'];
if (!groupBy || !validGroupBy.includes(groupBy)) {
return errorResponse(
'INVALID_PARAM',
'groupBy is required and must be one of: path, method, statusCode, hour, day',
{ status: 400 }
);
}
// Validate metric
const validMetrics = ['count', 'avgDuration', 'p95Duration', 'errorRate'];
if (!validMetrics.includes(metric)) {
return errorResponse(
'INVALID_PARAM',
'Invalid metric. Must be one of: count, avgDuration, p95Duration, errorRate',
{ status: 400 }
);
}
// Validate time range
const validRanges = ['1h', '6h', '24h', '7d', '30d'];
if (!validRanges.includes(timeRange)) {
return errorResponse(
'INVALID_PARAM',
'Invalid timeRange. Must be one of: 1h, 6h, 24h, 7d, 30d',
{ status: 400 }
);
}
// Validate limit
const limitNum = limit ? parseInt(limit, 10) : 20;
if (isNaN(limitNum) || limitNum < 1 || limitNum > 100) {
return errorResponse('INVALID_PARAM', 'limit must be between 1 and 100', {
status: 400,
});
}
try {
const result = await getAggregatedMetrics({
groupBy: groupBy as 'path' | 'method' | 'statusCode' | 'hour' | 'day',
metric: metric as 'count' | 'avgDuration' | 'p95Duration' | 'errorRate',
timeRange,
limit: limitNum,
});
return successResponse(result);
} catch (error) {
logger.error('Error fetching aggregated metrics', error instanceof Error ? error : new Error(String(error)), { category: 'API' });
return errorResponse('INTERNAL_ERROR', 'Failed to fetch aggregated metrics', {
status: 500,
});
}
}
export const GET = withErrorHandling(withAdmin(handleGet));
|