UNPKG

polyv-live-cli

Version:

CLI tool for managing PolyV live streaming services.

513 lines 18.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.PerformanceMonitor = void 0; const events_1 = require("events"); const perf_hooks_1 = require("perf_hooks"); const os = __importStar(require("os")); class PerformanceMonitor extends events_1.EventEmitter { constructor(config = {}) { super(); this.metrics = []; this.alerts = []; this.profiles = new Map(); this.isRunning = false; this.startTime = Date.now(); this.lastCpuUsage = process.cpuUsage(); this.lastMeasurement = Date.now(); this.alertIdCounter = 0; this.activeProfiles = new Set(); this.config = { enableAutoMonitoring: true, monitoringInterval: 5000, maxRecords: 1000, cpuThreshold: 80, memoryThreshold: 100, responseTimeThreshold: 1000, enableAlerts: true, enableReporting: true, reportInterval: 300000, enableProfiling: false, profilingSampleRate: 0.1, ...config, }; this.setupEventHandlers(); } start() { if (this.isRunning) { return; } this.isRunning = true; this.startTime = Date.now(); this.lastMeasurement = Date.now(); this.lastCpuUsage = process.cpuUsage(); if (this.config.enableAutoMonitoring) { this.startMonitoring(); } if (this.config.enableReporting) { this.startReporting(); } this.emit('monitoringStarted', { timestamp: Date.now(), config: this.config, }); } stop() { if (!this.isRunning) { return; } this.isRunning = false; if (this.monitoringTimer) { clearInterval(this.monitoringTimer); delete this.monitoringTimer; } if (this.reportTimer) { clearInterval(this.reportTimer); delete this.reportTimer; } for (const profileId of this.activeProfiles) { this.stopProfile(profileId); } const finalReport = this.generateReport(); this.emit('monitoringStopped', { timestamp: Date.now(), uptime: Date.now() - this.startTime, finalReport, }); } collectMetrics() { const now = Date.now(); const memoryUsage = process.memoryUsage(); const cpuUsage = process.cpuUsage(this.lastCpuUsage); const systemLoad = os.loadavg(); const cpuPercent = (cpuUsage.user + cpuUsage.system) / ((now - this.lastMeasurement) * 1000) * 100; const eventLoopDelay = this.measureEventLoopDelay(); const metrics = { timestamp: now, cpuUsage: Math.min(cpuPercent, 100), memoryUsage: memoryUsage.rss / 1024 / 1024, heapUsage: memoryUsage.heapUsed / 1024 / 1024, eventLoopDelay, renderTime: 0, apiResponseTime: 0, apiCallCount: 0, errorCount: 0, cacheHitRate: 0, activeConnections: 0, gcPauseTime: 0, frameRate: 0, systemLoad, }; this.lastCpuUsage = process.cpuUsage(); this.lastMeasurement = now; return metrics; } recordMetrics(metrics) { const currentMetrics = this.collectMetrics(); const combinedMetrics = { ...currentMetrics, ...metrics }; this.metrics.push(combinedMetrics); if (this.metrics.length > this.config.maxRecords) { this.metrics = this.metrics.slice(-this.config.maxRecords); } if (this.config.enableAlerts) { this.checkAlerts(combinedMetrics); } this.emit('metricsRecorded', { metrics: combinedMetrics, timestamp: Date.now(), }); } startProfile(profileId, name) { if (this.activeProfiles.has(profileId)) { return; } const profile = { id: profileId, name, startTime: Date.now(), endTime: 0, duration: 0, cpuSamples: [], memorySamples: [], callStack: [], hotSpots: [], }; this.profiles.set(profileId, profile); this.activeProfiles.add(profileId); if (this.config.enableProfiling) { this.startProfilingSampling(profileId); } this.emit('profileStarted', { profileId, name, timestamp: Date.now(), }); } stopProfile(profileId) { const profile = this.profiles.get(profileId); if (!profile || !this.activeProfiles.has(profileId)) { return null; } profile.endTime = Date.now(); profile.duration = profile.endTime - profile.startTime; this.activeProfiles.delete(profileId); this.analyzeProfile(profile); this.emit('profileStopped', { profileId, duration: profile.duration, timestamp: Date.now(), }); return profile; } getMetrics(timeRange) { if (!timeRange) { return [...this.metrics]; } return this.metrics.filter(metric => metric.timestamp >= timeRange.start && metric.timestamp <= timeRange.end); } getTrends(timeRange) { const metrics = this.getMetrics(timeRange); if (metrics.length < 2) { return []; } const trends = []; const metricKeys = [ 'cpuUsage', 'memoryUsage', 'renderTime', 'apiResponseTime', 'errorCount' ]; for (const key of metricKeys) { const values = metrics.map(m => m[key]).filter(v => !isNaN(v)); if (values.length < 2) continue; const trend = this.calculateTrend(key, values); trends.push(trend); } return trends; } getAlerts(timeRange) { if (!timeRange) { return [...this.alerts]; } return this.alerts.filter(alert => alert.timestamp >= timeRange.start && alert.timestamp <= timeRange.end); } generateReport(timeRange) { const now = Date.now(); const period = timeRange || { start: now - 3600000, end: now, }; const metrics = this.getMetrics(period); const trends = this.getTrends(period); const alerts = this.getAlerts(period); const summary = this.calculateSummary(metrics); const recommendations = this.generateRecommendations(metrics, trends, alerts); return { timestamp: now, period, summary, trends, alerts, recommendations, metrics, }; } getProfile(profileId) { return this.profiles.get(profileId) || null; } clearData() { const clearedMetrics = this.metrics.length; const clearedAlerts = this.alerts.length; const clearedProfiles = this.profiles.size; this.metrics = []; this.alerts = []; this.profiles.clear(); this.emit('dataCleared', { clearedMetrics, clearedAlerts, clearedProfiles, timestamp: Date.now(), }); } updateConfig(newConfig) { this.config = { ...this.config, ...newConfig }; if (this.isRunning) { this.stop(); this.start(); } this.emit('configUpdated', { config: this.config, timestamp: Date.now(), }); } measureEventLoopDelay() { const start = perf_hooks_1.performance.now(); return new Promise((resolve) => { setImmediate(() => { resolve(perf_hooks_1.performance.now() - start); }); }); } startMonitoring() { this.monitoringTimer = setInterval(() => { this.recordMetrics({}); }, this.config.monitoringInterval); } startReporting() { this.reportTimer = setInterval(() => { const report = this.generateReport(); this.emit('reportGenerated', { report, timestamp: Date.now(), }); }, this.config.reportInterval); } checkAlerts(metrics) { const alerts = []; if (metrics.cpuUsage > this.config.cpuThreshold) { alerts.push({ id: `alert_${++this.alertIdCounter}`, type: 'warning', message: `High CPU usage: ${metrics.cpuUsage.toFixed(1)}%`, metric: 'cpuUsage', currentValue: metrics.cpuUsage, threshold: this.config.cpuThreshold, timestamp: Date.now(), severity: 7, suggestedActions: [ 'Review CPU-intensive operations', 'Optimize algorithms', 'Consider load balancing', ], }); } if (metrics.memoryUsage > this.config.memoryThreshold) { alerts.push({ id: `alert_${++this.alertIdCounter}`, type: 'warning', message: `High memory usage: ${metrics.memoryUsage.toFixed(1)}MB`, metric: 'memoryUsage', currentValue: metrics.memoryUsage, threshold: this.config.memoryThreshold, timestamp: Date.now(), severity: 6, suggestedActions: [ 'Review memory allocation', 'Clear unused cache', 'Check for memory leaks', ], }); } if (metrics.apiResponseTime > this.config.responseTimeThreshold) { alerts.push({ id: `alert_${++this.alertIdCounter}`, type: 'warning', message: `Slow API response: ${metrics.apiResponseTime.toFixed(0)}ms`, metric: 'apiResponseTime', currentValue: metrics.apiResponseTime, threshold: this.config.responseTimeThreshold, timestamp: Date.now(), severity: 5, suggestedActions: [ 'Check network connectivity', 'Optimize API queries', 'Enable caching', ], }); } for (const alert of alerts) { this.alerts.push(alert); this.emit('alertTriggered', alert); } if (this.alerts.length > this.config.maxRecords) { this.alerts = this.alerts.slice(-this.config.maxRecords); } } startProfilingSampling(profileId) { const profile = this.profiles.get(profileId); if (!profile) return; const sampleInterval = 100; const samplingTimer = setInterval(() => { if (!this.activeProfiles.has(profileId)) { clearInterval(samplingTimer); return; } const metrics = this.collectMetrics(); profile.cpuSamples.push({ timestamp: Date.now(), usage: metrics.cpuUsage, }); profile.memorySamples.push({ timestamp: Date.now(), usage: metrics.memoryUsage, }); }, sampleInterval); } analyzeProfile(profile) { const cpuHotSpots = this.findHotSpots(profile.cpuSamples); const memoryHotSpots = this.findHotSpots(profile.memorySamples); profile.hotSpots = [ ...cpuHotSpots.map(spot => ({ location: `CPU-${spot.timestamp}`, time: spot.usage, percentage: (spot.usage / 100) * 100, })), ...memoryHotSpots.map(spot => ({ location: `Memory-${spot.timestamp}`, time: spot.usage, percentage: (spot.usage / (profile.memorySamples.reduce((max, s) => Math.max(max, s.usage), 0) || 1)) * 100, })), ]; } findHotSpots(samples) { if (samples.length < 2) return []; const threshold = samples.reduce((sum, s) => sum + s.usage, 0) / samples.length * 1.5; return samples.filter(sample => sample.usage > threshold); } calculateTrend(metric, values) { if (values.length < 2) { return { metric, direction: 'stable', strength: 0, average: 0, min: 0, max: 0, standardDeviation: 0, prediction: 0, }; } const average = values.reduce((sum, val) => sum + val, 0) / values.length; const min = Math.min(...values); const max = Math.max(...values); const variance = values.reduce((sum, val) => sum + Math.pow(val - average, 2), 0) / values.length; const standardDeviation = Math.sqrt(variance); const firstHalf = values.slice(0, Math.floor(values.length / 2)); const secondHalf = values.slice(Math.floor(values.length / 2)); const firstAvg = firstHalf.reduce((sum, val) => sum + val, 0) / firstHalf.length; const secondAvg = secondHalf.reduce((sum, val) => sum + val, 0) / secondHalf.length; const difference = secondAvg - firstAvg; const direction = Math.abs(difference) < average * 0.1 ? 'stable' : difference > 0 ? 'increasing' : 'decreasing'; const strength = Math.min(Math.abs(difference) / average, 1); const prediction = average + (difference / firstHalf.length) * values.length; return { metric, direction, strength, average, min, max, standardDeviation, prediction, }; } calculateSummary(metrics) { if (metrics.length === 0) { return { averageCpuUsage: 0, averageMemoryUsage: 0, averageResponseTime: 0, totalApiCalls: 0, totalErrors: 0, averageCacheHitRate: 0, uptime: Date.now() - this.startTime, systemHealth: 'healthy', }; } const averageCpuUsage = metrics.reduce((sum, m) => sum + m.cpuUsage, 0) / metrics.length; const averageMemoryUsage = metrics.reduce((sum, m) => sum + m.memoryUsage, 0) / metrics.length; const averageResponseTime = metrics.reduce((sum, m) => sum + m.apiResponseTime, 0) / metrics.length; const totalApiCalls = metrics.reduce((sum, m) => sum + m.apiCallCount, 0); const totalErrors = metrics.reduce((sum, m) => sum + m.errorCount, 0); const averageCacheHitRate = metrics.reduce((sum, m) => sum + m.cacheHitRate, 0) / metrics.length; let systemHealth = 'healthy'; if (averageCpuUsage > 80 || averageMemoryUsage > 200 || averageResponseTime > 2000) { systemHealth = 'critical'; } else if (averageCpuUsage > 60 || averageMemoryUsage > 150 || averageResponseTime > 1000) { systemHealth = 'degraded'; } return { averageCpuUsage, averageMemoryUsage, averageResponseTime, totalApiCalls, totalErrors, averageCacheHitRate, uptime: Date.now() - this.startTime, systemHealth, }; } generateRecommendations(_metrics, trends, alerts) { const recommendations = []; const cpuTrend = trends.find(t => t.metric === 'cpuUsage'); if (cpuTrend && cpuTrend.direction === 'increasing' && cpuTrend.average > 50) { recommendations.push('Consider optimizing CPU-intensive operations'); } const memoryTrend = trends.find(t => t.metric === 'memoryUsage'); if (memoryTrend && memoryTrend.direction === 'increasing') { recommendations.push('Review memory usage and implement cleanup strategies'); } const responseTrend = trends.find(t => t.metric === 'apiResponseTime'); if (responseTrend && responseTrend.average > 500) { recommendations.push('Optimize API calls with caching and request batching'); } const criticalAlerts = alerts.filter(a => a.type === 'critical'); if (criticalAlerts.length > 0) { recommendations.push('Address critical performance alerts immediately'); } if (recommendations.length === 0) { recommendations.push('Performance is within acceptable ranges'); } return recommendations; } setupEventHandlers() { process.on('warning', (warning) => { this.emit('performanceWarning', { warning: warning.message, timestamp: Date.now(), }); }); process.on('uncaughtException', (error) => { this.emit('performanceError', { error: error.message, timestamp: Date.now(), }); }); } } exports.PerformanceMonitor = PerformanceMonitor; //# sourceMappingURL=performance-monitor.js.map