import type { ApolloServerPlugin } from '@apollo/server'; import { logger, logQuery, logError } from '../monitoring/logger.js'; import { queryCounter, queryDuration, errorCounter, queryComplexityGauge, } from '../monitoring/metrics.js'; import { createTrace, endTrace } from '../monitoring/tracing.js'; /** * Monitoring Plugin für Apollo Server * Sammelt Logs, Metrics und Traces für jeden Request */ export const monitoringPlugin = (): ApolloServerPlugin => { return { async requestDidStart() { return { async didResolveOperation({ request, operationName }) { // Erstelle Trace für Request const traceId = createTrace().traceId; (request as any).traceId = traceId; logger.info('GraphQL operation started', { operationName: operationName || 'unknown', query: request.query, variables: request.variables, traceId, }); }, async willSendResponse({ request, response }) { const traceId = (request as any).traceId; const operationName = request.operationName || 'unknown'; const duration = traceId ? endTrace(traceId) : 0; // Log Query logQuery(operationName, request.variables, duration); // Metrics const status = response.errors && response.errors.length > 0 ? 'error' : 'success'; queryCounter.inc({ operation: operationName, status }); queryDuration.observe({ operation: operationName }, duration / 1000); // Log Errors if (response.errors && response.errors.length > 0) { response.errors.forEach((error) => { logError(error as Error, { operationName, traceId, }); errorCounter.inc({ type: error.extensions?.code as string || 'UNKNOWN', operation: operationName, }); }); } }, async didEncounterErrors({ request, errors }) { const traceId = (request as any).traceId; const operationName = request.operationName || 'unknown'; errors.forEach((error) => { logError(error as Error, { operationName, traceId, }); errorCounter.inc({ type: error.extensions?.code as string || 'UNKNOWN', operation: operationName, }); }); }, }; }, }; }; /** * Plugin für Query Complexity Tracking */ export const queryComplexityMonitoringPlugin = (): ApolloServerPlugin => { return { async requestDidStart() { return { async didResolveOperation({ request, operationName }) { // Wird vom queryComplexityPlugin gesetzt const complexity = (request as any).complexity; if (complexity) { queryComplexityGauge.set( { operation: operationName || 'unknown' }, complexity ); } }, }; }, }; };