UNPKG

@houmak/minerva-mcp-server

Version:

Minerva Model Context Protocol (MCP) Server for Microsoft 365 and Azure integrations

199 lines (198 loc) 6.74 kB
import { metrics, trace } from '@opentelemetry/api'; import { logger } from '../logger.js'; export class AdvancedMonitoring { config; meter; tracer; // Métriques personnalisées requestCounter; responseTimeHistogram; errorCounter; circuitBreakerStateGauge; cacheHitRatioGauge; activeConnectionsGauge; constructor(config) { this.config = config; } async initialize() { if (!this.config.enabled) { logger.info('Advanced monitoring is disabled'); return; } try { // Initialiser les métriques personnalisées this.initializeCustomMetrics(); logger.info('Advanced monitoring initialized successfully'); } catch (error) { logger.error('Error initializing advanced monitoring:', error); throw error; } } getHeaders() { const headers = {}; if (this.config.applicationInsightsConnectionString) { headers['x-ms-connection-string'] = this.config.applicationInsightsConnectionString; } if (this.config.applicationInsightsInstrumentationKey) { headers['x-ms-instrumentation-key'] = this.config.applicationInsightsInstrumentationKey; } return headers; } initializeCustomMetrics() { this.meter = metrics.getMeter(this.config.serviceName); this.tracer = trace.getTracer(this.config.serviceName); // Compteur de requêtes this.requestCounter = this.meter.createCounter('minerva_requests_total', { description: 'Total number of requests', }); // Histogramme des temps de réponse this.responseTimeHistogram = this.meter.createHistogram('minerva_response_time_seconds', { description: 'Response time in seconds', unit: 's', }); // Compteur d'erreurs this.errorCounter = this.meter.createCounter('minerva_errors_total', { description: 'Total number of errors', }); // Gauge pour l'état du circuit breaker this.circuitBreakerStateGauge = this.meter.createUpDownCounter('minerva_circuit_breaker_state', { description: 'Circuit breaker state (0=closed, 1=half-open, 2=open)', }); // Gauge pour le ratio de cache this.cacheHitRatioGauge = this.meter.createUpDownCounter('minerva_cache_hit_ratio', { description: 'Cache hit ratio percentage', }); // Gauge pour les connexions actives this.activeConnectionsGauge = this.meter.createUpDownCounter('minerva_active_connections', { description: 'Number of active connections', }); } // Méthodes pour les métriques recordRequest(provider, action, success) { if (!this.config.enabled) return; this.requestCounter.add(1, { provider, action, success: success.toString(), }); } recordResponseTime(provider, action, durationMs) { if (!this.config.enabled) return; this.responseTimeHistogram.record(durationMs / 1000, { provider, action, }); } recordError(provider, action, errorType) { if (!this.config.enabled) return; this.errorCounter.add(1, { provider, action, error_type: errorType, }); } updateCircuitBreakerState(provider, state) { if (!this.config.enabled) return; const stateValue = state === 'closed' ? 0 : state === 'half-open' ? 1 : 2; this.circuitBreakerStateGauge.add(stateValue, { provider, }); } updateCacheHitRatio(provider, hitRatio) { if (!this.config.enabled) return; this.cacheHitRatioGauge.add(hitRatio, { provider, }); } updateActiveConnections(provider, count) { if (!this.config.enabled) return; this.activeConnectionsGauge.add(count, { provider, }); } // Méthodes pour les traces startSpan(name, attributes) { if (!this.config.enabled) return null; return this.tracer.startSpan(name, { attributes, }); } addSpanEvent(span, name, attributes) { if (!this.config.enabled || !span) return; span.addEvent(name, attributes); } setSpanAttributes(span, attributes) { if (!this.config.enabled || !span) return; span.setAttributes(attributes); } endSpan(span, status) { if (!this.config.enabled || !span) return; if (status) { span.setStatus(status); } span.end(); } // Wrapper pour les opérations avec monitoring automatique async monitorOperation(operation, operationName, provider, attributes) { if (!this.config.enabled) { return await operation(); } const startTime = Date.now(); const span = this.startSpan(operationName, { provider, ...attributes, }); try { const result = await operation(); const duration = Date.now() - startTime; this.recordRequest(provider, operationName, true); this.recordResponseTime(provider, operationName, duration); this.endSpan(span, { code: 1 }); // OK return result; } catch (error) { const duration = Date.now() - startTime; const errorType = error instanceof Error ? error.constructor.name : 'Unknown'; this.recordRequest(provider, operationName, false); this.recordResponseTime(provider, operationName, duration); this.recordError(provider, operationName, errorType); this.endSpan(span, { code: 2, message: error instanceof Error ? error.message : 'Unknown error' }); // ERROR throw error; } } // Métriques de santé getHealthMetrics() { if (!this.config.enabled) { return { enabled: false }; } return { enabled: true, serviceName: this.config.serviceName, serviceVersion: this.config.serviceVersion, environment: this.config.environment, timestamp: new Date().toISOString(), }; } // Nettoyage async shutdown() { logger.info('Advanced monitoring shutdown completed'); } // Configuration getConfig() { return { ...this.config }; } isEnabled() { return this.config.enabled; } }