UNPKG

codecrucible-synth

Version:

Production-Ready AI Development Platform with Multi-Voice Synthesis, Smithery MCP Integration, Enterprise Security, and Zero-Timeout Reliability

400 lines โ€ข 14.7 kB
#!/usr/bin/env node /** * Performance Monitor - Consolidated performance tracking and metrics * Replaces: system-benchmark.ts, performance-optimized-client.ts, and scattered metrics */ import { EventEmitter } from 'events'; import { cpus } from 'os'; import { logger } from '../core/logger.js'; export class PerformanceMonitor extends EventEmitter { providerMetrics = new Map(); requestHistory = []; systemMetrics = null; alerts = []; startTime = Date.now(); monitoringEnabled; monitoringInterval; lastAlertTimes = new Map(); // Track last alert times to prevent spam MAX_HISTORY_SIZE = 50; // OPTIMIZED: Reduced from 1000 to prevent memory leaks ALERT_THRESHOLDS = { latency: 10000, // 10 seconds errorRate: 0.1, // 10% memoryUsage: 0.85, // 85% }; constructor(enableMonitoring = true) { super(); this.monitoringEnabled = enableMonitoring; // Set higher max listeners to avoid warnings during testing this.setMaxListeners(20); if (this.monitoringEnabled) { this.initializeSystemMonitoring(); } } initializeSystemMonitoring() { if (!this.monitoringEnabled) return; // Update system metrics every 30 seconds this.monitoringInterval = setInterval(async () => { // TODO: Store interval ID and call clearInterval in cleanup try { await this.updateSystemMetrics(); } catch (error) { // Silent error handling to prevent crashes } }, 30000); // Prevent interval from keeping process alive during tests this.monitoringInterval.unref(); // Initial system metrics this.updateSystemMetrics(); } /** * Disable monitoring and clean up intervals */ disableMonitoring() { this.monitoringEnabled = false; if (this.monitoringInterval) { clearInterval(this.monitoringInterval); this.monitoringInterval = undefined; } } /** * Clean up resources and disable monitoring */ destroy() { this.disableMonitoring(); this.removeAllListeners(); this.providerMetrics.clear(); this.requestHistory.length = 0; this.alerts.length = 0; } async updateSystemMetrics() { try { const memUsage = process.memoryUsage(); this.systemMetrics = { cpu: { usage: await this.getCPUUsage(), cores: cpus().length, }, memory: { used: memUsage.heapUsed, total: memUsage.heapTotal, percentage: memUsage.heapUsed / memUsage.heapTotal, }, disk: { used: 0, // Would require additional implementation total: 0, percentage: 0, }, }; // Check for memory alerts if (this.systemMetrics.memory.percentage > this.ALERT_THRESHOLDS.memoryUsage) { this.createAlert({ type: 'resource_usage', severity: 'warning', message: 'High memory usage detected', value: this.systemMetrics.memory.percentage, threshold: this.ALERT_THRESHOLDS.memoryUsage, timestamp: new Date(), }); } } catch (error) { logger.warn('Failed to update system metrics:', error); } } async getCPUUsage() { return new Promise(resolve => { const startUsage = process.cpuUsage(); setTimeout(() => { const currentUsage = process.cpuUsage(startUsage); const totalUsage = currentUsage.user + currentUsage.system; const percentage = totalUsage / 1000000; // Convert microseconds to seconds resolve(Math.min(percentage, 100)); }, 100); }); } /** * Record a request for performance tracking */ recordRequest(provider, metrics) { // Add to history this.requestHistory.push(metrics); // OPTIMIZED: Aggressive trimming to prevent memory leaks if (this.requestHistory.length > this.MAX_HISTORY_SIZE) { this.requestHistory = this.requestHistory.slice(-25); // Keep only 25 most recent } // Update provider metrics this.updateProviderMetrics(provider, metrics); // Check for performance alerts this.checkPerformanceAlerts(provider, metrics); // Emit metrics event this.emit('metrics', { provider, metrics }); } updateProviderMetrics(provider, metrics) { let providerStats = this.providerMetrics.get(provider); if (!providerStats) { providerStats = { requests: 0, totalRequests: 0, totalLatency: 0, averageLatency: 0, successRate: 0, errorRate: 0, }; this.providerMetrics.set(provider, providerStats); } // Update total requests providerStats.requests++; providerStats.totalRequests++; // Update latency if (metrics.endTime && metrics.startTime) { const latency = metrics.endTime - metrics.startTime; providerStats.totalLatency += latency; providerStats.averageLatency = (providerStats.averageLatency * (providerStats.totalRequests - 1) + latency) / providerStats.totalRequests; } // Update success/error rates const recentRequests = this.requestHistory.filter(r => r.provider === provider).slice(-100); // Last 100 requests const successCount = recentRequests.filter(r => r.success).length; providerStats.successRate = successCount / recentRequests.length; providerStats.errorRate = 1 - providerStats.successRate; // Update last error if (!metrics.success && metrics.error) { providerStats.lastError = metrics.error; } } checkPerformanceAlerts(provider, metrics) { const providerStats = this.providerMetrics.get(provider); if (!providerStats) return; // Check latency alert if (metrics.endTime && metrics.startTime) { const latency = metrics.endTime - metrics.startTime; if (latency > this.ALERT_THRESHOLDS.latency) { this.createAlert({ type: 'latency', severity: latency > this.ALERT_THRESHOLDS.latency * 2 ? 'critical' : 'warning', message: `High latency detected for provider ${provider}`, value: latency, threshold: this.ALERT_THRESHOLDS.latency, provider, timestamp: new Date(), }); } } // Check error rate alert if ((providerStats.errorRate ?? 0) > this.ALERT_THRESHOLDS.errorRate) { this.createAlert({ type: 'error_rate', severity: (providerStats.errorRate ?? 0) > this.ALERT_THRESHOLDS.errorRate * 2 ? 'critical' : 'warning', message: `High error rate detected for provider ${provider}`, value: providerStats.errorRate ?? 0, threshold: this.ALERT_THRESHOLDS.errorRate, provider, timestamp: new Date(), }); } } createAlert(alert) { // DISABLED: Performance alerts are too verbose for normal operation // Only store alert but don't log it to prevent spam this.alerts.push(alert); // OPTIMIZED: Keep only recent alerts (last 25 instead of 100) if (this.alerts.length > 25) { this.alerts = this.alerts.slice(-15); // Keep only 15 most recent } // NOTE: Logging disabled to prevent spam in normal operation // Alerts are still stored for monitoring purposes but not logged // Emit alert event this.emit('alert', alert); } /** * Get metrics for a specific provider */ getProviderMetrics(provider) { if (provider) { const metrics = this.providerMetrics.get(provider); return metrics ? { [provider]: metrics } : {}; } return Object.fromEntries(this.providerMetrics.entries()); } /** * Get overall performance summary */ getSummary() { const providers = Object.fromEntries(this.providerMetrics.entries()); // Calculate overall metrics const totalRequests = Array.from(this.providerMetrics.values()).reduce((sum, metrics) => sum + metrics.totalRequests, 0); const averageLatency = Array.from(this.providerMetrics.values()).reduce((sum, metrics) => { return sum + (metrics.averageLatency * metrics.totalRequests) / totalRequests; }, 0); const successRate = Array.from(this.providerMetrics.values()).reduce((sum, metrics) => { return sum + (metrics.successRate * metrics.totalRequests) / totalRequests; }, 0); const uptime = (Date.now() - this.startTime) / 1000; // seconds return { timestamp: new Date(), totalRequests, averageLatency: averageLatency || 0, errorRate: 1 - (successRate || 0), providers, overall: { totalRequests, averageLatency: averageLatency || 0, successRate: successRate || 0, uptime, }, }; } /** * Get recent performance alerts */ getAlerts(limit = 10) { return this.alerts.slice(-limit).sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()); } /** * Get system metrics */ getSystemMetrics() { return this.systemMetrics; } /** * Get request history */ getRequestHistory(provider, limit = 100) { let history = this.requestHistory; if (provider) { history = history.filter(r => r.provider === provider); } return history.slice(-limit); } /** * Reset metrics for a provider */ resetProviderMetrics(provider) { this.providerMetrics.delete(provider); this.requestHistory = this.requestHistory.filter(r => r.provider !== provider); logger.info(`๐Ÿ”„ Reset metrics for provider: ${provider}`); } /** * Clear all metrics */ clearAllMetrics() { this.providerMetrics.clear(); this.requestHistory.length = 0; this.alerts.length = 0; this.startTime = Date.now(); logger.info('๐Ÿงน Cleared all performance metrics'); } /** * Export metrics for analysis */ exportMetrics() { return { summary: this.getSummary(), history: this.requestHistory, alerts: this.alerts, system: this.systemMetrics, exportTime: new Date(), }; } /** * Get performance recommendations */ getRecommendations() { const recommendations = []; const summary = this.getSummary(); // Check overall latency if ((summary.overall?.averageLatency ?? 0) > 5000) { recommendations.push({ type: 'performance', priority: 'high', description: 'Average response latency is high', action: 'Consider optimizing models or switching to faster providers', }); } // Check success rate if ((summary.overall?.successRate ?? 0) < 0.9) { recommendations.push({ type: 'reliability', priority: 'high', description: 'Success rate is below 90%', action: 'Review error logs and improve error handling', }); } // Check memory usage if (this.systemMetrics && this.systemMetrics.memory.percentage > 0.8) { recommendations.push({ type: 'resource', priority: 'medium', description: 'High memory usage detected', action: 'Consider increasing memory allocation or optimizing memory usage', }); } // Check provider balance const providerCounts = Object.values(summary.providers || {}).map(p => p.totalRequests); const maxRequests = Math.max(...providerCounts); const minRequests = Math.min(...providerCounts); if (maxRequests > minRequests * 3) { recommendations.push({ type: 'performance', priority: 'low', description: 'Unbalanced load distribution across providers', action: 'Consider implementing better load balancing', }); } return recommendations; } /** * Start performance monitoring */ start() { logger.info('๐Ÿ“Š Performance monitoring started'); this.emit('started'); } /** * Stop performance monitoring */ stop() { this.clearAllMetrics(); logger.info('๐Ÿ“Š Performance monitoring stopped'); this.emit('stopped'); } /** * Start operation tracking (for compatibility) */ startOperation(operationId, component) { const startTime = Date.now(); if (!this.operationTracking) { this.operationTracking = new Map(); } this.operationTracking.set(operationId, { startTime, component }); } /** * End operation tracking (for compatibility) */ endOperation(operationId) { if (!this.operationTracking) { return; } const operation = this.operationTracking.get(operationId); if (operation) { const endTime = Date.now(); // Record as a request metric for tracking this.recordRequest(operation.component || 'unknown', { provider: operation.component || 'unknown', model: 'operation', startTime: operation.startTime, endTime, success: true, }); this.operationTracking.delete(operationId); } } operationTracking; } //# sourceMappingURL=performance.js.map