UNPKG

fortify2-js

Version:

MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.

412 lines (409 loc) 14.9 kB
import { EventEmitter } from 'events'; import { PerformancePlugin } from '../core/PerformancePlugin.js'; import { PluginPriority } from '../types/PluginTypes.js'; /** * Response Time Monitoring Plugin * * Ultra-fast performance monitoring plugin with <0.3ms overhead * for tracking response times and performance metrics. */ /** * Response Time Monitoring Plugin for ultra-fast performance tracking */ class ResponseTimePlugin extends PerformancePlugin { constructor() { super(...arguments); this.eventEmitter = new EventEmitter(); this.id = "fortify.performance.response-time"; this.name = "Response Time Monitoring Plugin"; this.version = "1.0.0"; this.priority = PluginPriority.NORMAL; // Performance thresholds (can be configured) this.performanceThresholds = { responseTime: 100, // 100ms memoryUsage: 50 * 1024 * 1024, // 50MB cpuUsage: 80, // 80% }; // Performance tracking this.routeMetrics = new Map(); // Alert thresholds this.alertThresholds = { slowResponseTime: 1000, // 1 second verySlowResponseTime: 5000, // 5 seconds highMemoryUsage: 100 * 1024 * 1024, // 100MB criticalMemoryUsage: 200 * 1024 * 1024, // 200MB }; // Performance alerts this.alertCooldowns = new Map(); this.ALERT_COOLDOWN = 60000; // 1 minute } /** * Initialize performance monitoring plugin */ async initializePerformanceMonitoring(context) { // Configure thresholds from settings if (context.config.customSettings.responseTimeThreshold) { this.alertThresholds.slowResponseTime = context.config.customSettings.responseTimeThreshold; } if (context.config.customSettings.memoryThreshold) { this.alertThresholds.highMemoryUsage = context.config.customSettings.memoryThreshold; } // Setup periodic metrics cleanup this.setupMetricsCleanup(); // Setup performance alerts this.setupPerformanceAlerts(); context.logger.info("Response Time Monitoring Plugin initialized"); } /** * Execute performance monitoring logic */ executePerformanceLogic(context, metrics) { const { req, res } = context; const route = this.normalizeRoute(req.path); // Start response time tracking const startTime = performance.now(); // Add response time header res.setHeader("X-Response-Time-Start", startTime.toString()); // Hook into response finish event to capture total time const originalEnd = res.end; res.end = (...args) => { const endTime = performance.now(); const responseTime = endTime - startTime; // Record route metrics this.recordRouteMetrics(route, responseTime); // Add response time headers res.setHeader("X-Response-Time", `${responseTime.toFixed(2)}ms`); res.setHeader("X-Performance-Score", this.calculatePerformanceScore(responseTime, metrics)); // Check for performance alerts this.checkRoutePerformanceAlerts(route, responseTime, metrics); // Call original end method with proper arguments return originalEnd.apply(res, args); }; return { route, startTime, memoryUsage: metrics.memoryUsage, cpuUsage: metrics.cpuUsage, requestSize: metrics.requestSize, }; } /** * Precompile performance monitoring systems */ async precompilePerformanceMonitoring() { // Pre-warm performance calculation functions this.calculatePerformanceScore(100, { memoryUsage: 10 * 1024 * 1024, cpuUsage: 50, }); // Pre-warm route normalization this.normalizeRoute("/api/test/123"); } /** * Collect custom performance metrics */ collectCustomMetrics(context) { const { req } = context; const route = this.normalizeRoute(req.path); const routeMetrics = this.routeMetrics.get(route); return { route, routeMetrics: routeMetrics ? { averageResponseTime: routeMetrics.averageTime, p95ResponseTime: routeMetrics.p95Time, p99ResponseTime: routeMetrics.p99Time, requestCount: routeMetrics.count, minResponseTime: routeMetrics.minTime, maxResponseTime: routeMetrics.maxTime, } : null, totalRoutes: this.routeMetrics.size, alertsActive: this.getActiveAlerts(), }; } // ===== ROUTE METRICS METHODS ===== /** * Record metrics for a specific route */ recordRouteMetrics(route, responseTime) { let metrics = this.routeMetrics.get(route); if (!metrics) { metrics = { count: 0, totalTime: 0, minTime: Infinity, maxTime: 0, averageTime: 0, p95Time: 0, p99Time: 0, recentTimes: [], }; this.routeMetrics.set(route, metrics); } // Update basic metrics metrics.count++; metrics.totalTime += responseTime; metrics.minTime = Math.min(metrics.minTime, responseTime); metrics.maxTime = Math.max(metrics.maxTime, responseTime); metrics.averageTime = metrics.totalTime / metrics.count; // Update recent times for percentile calculation metrics.recentTimes.push(responseTime); // Keep only last 100 response times for memory efficiency if (metrics.recentTimes.length > 100) { metrics.recentTimes.shift(); } // Calculate percentiles this.updatePercentiles(metrics); } /** * Update percentile calculations */ updatePercentiles(metrics) { if (metrics.recentTimes.length === 0) return; const sortedTimes = [...metrics.recentTimes].sort((a, b) => a - b); const length = sortedTimes.length; // Calculate P95 (95th percentile) const p95Index = Math.ceil(length * 0.95) - 1; metrics.p95Time = sortedTimes[Math.max(0, p95Index)]; // Calculate P99 (99th percentile) const p99Index = Math.ceil(length * 0.99) - 1; metrics.p99Time = sortedTimes[Math.max(0, p99Index)]; } /** * Normalize route for consistent metrics tracking */ normalizeRoute(path) { // Replace dynamic segments with placeholders return path .replace(/\/\d+/g, "/:id") // Replace numeric IDs .replace(/\/[a-f0-9-]{36}/g, "/:uuid") // Replace UUIDs .replace(/\/[a-f0-9]{24}/g, "/:objectId") // Replace MongoDB ObjectIds .replace(/\?.*$/, ""); // Remove query parameters } // ===== PERFORMANCE SCORING ===== /** * Calculate performance score (0-100) */ calculatePerformanceScore(responseTime, metrics) { let score = 100; // Response time scoring (50% weight) if (responseTime > this.alertThresholds.verySlowResponseTime) { score -= 50; } else if (responseTime > this.alertThresholds.slowResponseTime) { score -= 25; } else if (responseTime > this.performanceThresholds.responseTime) { score -= 10; } // Memory usage scoring (25% weight) if (metrics.memoryUsage > this.alertThresholds.criticalMemoryUsage) { score -= 25; } else if (metrics.memoryUsage > this.alertThresholds.highMemoryUsage) { score -= 15; } else if (metrics.memoryUsage > this.performanceThresholds.memoryUsage) { score -= 5; } // CPU usage scoring (25% weight) if (metrics.cpuUsage > 90) { score -= 25; } else if (metrics.cpuUsage > this.performanceThresholds.cpuUsage) { score -= 10; } return Math.max(0, score); } // ===== PERFORMANCE ALERTS ===== /** * Check for performance alerts (override from PerformancePlugin) */ checkPerformanceAlerts(metrics) { const alerts = []; // Check response time alerts if (metrics.responseTime > this.alertThresholds.verySlowResponseTime) { alerts.push("CRITICAL: Response time severely degraded"); this.triggerAlert("critical_response_time", { route: metrics.route, responseTime: metrics.responseTime, threshold: this.alertThresholds.verySlowResponseTime, }); } else if (metrics.responseTime > this.alertThresholds.slowResponseTime) { alerts.push("WARNING: Slow response time detected"); this.triggerAlert("slow_response_time", { route: metrics.route, responseTime: metrics.responseTime, threshold: this.alertThresholds.slowResponseTime, }); } // Check memory usage alerts if (metrics.memoryUsage > this.alertThresholds.criticalMemoryUsage) { alerts.push("CRITICAL: Memory usage critically high"); this.triggerAlert("critical_memory_usage", { memoryUsage: metrics.memoryUsage, threshold: this.alertThresholds.criticalMemoryUsage, }); } else if (metrics.memoryUsage > this.alertThresholds.highMemoryUsage) { alerts.push("WARNING: High memory usage detected"); this.triggerAlert("high_memory_usage", { memoryUsage: metrics.memoryUsage, threshold: this.alertThresholds.highMemoryUsage, }); } // Check CPU usage alerts if (metrics.cpuUsage > 90) { alerts.push("CRITICAL: CPU usage critically high"); this.triggerAlert("critical_cpu_usage", { cpuUsage: metrics.cpuUsage, threshold: 90, }); } return alerts; } /** * Check for performance alerts with route-specific parameters */ checkRoutePerformanceAlerts(route, responseTime, metrics) { // Use the base class method with enhanced metrics const enhancedMetrics = { ...metrics, route, responseTime, }; this.checkPerformanceAlerts(enhancedMetrics); } /** * Trigger performance alert with cooldown */ triggerAlert(alertType, data) { const now = Date.now(); const lastAlert = this.alertCooldowns.get(alertType) || 0; // Check cooldown if (now - lastAlert < this.ALERT_COOLDOWN) { return; } // Update cooldown this.alertCooldowns.set(alertType, now); // Log alert console.warn(`[PERFORMANCE ALERT] ${alertType}:`, data); // Emit alert event (can be listened to by monitoring systems) this.eventEmitter.emit("performance_alert", { type: alertType, data, timestamp: new Date(), }); } /** * Get active alerts */ getActiveAlerts() { const now = Date.now(); const activeAlerts = []; for (const [alertType, lastTriggered,] of this.alertCooldowns.entries()) { if (now - lastTriggered < this.ALERT_COOLDOWN) { activeAlerts.push(alertType); } } return activeAlerts; } // ===== CLEANUP AND MAINTENANCE ===== /** * Setup metrics cleanup */ setupMetricsCleanup() { // Clean up old metrics every 10 minutes setInterval(() => { this.cleanupOldMetrics(); }, 600000); // 10 minutes } /** * Clean up old metrics to prevent memory leaks */ cleanupOldMetrics() { const now = Date.now(); // Remove routes that haven't been accessed in the last hour for (const [route, metrics] of this.routeMetrics.entries()) { // If no recent activity, remove the route metrics if (metrics.recentTimes.length === 0) { this.routeMetrics.delete(route); } } // Clean up old alert cooldowns for (const [alertType, lastTriggered,] of this.alertCooldowns.entries()) { if (now - lastTriggered > this.ALERT_COOLDOWN * 2) { this.alertCooldowns.delete(alertType); } } } /** * Setup performance alerts monitoring */ setupPerformanceAlerts() { // Monitor overall system performance every 30 seconds setInterval(() => { this.checkSystemPerformance(); }, 30000); // 30 seconds } /** * Check overall system performance */ checkSystemPerformance() { const memoryUsage = this.getMemoryUsage(); const cpuUsage = this.getCpuUsage(); // Check system-wide thresholds if (memoryUsage > this.alertThresholds.criticalMemoryUsage) { this.triggerAlert("system_critical_memory", { memoryUsage }); } if (cpuUsage > 95) { this.triggerAlert("system_critical_cpu", { cpuUsage }); } } // ===== PUBLIC API ===== /** * Get route performance summary */ getRoutePerformanceSummary() { const summary = {}; for (const [route, metrics] of this.routeMetrics.entries()) { summary[route] = { requestCount: metrics.count, averageResponseTime: Math.round(metrics.averageTime * 100) / 100, minResponseTime: Math.round(metrics.minTime * 100) / 100, maxResponseTime: Math.round(metrics.maxTime * 100) / 100, p95ResponseTime: Math.round(metrics.p95Time * 100) / 100, p99ResponseTime: Math.round(metrics.p99Time * 100) / 100, }; } return summary; } /** * Get performance alerts summary */ getPerformanceAlertsSummary() { return { activeAlerts: this.getActiveAlerts(), alertThresholds: this.alertThresholds, lastAlerts: Object.fromEntries(this.alertCooldowns), }; } /** * Reset route metrics */ resetRouteMetrics(route) { if (route) { this.routeMetrics.delete(route); } else { this.routeMetrics.clear(); } } } export { ResponseTimePlugin }; //# sourceMappingURL=ResponseTimePlugin.js.map