GreenPlusbyGXS / web /src /utils /systemHealth.js
gaialive's picture
Upload 106 files
759768a verified
/**
* SYSTEM HEALTH MONITORING
* Monitor application performance and health metrics
*/
export class SystemHealthMonitor {
constructor() {
this.metrics = {
performance: {},
errors: [],
warnings: [],
uptime: Date.now(),
lastCheck: Date.now()
};
this.thresholds = {
memoryUsage: 100 * 1024 * 1024, // 100MB
responseTime: 1000, // 1 second
errorRate: 0.05 // 5%
};
this.startMonitoring();
}
startMonitoring() {
// Monitor performance every 30 seconds
setInterval(() => {
this.checkSystemHealth();
}, 30000);
// Monitor memory usage
if (performance.memory) {
this.monitorMemoryUsage();
}
// Monitor network performance
this.monitorNetworkPerformance();
}
checkSystemHealth() {
const now = Date.now();
const uptime = now - this.metrics.uptime;
this.metrics.lastCheck = now;
this.metrics.performance.uptime = uptime;
// Check for performance issues
this.checkPerformanceMetrics();
// Clean old errors (keep last 100)
if (this.metrics.errors.length > 100) {
this.metrics.errors = this.metrics.errors.slice(-100);
}
// Clean old warnings (keep last 50)
if (this.metrics.warnings.length > 50) {
this.metrics.warnings = this.metrics.warnings.slice(-50);
}
return this.getHealthStatus();
}
monitorMemoryUsage() {
if (performance.memory) {
const memory = performance.memory;
this.metrics.performance.memory = {
used: memory.usedJSHeapSize,
total: memory.totalJSHeapSize,
limit: memory.jsHeapSizeLimit,
timestamp: Date.now()
};
// Check for memory leaks
if (memory.usedJSHeapSize > this.thresholds.memoryUsage) {
this.addWarning('High memory usage detected', {
used: memory.usedJSHeapSize,
threshold: this.thresholds.memoryUsage
});
}
}
}
monitorNetworkPerformance() {
// Monitor fetch performance
const originalFetch = window.fetch;
const self = this;
window.fetch = function(...args) {
const startTime = performance.now();
return originalFetch.apply(this, args)
.then(response => {
const endTime = performance.now();
const duration = endTime - startTime;
self.recordNetworkMetric(args[0], duration, response.status);
return response;
})
.catch(error => {
const endTime = performance.now();
const duration = endTime - startTime;
self.recordNetworkError(args[0], duration, error);
throw error;
});
};
}
recordNetworkMetric(url, duration, status) {
if (!this.metrics.performance.network) {
this.metrics.performance.network = [];
}
this.metrics.performance.network.push({
url: typeof url === 'string' ? url : url.toString(),
duration,
status,
timestamp: Date.now()
});
// Keep only last 50 network requests
if (this.metrics.performance.network.length > 50) {
this.metrics.performance.network = this.metrics.performance.network.slice(-50);
}
// Check for slow requests
if (duration > this.thresholds.responseTime) {
this.addWarning('Slow network request detected', {
url: typeof url === 'string' ? url : url.toString(),
duration,
threshold: this.thresholds.responseTime
});
}
}
recordNetworkError(url, duration, error) {
this.addError('Network request failed', {
url: typeof url === 'string' ? url : url.toString(),
duration,
error: error.message
});
}
checkPerformanceMetrics() {
// Check navigation timing
if (performance.navigation && performance.timing) {
const timing = performance.timing;
const loadTime = timing.loadEventEnd - timing.navigationStart;
this.metrics.performance.pageLoad = {
loadTime,
domReady: timing.domContentLoadedEventEnd - timing.navigationStart,
timestamp: Date.now()
};
}
// Check resource timing
if (performance.getEntriesByType) {
const resources = performance.getEntriesByType('resource');
const slowResources = resources.filter(resource => resource.duration > 1000);
if (slowResources.length > 0) {
this.addWarning('Slow resources detected', {
count: slowResources.length,
resources: slowResources.map(r => ({ name: r.name, duration: r.duration }))
});
}
}
}
addError(message, details = {}) {
this.metrics.errors.push({
message,
details,
timestamp: Date.now(),
type: 'error'
});
console.error('System Health Error:', message, details);
}
addWarning(message, details = {}) {
this.metrics.warnings.push({
message,
details,
timestamp: Date.now(),
type: 'warning'
});
console.warn('System Health Warning:', message, details);
}
getHealthStatus() {
const now = Date.now();
const recentErrors = this.metrics.errors.filter(e => now - e.timestamp < 300000); // Last 5 minutes
const recentWarnings = this.metrics.warnings.filter(w => now - w.timestamp < 300000);
let status = 'healthy';
let score = 100;
// Deduct points for errors and warnings
score -= recentErrors.length * 10;
score -= recentWarnings.length * 5;
// Check memory usage
if (this.metrics.performance.memory) {
const memoryUsage = this.metrics.performance.memory.used / this.metrics.performance.memory.limit;
if (memoryUsage > 0.8) {
score -= 20;
} else if (memoryUsage > 0.6) {
score -= 10;
}
}
// Check network performance
if (this.metrics.performance.network) {
const recentRequests = this.metrics.performance.network.filter(r => now - r.timestamp < 300000);
const slowRequests = recentRequests.filter(r => r.duration > this.thresholds.responseTime);
const errorRate = slowRequests.length / recentRequests.length;
if (errorRate > this.thresholds.errorRate) {
score -= 15;
}
}
// Determine status based on score
if (score >= 90) status = 'excellent';
else if (score >= 75) status = 'good';
else if (score >= 60) status = 'fair';
else if (score >= 40) status = 'poor';
else status = 'critical';
return {
status,
score: Math.max(0, score),
uptime: now - this.metrics.uptime,
lastCheck: this.metrics.lastCheck,
recentErrors: recentErrors.length,
recentWarnings: recentWarnings.length,
metrics: this.metrics
};
}
getDetailedReport() {
return {
...this.getHealthStatus(),
performance: this.metrics.performance,
recentErrors: this.metrics.errors.slice(-10),
recentWarnings: this.metrics.warnings.slice(-10)
};
}
reset() {
this.metrics = {
performance: {},
errors: [],
warnings: [],
uptime: Date.now(),
lastCheck: Date.now()
};
}
}
// Global instance
export const systemHealth = new SystemHealthMonitor();
// Utility functions
export const getSystemHealth = () => systemHealth.getHealthStatus();
export const getDetailedHealthReport = () => systemHealth.getDetailedReport();
export const recordError = (message, details) => systemHealth.addError(message, details);
export const recordWarning = (message, details) => systemHealth.addWarning(message, details);