Skip to main content
Glama
PerformanceAnalytics.ts25.9 kB
/** * Advanced Performance Analytics for WordPress MCP Server * Provides insights, predictions, and optimization recommendations */ import { PerformanceMetrics } from "./PerformanceMonitor.js"; import { MetricsCollector } from "./MetricsCollector.js"; export interface AnalyticsConfig { enablePredictiveAnalysis: boolean; enableAnomalyDetection: boolean; enableTrendAnalysis: boolean; lookbackPeriod: number; // in milliseconds sensitivityLevel: "low" | "medium" | "high"; } export interface PerformanceTrend { metric: string; direction: "improving" | "declining" | "stable"; changeRate: number; // percentage change confidence: number; // 0-1 prediction: { nextValue: number; timeframe: number; // milliseconds confidence: number; }; } export interface PerformanceAnomaly { timestamp: number; metric: string; expectedValue: number; actualValue: number; deviation: number; // percentage severity: "minor" | "moderate" | "major" | "critical"; possibleCauses: string[]; } export interface PerformanceInsight { id: string; category: "optimization" | "scaling" | "maintenance" | "alert"; priority: "low" | "medium" | "high" | "critical"; title: string; description: string; impact: "performance" | "reliability" | "cost" | "user_experience"; recommendation: string; estimatedImprovement: string; implementationEffort: "low" | "medium" | "high"; relatedMetrics: string[]; } export interface BenchmarkComparison { category: string; currentValue: number; benchmarkValue: number; percentile: number; // Where current performance ranks (0-100) status: "excellent" | "good" | "average" | "below_average" | "poor"; improvement: number; // How much improvement needed to reach next tier } /** * Performance Analytics Engine */ export class PerformanceAnalytics { private collector: MetricsCollector; private config: AnalyticsConfig; private historicalData: PerformanceMetrics[] = []; private detectedAnomalies: PerformanceAnomaly[] = []; private generatedInsights: PerformanceInsight[] = []; // Performance benchmarks (based on industry standards) private benchmarks = { responseTime: { excellent: 200, // <200ms good: 500, // 200-500ms average: 1000, // 500ms-1s below_average: 2000, // 1-2s poor: Infinity, // >2s }, cacheHitRate: { excellent: 0.95, // >95% good: 0.85, // 85-95% average: 0.7, // 70-85% below_average: 0.5, // 50-70% poor: 0, // <50% }, errorRate: { excellent: 0.001, // <0.1% good: 0.01, // 0.1-1% average: 0.02, // 1-2% below_average: 0.05, // 2-5% poor: Infinity, // >5% }, memoryUsage: { excellent: 50, // <50% good: 70, // 50-70% average: 80, // 70-80% below_average: 90, // 80-90% poor: 100, // >90% }, }; constructor(collector: MetricsCollector, config: Partial<AnalyticsConfig> = {}) { this.collector = collector; this.config = { enablePredictiveAnalysis: true, enableAnomalyDetection: true, enableTrendAnalysis: true, lookbackPeriod: 24 * 60 * 60 * 1000, // 24 hours sensitivityLevel: "medium", ...config, }; } /** * Add historical data point for analysis */ addDataPoint(metrics: PerformanceMetrics): void { this.historicalData.push(metrics); // Limit historical data to lookback period const cutoff = Date.now() - this.config.lookbackPeriod; this.historicalData = this.historicalData.filter((data) => data.system.uptime > cutoff); // Run analysis on new data if (this.config.enableAnomalyDetection) { this.detectAnomalies(metrics); } } /** * Analyze performance trends */ analyzeTrends(): PerformanceTrend[] { if (!this.config.enableTrendAnalysis || this.historicalData.length < 5) { return []; } const trends: PerformanceTrend[] = []; // Analyze response time trend trends.push( this.analyzeTrend( "responseTime", this.historicalData.map((d) => d.requests.averageResponseTime), ), ); // Analyze cache hit rate trend trends.push( this.analyzeTrend( "cacheHitRate", this.historicalData.map((d) => d.cache.hitRate), ), ); // Analyze error rate trend trends.push( this.analyzeTrend( "errorRate", this.historicalData.map((d) => (d.requests.total > 0 ? d.requests.failed / d.requests.total : 0)), ), ); // Analyze memory usage trend trends.push( this.analyzeTrend( "memoryUsage", this.historicalData.map((d) => d.system.memoryUsage), ), ); // Analyze request volume trend trends.push( this.analyzeTrend( "requestVolume", this.historicalData.map((d) => d.requests.requestsPerSecond), ), ); return trends; } /** * Generate performance insights */ generateInsights(): PerformanceInsight[] { const insights: PerformanceInsight[] = []; const currentMetrics = this.collector.collectCurrentMetrics(); const trends = this.analyzeTrends(); // Cache optimization insights if (currentMetrics.cache.hitRate < 0.8) { insights.push({ id: "cache-optimization-1", category: "optimization", priority: "high", title: "Improve Cache Hit Rate", description: `Current cache hit rate is ${(currentMetrics.cache.hitRate * 100).toFixed( 1, )}%, which is below optimal performance.`, impact: "performance", recommendation: "Implement cache warming strategies and optimize TTL values for frequently accessed data.", estimatedImprovement: "20-40% reduction in response times", implementationEffort: "medium", relatedMetrics: ["cacheHitRate", "responseTime"], }); } // Response time insights if (currentMetrics.requests.averageResponseTime > 1000) { insights.push({ id: "response-time-1", category: "optimization", priority: "high", title: "Reduce Response Times", description: `Average response time of ${currentMetrics.requests.averageResponseTime.toFixed( 0, )}ms is above recommended threshold.`, impact: "user_experience", recommendation: "Enable aggressive caching, optimize database queries, or consider upgrading server resources.", estimatedImprovement: "50-70% reduction in response times", implementationEffort: "medium", relatedMetrics: ["responseTime", "cacheHitRate"], }); } // Memory usage insights if (currentMetrics.system.memoryUsage > 80) { insights.push({ id: "memory-usage-1", category: "scaling", priority: "medium", title: "Memory Usage Optimization", description: `Memory usage at ${currentMetrics.system.memoryUsage}% is approaching limits.`, impact: "reliability", recommendation: "Increase cache size limits, implement cache eviction policies, or scale server resources.", estimatedImprovement: "Improved system stability", implementationEffort: "low", relatedMetrics: ["memoryUsage", "cacheSize"], }); } // Tool usage insights const toolMetrics = currentMetrics.tools; if (Object.keys(toolMetrics.toolUsageCount).length > 0) { const mostUsed = Object.entries(toolMetrics.toolUsageCount) .sort(([, a], [, b]) => b - a) .slice(0, 3); insights.push({ id: "tool-usage-1", category: "optimization", priority: "low", title: "Optimize Frequently Used Tools", description: `Most used tools: ${mostUsed .map(([tool]) => tool) .join(", ")}. Consider optimizing these workflows.`, impact: "performance", recommendation: "Create cached workflows or batch operations for frequently used tools.", estimatedImprovement: "10-20% reduction in API calls", implementationEffort: "high", relatedMetrics: ["toolUsage", "requestVolume"], }); } // Trend-based insights const responseTimeTrend = trends.find((t) => t.metric === "responseTime"); if (responseTimeTrend && responseTimeTrend.direction === "declining" && responseTimeTrend.changeRate > 10) { insights.push({ id: "trend-response-time-1", category: "alert", priority: "high", title: "Response Time Degradation Detected", description: `Response times are declining at ${responseTimeTrend.changeRate.toFixed(1)}% rate.`, impact: "performance", recommendation: "Investigate recent changes, check WordPress site health, and monitor resource usage.", estimatedImprovement: "Prevent further degradation", implementationEffort: "medium", relatedMetrics: ["responseTime", "errorRate"], }); } this.generatedInsights = insights; return insights; } /** * Compare performance against benchmarks */ benchmarkPerformance(): BenchmarkComparison[] { const currentMetrics = this.collector.collectCurrentMetrics(); const comparisons: BenchmarkComparison[] = []; // Response time benchmark comparisons.push( this.createBenchmarkComparison( "Response Time", currentMetrics.requests.averageResponseTime, this.benchmarks.responseTime, false, // lower is better ), ); // Cache hit rate benchmark comparisons.push( this.createBenchmarkComparison( "Cache Hit Rate", currentMetrics.cache.hitRate * 100, Object.fromEntries(Object.entries(this.benchmarks.cacheHitRate).map(([k, v]) => [k, v * 100])), true, // higher is better ), ); // Error rate benchmark const errorRate = currentMetrics.requests.total > 0 ? (currentMetrics.requests.failed / currentMetrics.requests.total) * 100 : 0; comparisons.push( this.createBenchmarkComparison( "Error Rate", errorRate, Object.fromEntries(Object.entries(this.benchmarks.errorRate).map(([k, v]) => [k, v * 100])), false, // lower is better ), ); // Memory usage benchmark comparisons.push( this.createBenchmarkComparison( "Memory Usage", currentMetrics.system.memoryUsage, this.benchmarks.memoryUsage, false, // lower is better ), ); return comparisons; } /** * Predict future performance based on trends */ predictPerformance(timeframeMinutes: number = 60): { predictions: Array<{ metric: string; currentValue: number; predictedValue: number; confidence: number; trend: "improving" | "declining" | "stable"; }>; alerts: string[]; } { if (!this.config.enablePredictiveAnalysis) { return { predictions: [], alerts: [] }; } const trends = this.analyzeTrends(); const predictions: Array<{ metric: string; currentValue: number; predictedValue: number; confidence: number; trend: "improving" | "declining" | "stable"; }> = []; const alerts: string[] = []; for (const trend of trends) { const _timeframeMs = timeframeMinutes * 60 * 1000; const predictedValue = trend.prediction.nextValue; predictions.push({ metric: trend.metric, currentValue: this.getCurrentMetricValue(trend.metric), predictedValue, confidence: trend.confidence, trend: trend.direction, }); // Generate alerts for concerning predictions if (trend.metric === "responseTime" && predictedValue > 2000 && trend.direction === "declining") { alerts.push(`Response times predicted to exceed 2s in ${timeframeMinutes} minutes`); } if (trend.metric === "cacheHitRate" && predictedValue < 0.5 && trend.direction === "declining") { alerts.push(`Cache hit rate predicted to drop below 50% in ${timeframeMinutes} minutes`); } if (trend.metric === "memoryUsage" && predictedValue > 90 && trend.direction === "declining") { alerts.push(`Memory usage predicted to exceed 90% in ${timeframeMinutes} minutes`); } } return { predictions, alerts }; } /** * Generate optimization recommendations with ROI estimates */ generateOptimizationPlan(): { quickWins: PerformanceInsight[]; mediumTerm: PerformanceInsight[]; longTerm: PerformanceInsight[]; estimatedROI: { performanceGain: number; // percentage implementationCost: "low" | "medium" | "high"; timeToValue: number; // days }; } { const insights = this.generateInsights(); const quickWins = insights.filter( (i) => i.implementationEffort === "low" && ["high", "critical"].includes(i.priority), ); const mediumTerm = insights.filter((i) => i.implementationEffort === "medium"); const longTerm = insights.filter((i) => i.implementationEffort === "high"); // Estimate ROI based on current performance issues const currentMetrics = this.collector.collectCurrentMetrics(); let estimatedGain = 0; if (currentMetrics.cache.hitRate < 0.8) estimatedGain += 30; if (currentMetrics.requests.averageResponseTime > 1000) estimatedGain += 40; if (currentMetrics.system.memoryUsage > 80) estimatedGain += 20; return { quickWins, mediumTerm, longTerm, estimatedROI: { performanceGain: Math.min(estimatedGain, 80), // Cap at 80% implementationCost: quickWins.length > 2 ? "low" : mediumTerm.length > 2 ? "medium" : "high", timeToValue: quickWins.length > 0 ? 1 : mediumTerm.length > 0 ? 7 : 30, }, }; } /** * Get anomalies detected in recent data */ getAnomalies(severity?: string): PerformanceAnomaly[] { if (severity) { return this.detectedAnomalies.filter((a) => a.severity === severity); } return [...this.detectedAnomalies]; } /** * Export comprehensive analytics report */ exportAnalyticsReport(): { timestamp: string; summary: { overallHealth: string; keyInsights: number; criticalAlerts: number; performanceScore: number; }; trends: PerformanceTrend[]; benchmarks: BenchmarkComparison[]; insights: PerformanceInsight[]; anomalies: PerformanceAnomaly[]; predictions: Array<{ metric: string; currentValue: number; predictedValue: number; confidence: number; trend: "improving" | "declining" | "stable"; }>; optimizationPlan: Record<string, unknown>; } { const currentMetrics = this.collector.collectCurrentMetrics(); const performanceScore = this.calculatePerformanceScore(currentMetrics); return { timestamp: new Date().toISOString(), summary: { overallHealth: this.calculateOverallHealth(performanceScore), keyInsights: this.generatedInsights.length, criticalAlerts: this.generatedInsights.filter((i) => i.priority === "critical").length, performanceScore, }, trends: this.analyzeTrends(), benchmarks: this.benchmarkPerformance(), insights: this.generateInsights(), anomalies: this.getAnomalies(), predictions: this.predictPerformance().predictions, optimizationPlan: this.generateOptimizationPlan(), }; } /** * Analyze trend for a specific metric */ private analyzeTrend(metricName: string, values: number[]): PerformanceTrend { if (values.length < 3) { return { metric: metricName, direction: "stable", changeRate: 0, confidence: 0, prediction: { nextValue: values[values.length - 1] || 0, timeframe: 0, confidence: 0, }, }; } // Calculate linear regression const n = values.length; const x = Array.from({ length: n }, (_, i) => i); const y = values; const sumX = x.reduce((a, b) => a + b, 0); const sumY = y.reduce((a, b) => a + b, 0); const sumXY = x.map((xi, i) => xi * y[i]).reduce((a, b) => a + b, 0); const sumXX = x.map((xi) => xi * xi).reduce((a, b) => a + b, 0); const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX); const intercept = (sumY - slope * sumX) / n; // Calculate R-squared for confidence const yMean = sumY / n; const totalSumSquares = y.map((yi) => Math.pow(yi - yMean, 2)).reduce((a, b) => a + b, 0); const residualSumSquares = y .map((yi, i) => { const predicted = slope * x[i] + intercept; return Math.pow(yi - predicted, 2); }) .reduce((a, b) => a + b, 0); const rSquared = 1 - residualSumSquares / totalSumSquares; // Determine direction and change rate const currentValue = values[values.length - 1]; const previousValue = values[values.length - 2]; const changeRate = Math.abs((currentValue - previousValue) / previousValue) * 100; let direction: "improving" | "declining" | "stable" = "stable"; if (Math.abs(slope) > 0.1) { // For metrics where lower is better (response time, error rate) if (["responseTime", "errorRate", "memoryUsage"].includes(metricName)) { direction = slope < 0 ? "improving" : "declining"; } else { // For metrics where higher is better (cache hit rate) direction = slope > 0 ? "improving" : "declining"; } } // Predict next value const nextValue = slope * n + intercept; return { metric: metricName, direction, changeRate, confidence: Math.max(0, Math.min(1, rSquared)), prediction: { nextValue: Math.max(0, nextValue), timeframe: 30 * 60 * 1000, // 30 minutes confidence: Math.max(0, Math.min(1, rSquared * 0.8)), // Slightly lower confidence for predictions }, }; } /** * Detect anomalies in current metrics */ private detectAnomalies(metrics: PerformanceMetrics): void { if (this.historicalData.length < 10) return; // Need historical context const recentData = this.historicalData.slice(-10); // Check response time anomalies const responseTimes = recentData.map((d) => d.requests.averageResponseTime); this.checkMetricAnomaly( "responseTime", metrics.requests.averageResponseTime, responseTimes, "Response time spike detected", ); // Check cache hit rate anomalies const hitRates = recentData.map((d) => d.cache.hitRate); this.checkMetricAnomaly("cacheHitRate", metrics.cache.hitRate, hitRates, "Cache hit rate drop detected"); // Check error rate anomalies const errorRates = recentData.map((d) => (d.requests.total > 0 ? d.requests.failed / d.requests.total : 0)); const currentErrorRate = metrics.requests.total > 0 ? metrics.requests.failed / metrics.requests.total : 0; this.checkMetricAnomaly("errorRate", currentErrorRate, errorRates, "Error rate spike detected"); } /** * Check if a metric value is anomalous */ private checkMetricAnomaly( metricName: string, currentValue: number, historicalValues: number[], description: string, ): void { if (historicalValues.length < 5) return; const mean = historicalValues.reduce((a, b) => a + b, 0) / historicalValues.length; const variance = historicalValues.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) / historicalValues.length; const standardDeviation = Math.sqrt(variance); // Calculate z-score const zScore = Math.abs((currentValue - mean) / standardDeviation); // Determine sensitivity threshold let threshold = 2; // Default for medium sensitivity if (this.config.sensitivityLevel === "low") threshold = 3; if (this.config.sensitivityLevel === "high") threshold = 1.5; if (zScore > threshold) { const deviation = ((currentValue - mean) / mean) * 100; let severity: "minor" | "moderate" | "major" | "critical" = "minor"; if (zScore > 4) severity = "critical"; else if (zScore > 3) severity = "major"; else if (zScore > 2.5) severity = "moderate"; const anomaly: PerformanceAnomaly = { timestamp: Date.now(), metric: metricName, expectedValue: mean, actualValue: currentValue, deviation, severity, possibleCauses: this.generatePossibleCauses(metricName, currentValue > mean), }; this.detectedAnomalies.push(anomaly); // Limit anomaly history if (this.detectedAnomalies.length > 100) { this.detectedAnomalies = this.detectedAnomalies.slice(-50); } } } /** * Generate possible causes for anomalies */ private generatePossibleCauses(metricName: string, isIncrease: boolean): string[] { const causes: string[] = []; if (metricName === "responseTime" && isIncrease) { causes.push("High server load", "Database performance issues", "Network latency", "Cache miss increase"); } else if (metricName === "cacheHitRate" && !isIncrease) { causes.push("Cache invalidation event", "New data requests", "Cache size limit reached", "TTL expiration"); } else if (metricName === "errorRate" && isIncrease) { causes.push("WordPress site issues", "Authentication problems", "Network connectivity", "Plugin conflicts"); } return causes; } /** * Create benchmark comparison */ private createBenchmarkComparison( category: string, currentValue: number, benchmarks: Record<string, unknown>, higherIsBetter: boolean, ): BenchmarkComparison { let status: "excellent" | "good" | "average" | "below_average" | "poor" = "poor"; let percentile = 0; let improvement = 0; if (higherIsBetter) { if (currentValue >= (benchmarks.excellent as number)) status = "excellent"; else if (currentValue >= (benchmarks.good as number)) status = "good"; else if (currentValue >= (benchmarks.average as number)) status = "average"; else if (currentValue >= (benchmarks.below_average as number)) status = "below_average"; // Calculate improvement needed if (status !== "excellent") { const nextTier = status === "good" ? (benchmarks.excellent as number) : status === "average" ? (benchmarks.good as number) : status === "below_average" ? (benchmarks.average as number) : (benchmarks.below_average as number); improvement = nextTier - currentValue; } } else { if (currentValue <= (benchmarks.excellent as number)) status = "excellent"; else if (currentValue <= (benchmarks.good as number)) status = "good"; else if (currentValue <= (benchmarks.average as number)) status = "average"; else if (currentValue <= (benchmarks.below_average as number)) status = "below_average"; // Calculate improvement needed if (status !== "excellent") { const nextTier = status === "good" ? benchmarks.excellent : status === "average" ? benchmarks.good : status === "below_average" ? benchmarks.average : benchmarks.below_average; improvement = currentValue - (nextTier as number); } } // Calculate percentile (simplified) percentile = status === "excellent" ? 95 : status === "good" ? 80 : status === "average" ? 60 : status === "below_average" ? 30 : 10; return { category, currentValue, benchmarkValue: benchmarks.excellent as number, percentile, status, improvement, }; } /** * Get current value for a metric */ private getCurrentMetricValue(metricName: string): number { const current = this.collector.collectCurrentMetrics(); switch (metricName) { case "responseTime": return current.requests.averageResponseTime; case "cacheHitRate": return current.cache.hitRate; case "errorRate": return current.requests.total > 0 ? current.requests.failed / current.requests.total : 0; case "memoryUsage": return current.system.memoryUsage; case "requestVolume": return current.requests.requestsPerSecond; default: return 0; } } /** * Calculate overall performance score */ private calculatePerformanceScore(metrics: PerformanceMetrics): number { let score = 100; // Response time (30% weight) if (metrics.requests.averageResponseTime > 2000) score -= 30; else if (metrics.requests.averageResponseTime > 1000) score -= 15; else if (metrics.requests.averageResponseTime > 500) score -= 5; // Error rate (25% weight) const errorRate = metrics.requests.total > 0 ? metrics.requests.failed / metrics.requests.total : 0; if (errorRate > 0.05) score -= 25; else if (errorRate > 0.02) score -= 15; else if (errorRate > 0.01) score -= 5; // Cache performance (25% weight) if (metrics.cache.hitRate < 0.5) score -= 25; else if (metrics.cache.hitRate < 0.7) score -= 15; else if (metrics.cache.hitRate < 0.85) score -= 5; // System resources (20% weight) if (metrics.system.memoryUsage > 90) score -= 20; else if (metrics.system.memoryUsage > 80) score -= 10; else if (metrics.system.memoryUsage > 70) score -= 5; return Math.max(0, score); } /** * Calculate overall health status */ private calculateOverallHealth(score: number): string { if (score >= 90) return "excellent"; if (score >= 75) return "good"; if (score >= 60) return "fair"; if (score >= 40) return "poor"; return "critical"; } }

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/docdyhr/mcp-wordpress'

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