import { NextResponse } from 'next/server'; import client from 'prom-client'; // Force Node.js runtime for this route export const runtime = 'nodejs'; export const dynamic = 'force-dynamic'; // Singleton pattern to avoid duplicate metric registration const globalForProm = globalThis as unknown as { promRegistry: client.Registry | undefined; metricsInitialized: boolean | undefined; }; function getRegistry(): client.Registry { if (!globalForProm.promRegistry) { globalForProm.promRegistry = new client.Registry(); } return globalForProm.promRegistry; } function initializeMetrics(register: client.Registry) { if (globalForProm.metricsInitialized) { return; } // Add default metrics (CPU, memory, etc.) client.collectDefaultMetrics({ register }); // Custom metrics new client.Counter({ name: 'http_requests_total', help: 'Total number of HTTP requests', labelNames: ['method', 'path', 'status'], registers: [register], }); new client.Histogram({ name: 'http_request_duration_seconds', help: 'Duration of HTTP requests in seconds', labelNames: ['method', 'path'], buckets: [0.1, 0.3, 0.5, 0.7, 1, 3, 5, 7, 10], registers: [register], }); globalForProm.metricsInitialized = true; } export async function GET() { try { const register = getRegistry(); initializeMetrics(register); const metrics = await register.metrics(); return new NextResponse(metrics, { status: 200, headers: { 'Content-Type': register.contentType, }, }); } catch (error) { console.error('Metrics error:', error); return NextResponse.json({ error: 'Failed to get metrics' }, { status: 500 }); } }