UNPKG

@gebrai/gebrai

Version:

Model Context Protocol server for GeoGebra mathematical visualization

161 lines 5.91 kB
"use strict"; /** * Performance Monitoring and Optimization System * GEB-9: Performance Optimization: Response Time and Resource Management */ Object.defineProperty(exports, "__esModule", { value: true }); exports.performanceMonitor = exports.PerformanceMonitor = void 0; class PerformanceMonitor { static instance; metrics = []; thresholds; maxMetrics = 1000; // Keep last 1000 metrics // PRD requirements: <2 second response time defaultThresholds = { 'geogebra_eval_command': { warning: 1000, critical: 2000 }, 'geogebra_create_point': { warning: 500, critical: 1000 }, 'geogebra_create_line': { warning: 500, critical: 1000 }, 'geogebra_export_png': { warning: 1500, critical: 2000 }, 'geogebra_export_svg': { warning: 800, critical: 1500 }, 'geogebra_instance_init': { warning: 8000, critical: 15000 }, 'geogebra_clear_construction': { warning: 300, critical: 1000 }, 'default': { warning: 1000, critical: 2000 } }; constructor() { this.thresholds = { ...this.defaultThresholds }; } static getInstance() { if (!PerformanceMonitor.instance) { PerformanceMonitor.instance = new PerformanceMonitor(); } return PerformanceMonitor.instance; } /** * Start timing an operation */ startTiming(operationName, metadata) { const startTime = performance.now(); const startMemory = process.memoryUsage(); return (success = true, errorMessage) => { const endTime = performance.now(); const endMemory = process.memoryUsage(); const duration = endTime - startTime; const metric = { operationName, startTime, endTime, duration, success, ...(errorMessage && { errorMessage }), memoryUsage: { rss: endMemory.rss - startMemory.rss, heapTotal: endMemory.heapTotal - startMemory.heapTotal, heapUsed: endMemory.heapUsed - startMemory.heapUsed, external: endMemory.external - startMemory.external, arrayBuffers: endMemory.arrayBuffers - startMemory.arrayBuffers }, ...(metadata && { metadata }) }; this.addMetric(metric); this.checkThresholds(metric); return metric; }; } /** * Measure and record an async operation */ async measureOperation(operationName, operation, metadata) { const endTiming = this.startTiming(operationName, metadata); try { const result = await operation(); endTiming(true); return result; } catch (error) { endTiming(false, error instanceof Error ? error.message : String(error)); throw error; } } /** * Add a metric to the collection */ addMetric(metric) { this.metrics.push(metric); // Keep only the last maxMetrics entries if (this.metrics.length > this.maxMetrics) { this.metrics = this.metrics.slice(-this.maxMetrics); } } /** * Check if metric exceeds thresholds and log warnings */ checkThresholds(metric) { const threshold = this.thresholds[metric.operationName] || this.thresholds['default']; if (threshold && metric.duration > threshold.critical) { console.error(`🚨 CRITICAL: ${metric.operationName} took ${metric.duration.toFixed(2)}ms (threshold: ${threshold.critical}ms)`); } else if (threshold && metric.duration > threshold.warning) { console.warn(`⚠️ WARNING: ${metric.operationName} took ${metric.duration.toFixed(2)}ms (threshold: ${threshold.warning}ms)`); } } /** * Get performance statistics for an operation */ getStats(operationName) { const relevantMetrics = operationName ? this.metrics.filter(m => m.operationName === operationName) : this.metrics; if (relevantMetrics.length === 0) { return { count: 0, averageDuration: 0, medianDuration: 0, minDuration: 0, maxDuration: 0, successRate: 0, p95Duration: 0, p99Duration: 0 }; } const durations = relevantMetrics.map(m => m.duration).sort((a, b) => a - b); const successCount = relevantMetrics.filter(m => m.success).length; return { count: relevantMetrics.length, averageDuration: durations.reduce((sum, d) => sum + d, 0) / durations.length, medianDuration: durations[Math.floor(durations.length / 2)] || 0, minDuration: durations[0] || 0, maxDuration: durations[durations.length - 1] || 0, successRate: successCount / relevantMetrics.length, p95Duration: durations[Math.floor(durations.length * 0.95)] || 0, p99Duration: durations[Math.floor(durations.length * 0.99)] || 0 }; } /** * Get all operation names with metrics */ getOperationNames() { return [...new Set(this.metrics.map(m => m.operationName))]; } /** * Clear all metrics */ clearMetrics() { this.metrics = []; } /** * Export metrics for analysis */ exportMetrics() { return [...this.metrics]; } /** * Set custom thresholds */ setThresholds(thresholds) { Object.assign(this.thresholds, thresholds); } } exports.PerformanceMonitor = PerformanceMonitor; // Global instance exports.performanceMonitor = PerformanceMonitor.getInstance(); //# sourceMappingURL=index.js.map