import { NextRequest, NextResponse } from 'next/server'; import { createLogger, generateRequestId, formatError } from './logger'; /** * API Route Handler type */ type ApiRouteHandler = ( request: NextRequest, context: any ) => Promise | NextResponse; /** * Wrap an API route handler with logging * Automatically logs requests, responses, errors, and timing * * @param handler - The API route handler function * @param operationName - Optional operation name for logging context * @returns Wrapped handler with logging * * @example * ```typescript * export const GET = withLogging(async (request) => { * const data = await fetchData(); * return NextResponse.json(data); * }, 'getAllProcesses'); * ``` */ export function withLogging( handler: ApiRouteHandler, operationName?: string ): ApiRouteHandler { return async (request: NextRequest, context: any) => { const requestId = generateRequestId(); const startTime = Date.now(); // Extract request information const method = request.method; const url = request.url; const pathname = new URL(url).pathname; // Create logger with request context const logger = createLogger({ requestId, method, path: pathname, operation: operationName || pathname.split('/').pop(), }); // Log incoming request logger.info({ userAgent: request.headers.get('user-agent'), remoteAddress: request.headers.get('x-forwarded-for') || 'unknown', }, `Incoming ${method} request`); try { // Execute the handler const response = await handler(request, context); // Calculate duration const duration = Date.now() - startTime; // Log successful response logger.info({ statusCode: response.status, duration, }, `Request completed successfully in ${duration}ms`); // Add request ID to response headers response.headers.set('X-Request-ID', requestId); return response; } catch (error: unknown) { // Calculate duration even for errors const duration = Date.now() - startTime; // Format and log error const errorInfo = formatError(error); logger.error({ error: errorInfo, duration, }, `Request failed after ${duration}ms: ${errorInfo.message}`); // Return error response return NextResponse.json( { error: errorInfo.message, requestId, }, { status: 500, headers: { 'X-Request-ID': requestId, }, } ); } }; } /** * Log performance timing for an operation within a request * * @param logger - Logger instance * @param operation - Operation name * @param fn - Async function to time * @returns Result of the function * * @example * ```typescript * const data = await logPerformance(logger, 'fetchData', async () => { * return await supervisorClient.getAllProcessInfo(); * }); * ``` */ export async function logPerformance( logger: ReturnType, operation: string, fn: () => Promise ): Promise { const startTime = Date.now(); try { const result = await fn(); const duration = Date.now() - startTime; logger.debug({ operation, duration, }, `${operation} completed in ${duration}ms`); return result; } catch (error) { const duration = Date.now() - startTime; const errorInfo = formatError(error); logger.error({ operation, duration, error: errorInfo, }, `${operation} failed after ${duration}ms: ${errorInfo.message}`); throw error; } } /** * Create a logger for a specific API operation * Use this for manual logging within API routes * * @param request - Next.js request object * @param operation - Operation name * @returns Logger instance with request context * * @example * ```typescript * const logger = createApiLogger(request, 'startProcess'); * logger.info({ processName }, 'Starting process'); * ``` */ export function createApiLogger(request: NextRequest, operation: string) { const requestId = request.headers.get('x-request-id') || generateRequestId(); const pathname = new URL(request.url).pathname; return createLogger({ requestId, method: request.method, path: pathname, operation, }); }