polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
513 lines • 18.8 kB
JavaScript
"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