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 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | /** * Database Performance Metrics API * * GET /api/admin/monitoring/performance/database * * Returns database query performance metrics for the monitoring dashboard. */ export const dynamic = 'force-dynamic'; import { NextRequest, NextResponse } from 'next/server'; import { getDatabaseMetrics } from '@/lib/monitoring/databaseMetrics'; import { detectQueryPatterns, summarizePatterns } from '@/lib/monitoring/queryPatterns'; import { withAdmin, withErrorHandling, successResponse, errorResponse, type ApiSuccessResponse, type ApiErrorResponse, } from '@/lib/api'; /** * Database metrics response type */ interface DatabaseMetricsResponse { metrics: { totalQueries: number; avgDuration: number; slowQueries: Array<{ id: string; name: string; operation: string; tableName: string | null; duration: number; rowCount: number | null; success: boolean; errorType: string | null; timestamp: Date; }>; queryStats: Array<{ tableName: string; avgDuration: number; totalCalls: number; slowCount: number; }>; operationBreakdown: Record<string, number>; }; patterns: ReturnType<typeof summarizePatterns> | null; timeRange: { start: string; end: string; hours: number; }; config: { slowThreshold: number; limit: number; }; } /** * GET handler for database metrics */ async function handleGet( request: NextRequest ): Promise<NextResponse<ApiSuccessResponse<DatabaseMetricsResponse> | ApiErrorResponse>> { // Parse query parameters const { searchParams } = new URL(request.url); const hours = parseInt(searchParams.get('hours') || '24', 10); const slowThreshold = parseInt(searchParams.get('slowThreshold') || '500', 10); const limit = parseInt(searchParams.get('limit') || '20', 10); const includePatterns = searchParams.get('includePatterns') === 'true'; // Validate parameters if (hours < 1 || hours > 720) { return errorResponse('INVALID_PARAM', 'Invalid hours parameter. Must be between 1 and 720.', { status: 400 }); } if (slowThreshold < 1 || slowThreshold > 60000) { return errorResponse('INVALID_PARAM', 'Invalid slowThreshold parameter. Must be between 1 and 60000.', { status: 400 }); } if (limit < 1 || limit > 100) { return errorResponse('INVALID_PARAM', 'Invalid limit parameter. Must be between 1 and 100.', { status: 400 }); } // Calculate time range const endTime = new Date(); const startTime = new Date(endTime.getTime() - hours * 60 * 60 * 1000); // Get database metrics const metrics = await getDatabaseMetrics({ startTime, endTime, limit, slowThreshold, }); // Optionally detect query patterns let patterns = null; if (includePatterns) { const detectedPatterns = await detectQueryPatterns({ timeRange: { start: startTime, end: endTime }, slowThreshold, }); patterns = summarizePatterns(detectedPatterns); } return successResponse({ metrics: { totalQueries: metrics.totalQueries, avgDuration: metrics.avgDuration, slowQueries: metrics.slowQueries.map((q) => ({ id: q.id, name: q.name, operation: q.operation, tableName: q.tableName, duration: q.duration, rowCount: q.rowCount, success: q.success, errorType: q.errorType, timestamp: q.timestamp, })), queryStats: metrics.queryStats, operationBreakdown: metrics.operationBreakdown, }, patterns, timeRange: { start: startTime.toISOString(), end: endTime.toISOString(), hours, }, config: { slowThreshold, limit, }, }); } export const GET = withErrorHandling(withAdmin(handleGet)); |