Skip to main content
Glama

MCP SQL Server

by ryudg
performance-monitor.ts6.66 kB
import { Logger } from "../../core/logger.js"; import { MetricsCollector } from "./metrics-collector.js"; import { PerformanceMetric, PerformanceAlert, PerformanceConfig, PerformanceThresholds, } from "../../types/performance.types.js"; /** * Performance Monitor - Single responsibility: Control monitoring and alerts * Simple monitoring control for MCP-SQL database operations */ export class PerformanceMonitor { private isMonitoring: boolean = false; private monitoringInterval: NodeJS.Timeout | null = null; private metrics: PerformanceMetric[] = []; private alerts: PerformanceAlert[] = []; private config: PerformanceConfig; constructor( private metricsCollector: MetricsCollector, private logger: Logger, config?: Partial<PerformanceConfig> ) { // Default configuration for MCP-SQL this.config = { thresholds: { slowQueryThreshold: 1000, // 1 second highCpuThreshold: 80, highMemoryThreshold: 85, maxConnections: 100, maxErrorRate: 5, }, monitoringInterval: 5000, // 5 seconds maxMetricsHistory: 1000, ...config, }; } /** * Start performance monitoring */ startMonitoring(customInterval?: number): void { if (this.isMonitoring) { this.logger.warn("Performance monitoring is already running"); return; } const interval = customInterval || this.config.monitoringInterval; this.isMonitoring = true; this.logger.info("Performance monitoring started", { intervalMs: interval, }); this.monitoringInterval = setInterval(async () => { await this.collectAndCheckMetrics(); }, interval); } /** * Stop performance monitoring */ stopMonitoring(): void { if (!this.isMonitoring) { this.logger.warn("Performance monitoring is not running"); return; } this.isMonitoring = false; if (this.monitoringInterval) { clearInterval(this.monitoringInterval); this.monitoringInterval = null; } this.logger.info("Performance monitoring stopped", { totalMetrics: this.metrics.length, totalAlerts: this.alerts.length, }); } /** * Get current metrics */ getCurrentMetrics(): PerformanceMetric | null { return this.metrics.length > 0 ? this.metrics[this.metrics.length - 1] : null; } /** * Get metrics history */ getMetricsHistory(limit: number = 100): PerformanceMetric[] { return this.metrics.slice(-limit); } /** * Get active alerts */ getActiveAlerts(): PerformanceAlert[] { return this.alerts.filter((alert) => !alert.resolved); } /** * Get all alerts */ getAllAlerts(): PerformanceAlert[] { return this.alerts; } /** * Clear all metrics and alerts */ clearMetrics(): void { this.metrics = []; this.alerts = []; this.metricsCollector.clearMetrics(); this.logger.info("Performance metrics and alerts history cleared"); } /** * Record slow query for monitoring */ recordSlowQuery(query: string, executionTime: number): void { this.metricsCollector.recordQueryTime(executionTime); if (executionTime > this.config.thresholds.slowQueryThreshold) { this.generateAlert( "warning", "queryTime", executionTime, this.config.thresholds.slowQueryThreshold, `Slow query detected: ${executionTime}ms (threshold: ${this.config.thresholds.slowQueryThreshold}ms)` ); this.logger.warn("Slow query detected", { query: query.substring(0, 100) + (query.length > 100 ? "..." : ""), executionTime: `${executionTime}ms`, threshold: `${this.config.thresholds.slowQueryThreshold}ms`, }); } } // Private methods private async collectAndCheckMetrics(): Promise<void> { try { const metric = await this.metricsCollector.collectMetrics(); this.addMetric(metric); this.checkThresholds(metric); } catch (error) { this.logger.error("Failed to collect metrics during monitoring", { error: error instanceof Error ? error.message : String(error), }); } } private addMetric(metric: PerformanceMetric): void { this.metrics.push(metric); // Limit history size if (this.metrics.length > this.config.maxMetricsHistory) { this.metrics = this.metrics.slice(-this.config.maxMetricsHistory); } } private checkThresholds(metric: PerformanceMetric): void { const thresholds = this.config.thresholds; // Check CPU usage if (metric.cpuUsage && metric.cpuUsage > thresholds.highCpuThreshold) { this.generateAlert( "warning", "cpuUsage", metric.cpuUsage, thresholds.highCpuThreshold, `High CPU usage: ${metric.cpuUsage}%` ); } // Check memory usage if ( metric.memoryUsage && metric.memoryUsage > thresholds.highMemoryThreshold ) { this.generateAlert( "warning", "memoryUsage", metric.memoryUsage, thresholds.highMemoryThreshold, `High memory usage: ${metric.memoryUsage}%` ); } // Check connection count if ( metric.connectionCount && metric.connectionCount > thresholds.maxConnections ) { this.generateAlert( "critical", "connectionCount", metric.connectionCount, thresholds.maxConnections, `Connection limit exceeded: ${metric.connectionCount}` ); } // Check error rate if (metric.errorRate && metric.errorRate > thresholds.maxErrorRate) { this.generateAlert( "critical", "errorRate", metric.errorRate, thresholds.maxErrorRate, `High error rate: ${metric.errorRate}%` ); } } private generateAlert( type: "warning" | "critical" | "info", metric: string, currentValue: number, threshold: number, message: string ): void { const alert: PerformanceAlert = { id: `alert-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, type, metric, threshold, currentValue, message, timestamp: new Date(), resolved: false, }; this.alerts.push(alert); // Log alert based on severity if (type === "critical") { this.logger.error("Critical performance alert", alert); } else if (type === "warning") { this.logger.warn("Performance warning", alert); } else { this.logger.info("Performance info", alert); } // Limit alerts history if (this.alerts.length > 1000) { this.alerts = this.alerts.slice(-1000); } } }

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/ryudg/mcp-sql'

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