Skip to main content
Glama
PerformanceMonitor.ts4.39 kB
export class PerformanceMonitor { private metrics: Map<string, { count: number; totalTime: number; minTime: number; maxTime: number; errors: number; }> = new Map(); private startTimes: Map<string, number> = new Map(); startOperation(operationName: string): void { this.startTimes.set(operationName, performance.now()); } endOperation(operationName: string, success: boolean = true): number { const startTime = this.startTimes.get(operationName); if (!startTime) return 0; const duration = performance.now() - startTime; this.startTimes.delete(operationName); const metric = this.metrics.get(operationName) || { count: 0, totalTime: 0, minTime: Infinity, maxTime: 0, errors: 0 }; metric.count++; metric.totalTime += duration; metric.minTime = Math.min(metric.minTime, duration); metric.maxTime = Math.max(metric.maxTime, duration); if (!success) metric.errors++; this.metrics.set(operationName, metric); return duration; } async measureAsync<T>( operationName: string, operation: () => Promise<T> ): Promise<T> { this.startOperation(operationName); try { const result = await operation(); this.endOperation(operationName, true); return result; } catch (error) { this.endOperation(operationName, false); throw error; } } getMetrics(operationName?: string) { if (operationName) { const metric = this.metrics.get(operationName); if (!metric) return null; return { operation: operationName, calls: metric.count, averageTime: metric.totalTime / metric.count, minTime: metric.minTime, maxTime: metric.maxTime, totalTime: metric.totalTime, errorRate: (metric.errors / metric.count) * 100 }; } const allMetrics: any[] = []; this.metrics.forEach((metric, name) => { allMetrics.push({ operation: name, calls: metric.count, averageTime: metric.totalTime / metric.count, minTime: metric.minTime, maxTime: metric.maxTime, totalTime: metric.totalTime, errorRate: (metric.errors / metric.count) * 100 }); }); return allMetrics.sort((a, b) => b.totalTime - a.totalTime); } getReport(): string { const metrics = this.getMetrics() as any[]; if (!metrics || metrics.length === 0) { return 'No performance metrics collected'; } let report = '\n=== PERFORMANCE REPORT ===\n\n'; report += 'Operation'.padEnd(30) + 'Calls'.padEnd(10) + 'Avg(ms)'.padEnd(12) + 'Min(ms)'.padEnd(12) + 'Max(ms)'.padEnd(12) + 'Errors\n'; report += '-'.repeat(86) + '\n'; metrics.forEach(m => { report += m.operation.padEnd(30) + m.calls.toString().padEnd(10) + m.averageTime.toFixed(2).padEnd(12) + m.minTime.toFixed(2).padEnd(12) + m.maxTime.toFixed(2).padEnd(12) + `${m.errorRate.toFixed(1)}%\n`; }); const totalCalls = metrics.reduce((sum, m) => sum + m.calls, 0); const totalTime = metrics.reduce((sum, m) => sum + m.totalTime, 0); report += '\n'; report += `Total Operations: ${totalCalls}\n`; report += `Total Time: ${totalTime.toFixed(2)}ms\n`; report += `Average per Operation: ${(totalTime / totalCalls).toFixed(2)}ms\n`; return report; } reset() { this.metrics.clear(); this.startTimes.clear(); } // Memory usage tracking getMemoryUsage() { if (typeof process !== 'undefined' && process.memoryUsage) { const usage = process.memoryUsage(); return { heapUsed: (usage.heapUsed / 1024 / 1024).toFixed(2) + ' MB', heapTotal: (usage.heapTotal / 1024 / 1024).toFixed(2) + ' MB', rss: (usage.rss / 1024 / 1024).toFixed(2) + ' MB', external: (usage.external / 1024 / 1024).toFixed(2) + ' MB' }; } return null; } // Get top slowest operations getBottlenecks(limit: number = 5) { const metrics = this.getMetrics() as any[]; return metrics .sort((a, b) => b.averageTime - a.averageTime) .slice(0, limit) .map(m => ({ operation: m.operation, averageTime: m.averageTime.toFixed(2) + 'ms', maxTime: m.maxTime.toFixed(2) + 'ms', calls: m.calls })); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/williamzujkowski/strudel-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server