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 | export const dynamic = "force-dynamic"; import { NextRequest, NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; import { logger, type LogCategory } from '@/lib/logging'; import crypto from 'crypto'; type RouteHandler = ( request: NextRequest, context?: { params: Promise<Record<string, string>> } ) => Promise<NextResponse>; interface MonitoringOptions { name: string; category?: LogCategory; slowThreshold?: number; // ms, default 1000 logSuccessful?: boolean; // default true } export function withMonitoring( handler: RouteHandler, options: MonitoringOptions ): RouteHandler { const { name, category = 'API', slowThreshold = 1000, logSuccessful = true} = options; return async (request, context) => { const startTime = performance.now(); const requestId = request.headers.get('x-request-id') || crypto.randomUUID(); // Extract user info if available (from session/auth) let userId: number | undefined; try { const response = await handler(request, context); const duration = performance.now() - startTime; // Log request if (logSuccessful) { logger.info(`${request.method} ${name}`, { category, requestId, duration: Number(duration.toFixed(2)), statusCode: response.status, method: request.method, url: request.url}); } // Store performance metric if (process.env.NODE_ENV === 'production') { prisma.performanceMetric.create({ data: { type: 'api', name, duration, method: request.method, statusCode: response.status, userId, requestId}}).catch(() => {}); // Non-blocking } // Log slow requests if (duration > slowThreshold) { logger.warn(`Slow API: ${name}`, { category, requestId, duration: Number(duration.toFixed(2)), method: request.method, url: request.url}); } // Add request ID to response headers const headers = new Headers(response.headers); headers.set('x-request-id', requestId); return new NextResponse(response.body, { status: response.status, statusText: response.statusText, headers}); } catch (error) { const duration = performance.now() - startTime; logger.error(`${request.method} ${name} failed`, error instanceof Error ? error : new Error(String(error)), { category, requestId, duration: Number(duration.toFixed(2)), method: request.method, url: request.url, statusCode: 500}); throw error; } }; } |