import { useState, useCallback, useRef, useEffect } from 'react'; import { PerformanceLogEntry, ResourceUsage } from '../types'; interface PerformanceConfig { enableLogging?: boolean; logLevel?: 'debug' | 'info' | 'warn' | 'error'; metricsInterval?: number; maxLogEntries?: number; } interface PerformanceMetrics { cpu: number; memory: number; diskIO: number; networkIO: number; responseTime: number; throughput: number; errorRate: number; } interface AnomalyThresholds { cpu: number; memory: number; responseTime: number; errorRate: number; } export const usePerformanceMonitoring = (config: PerformanceConfig = {}) => { const [performanceLog, setPerformanceLog] = useState([]); const [isMonitoring, setIsMonitoring] = useState(false); const [currentMetrics, setCurrentMetrics] = useState({ cpu: 0, memory: 0, diskIO: 0, networkIO: 0, responseTime: 0, throughput: 0, errorRate: 0 }); const monitoringIntervalRef = useRef(null); const metricsHistoryRef = useRef([]); const startTimeRef = useRef(Date.now()); const requestCountRef = useRef(0); const errorCountRef = useRef(0); const defaultThresholds: AnomalyThresholds = { cpu: 0.8, memory: 0.85, responseTime: 5000, // 5 seconds errorRate: 0.05 // 5% }; // Start performance monitoring const startMonitoring = useCallback(async () => { if (isMonitoring) return; setIsMonitoring(true); startTimeRef.current = Date.now(); const interval = config.metricsInterval || 5000; // Default 5 seconds monitoringIntervalRef.current = setInterval(() => { collectMetrics(); }, interval); // Log monitoring start logEvent({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'monitoring_started', status: 'success', details: { interval, config }, resourceUsage: { cpu: 0, memory: 0, diskIO: 0, networkIO: 0 } }); }, [config, isMonitoring]); // Stop performance monitoring const stopMonitoring = useCallback(() => { if (!isMonitoring) return; setIsMonitoring(false); if (monitoringIntervalRef.current) { clearInterval(monitoringIntervalRef.current); monitoringIntervalRef.current = null; } // Log monitoring stop logEvent({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'monitoring_stopped', status: 'success', details: { duration: Date.now() - startTimeRef.current, totalRequests: requestCountRef.current, totalErrors: errorCountRef.current }, resourceUsage: currentMetrics }); }, [isMonitoring, currentMetrics]); // Collect performance metrics const collectMetrics = useCallback(() => { const metrics: PerformanceMetrics = { cpu: getCPUUsage(), memory: getMemoryUsage(), diskIO: getDiskIOUsage(), networkIO: getNetworkIOUsage(), responseTime: getAverageResponseTime(), throughput: calculateThroughput(), errorRate: calculateErrorRate() }; setCurrentMetrics(metrics); // Store in history (keep last 100 entries) metricsHistoryRef.current = [...metricsHistoryRef.current.slice(-99), metrics]; // Log metrics if enabled if (config.enableLogging !== false) { logEvent({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'metrics_collected', status: 'success', details: metrics, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } }, [config.enableLogging]); // Simulated metric collection functions (in real implementation, these would use actual system APIs) const getCPUUsage = (): number => { // Simulate CPU usage with some randomness and trends const baseUsage = 0.2 + Math.random() * 0.3; const timeVariation = Math.sin(Date.now() / 10000) * 0.1; return Math.max(0, Math.min(1, baseUsage + timeVariation)); }; const getMemoryUsage = (): number => { // Simulate memory usage that gradually increases const baseUsage = 0.3; const growth = (Date.now() - startTimeRef.current) / (1000 * 60 * 60) * 0.1; // 10% per hour const randomVariation = Math.random() * 0.1; return Math.max(0, Math.min(1, baseUsage + growth + randomVariation)); }; const getDiskIOUsage = (): number => { // Simulate disk I/O with spikes during file processing const baseIO = 0.1 + Math.random() * 0.2; return Math.max(0, Math.min(1, baseIO)); }; const getNetworkIOUsage = (): number => { // Simulate network I/O const baseIO = 0.05 + Math.random() * 0.15; return Math.max(0, Math.min(1, baseIO)); }; const getAverageResponseTime = (): number => { // Simulate response time in milliseconds const baseTime = 100 + Math.random() * 200; const loadFactor = currentMetrics.cpu * 500; // Higher CPU = slower response return baseTime + loadFactor; }; const calculateThroughput = (): number => { // Calculate requests per second const elapsedSeconds = (Date.now() - startTimeRef.current) / 1000; return elapsedSeconds > 0 ? requestCountRef.current / elapsedSeconds : 0; }; const calculateErrorRate = (): number => { // Calculate error rate as percentage return requestCountRef.current > 0 ? errorCountRef.current / requestCountRef.current : 0; }; // Log performance events const logEvent = useCallback((entry: PerformanceLogEntry) => { const logLevel = config.logLevel || 'info'; const shouldLog = shouldLogLevel(entry.eventType, logLevel); if (!shouldLog) return; setPerformanceLog(prev => { const maxEntries = config.maxLogEntries || 1000; const newLog = [...prev, entry]; // Keep only the most recent entries if (newLog.length > maxEntries) { return newLog.slice(-maxEntries); } return newLog; }); }, [config.logLevel, config.maxLogEntries]); // Determine if event should be logged based on level const shouldLogLevel = (eventType: string, logLevel: string): boolean => { const eventLevels: Record = { debug: 0, info: 1, warn: 2, error: 3 }; const configLevels: Record = { debug: 0, info: 1, warn: 2, error: 3 }; const eventLevel = eventType.includes('error') ? 3 : eventType.includes('warn') || eventType.includes('anomaly') ? 2 : 1; return eventLevel >= (configLevels[logLevel] || 1); }; // Get current performance metrics const getPerformanceMetrics = useCallback(async (): Promise => { return currentMetrics; }, [currentMetrics]); // Detect performance anomalies const detectAnomalies = useCallback(async (metrics: PerformanceMetrics): Promise => { const anomalies: PerformanceLogEntry[] = []; const thresholds = defaultThresholds; // CPU anomaly detection if (metrics.cpu > thresholds.cpu) { anomalies.push({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'cpu_anomaly', status: 'warning', details: { currentCPU: metrics.cpu, threshold: thresholds.cpu, severity: metrics.cpu > 0.95 ? 'critical' : 'warning' }, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } // Memory anomaly detection if (metrics.memory > thresholds.memory) { anomalies.push({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'memory_anomaly', status: 'warning', details: { currentMemory: metrics.memory, threshold: thresholds.memory, severity: metrics.memory > 0.95 ? 'critical' : 'warning' }, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } // Response time anomaly detection if (metrics.responseTime > thresholds.responseTime) { anomalies.push({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'response_time_anomaly', status: 'warning', details: { currentResponseTime: metrics.responseTime, threshold: thresholds.responseTime, severity: metrics.responseTime > 10000 ? 'critical' : 'warning' }, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } // Error rate anomaly detection if (metrics.errorRate > thresholds.errorRate) { anomalies.push({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'error_rate_anomaly', status: 'warning', details: { currentErrorRate: metrics.errorRate, threshold: thresholds.errorRate, severity: metrics.errorRate > 0.1 ? 'critical' : 'warning' }, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } // Trend-based anomaly detection if (metricsHistoryRef.current.length >= 5) { const recentMetrics = metricsHistoryRef.current.slice(-5); // Detect rapid CPU increase const cpuTrend = recentMetrics.map(m => m.cpu); const cpuIncrease = cpuTrend[cpuTrend.length - 1] - cpuTrend[0]; if (cpuIncrease > 0.3) { anomalies.push({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'cpu_trend_anomaly', status: 'warning', details: { trend: 'increasing', increase: cpuIncrease, timeWindow: '5 measurements' }, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } // Detect memory leak pattern const memoryTrend = recentMetrics.map(m => m.memory); const memoryIncrease = memoryTrend[memoryTrend.length - 1] - memoryTrend[0]; if (memoryIncrease > 0.2 && memoryTrend.every((val, i) => i === 0 || val >= memoryTrend[i - 1])) { anomalies.push({ id: crypto.randomUUID(), timestamp: new Date(), eventType: 'memory_leak_anomaly', status: 'warning', details: { trend: 'consistent_increase', increase: memoryIncrease, pattern: 'potential_memory_leak' }, resourceUsage: { cpu: metrics.cpu, memory: metrics.memory, diskIO: metrics.diskIO, networkIO: metrics.networkIO } }); } } // Log detected anomalies anomalies.forEach(anomaly => { logEvent(anomaly); }); return anomalies; }, [logEvent]); // Track request for throughput calculation const trackRequest = useCallback((isError: boolean = false) => { requestCountRef.current++; if (isError) { errorCountRef.current++; } }, []); // Get performance statistics const getPerformanceStats = useCallback(() => { const uptime = Date.now() - startTimeRef.current; const avgCPU = metricsHistoryRef.current.length > 0 ? metricsHistoryRef.current.reduce((sum, m) => sum + m.cpu, 0) / metricsHistoryRef.current.length : 0; const avgMemory = metricsHistoryRef.current.length > 0 ? metricsHistoryRef.current.reduce((sum, m) => sum + m.memory, 0) / metricsHistoryRef.current.length : 0; return { uptime, totalRequests: requestCountRef.current, totalErrors: errorCountRef.current, currentMetrics, averageMetrics: { cpu: avgCPU, memory: avgMemory }, logEntries: performanceLog.length, isMonitoring }; }, [currentMetrics, performanceLog.length, isMonitoring]); // Reset monitoring data const reset = useCallback(() => { setPerformanceLog([]); setCurrentMetrics({ cpu: 0, memory: 0, diskIO: 0, networkIO: 0, responseTime: 0, throughput: 0, errorRate: 0 }); metricsHistoryRef.current = []; requestCountRef.current = 0; errorCountRef.current = 0; startTimeRef.current = Date.now(); }, []); // Cleanup on unmount useEffect(() => { return () => { if (monitoringIntervalRef.current) { clearInterval(monitoringIntervalRef.current); } }; }, []); return { performanceLog, currentMetrics, isMonitoring, startMonitoring, stopMonitoring, getPerformanceMetrics, detectAnomalies, trackRequest, getPerformanceStats, logEvent, reset }; };