This commit is contained in:
MCHost
2025-09-25 20:52:54 -04:00
parent 0da10d5139
commit 5539d45780
2 changed files with 62 additions and 87 deletions
+61 -86
View File
@@ -150,7 +150,8 @@
<div class="chart-container"> <div class="chart-container">
<canvas id="docker-net-chart"></canvas> <canvas id="docker-net-chart"></canvas>
</div> </div>
</div> <h3 class="text-xl minecraft-font mb-6 text-teal-400 text-center">Minecraft Containers (Sorted by CPU)</h3> </div>
<h3 class="text-xl minecraft-font mb-6 text-teal-400 text-center">Minecraft Containers (Sorted by CPU)</h3>
<div class="container-table"> <div class="container-table">
<table class="w-full text-sm text-gray-200 mb-8"> <table class="w-full text-sm text-gray-200 mb-8">
<thead class="text-xs uppercase bg-gray-800"> <thead class="text-xs uppercase bg-gray-800">
@@ -295,7 +296,7 @@
<script> <script>
const ws = new WebSocket('wss://' + window.location.host); const ws = new WebSocket('wss://' + window.location.host);
const socket = ws const socket = ws;
let charts = {}; let charts = {};
let dockerNetHistory = []; let dockerNetHistory = [];
let netHistory = []; let netHistory = [];
@@ -305,10 +306,9 @@
let hostLoadHistory = []; let hostLoadHistory = [];
let jumpLoadHistory = []; let jumpLoadHistory = [];
let jumpRamHistory = []; let jumpRamHistory = [];
const MAX_POINTS = 30; // Match to points in API query const MAX_POINTS = 30;
const SMOOTHING_WINDOW = 3; const SMOOTHING_WINDOW = 3;
// Helper to smooth data
function smoothData(data, windowSize) { function smoothData(data, windowSize) {
if (!data || data.length < windowSize) return data || []; if (!data || data.length < windowSize) return data || [];
return data.map((_, i) => { return data.map((_, i) => {
@@ -318,7 +318,6 @@
}); });
} }
// Helper to format bytes dynamically (mirrors system-status.js)
function formatBytes(bytes) { function formatBytes(bytes) {
if (bytes >= 1e9) return { value: (bytes / 1e9).toFixed(2), unit: 'GB/s' }; if (bytes >= 1e9) return { value: (bytes / 1e9).toFixed(2), unit: 'GB/s' };
if (bytes >= 1e6) return { value: (bytes / 1e6).toFixed(2), unit: 'MB/s' }; if (bytes >= 1e6) return { value: (bytes / 1e6).toFixed(2), unit: 'MB/s' };
@@ -326,13 +325,15 @@
return { value: bytes.toFixed(2), unit: 'B/s' }; return { value: bytes.toFixed(2), unit: 'B/s' };
} }
// Helper to format uptime in days
function formatUptime(seconds) { function formatUptime(seconds) {
const days = Math.floor(seconds / (60 * 60 * 24)); const days = Math.floor(seconds / (60 * 60 * 24));
return `${days} days`; return `${days} days`;
} }
// Initialize Chart.js charts function formatTime(timestamp) {
return new Date(timestamp * 1000).toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit' });
}
function initCharts() { function initCharts() {
if (typeof Chart === 'undefined') { if (typeof Chart === 'undefined') {
console.error('Chart.js failed to load.'); console.error('Chart.js failed to load.');
@@ -366,7 +367,11 @@
animation: { duration: 500, easing: 'linear' }, animation: { duration: 500, easing: 'linear' },
scales: { scales: {
y: { beginAtZero: true, grid: { color: 'rgba(255,255,255,0.1)' }, ticks: { color: '#e5e7eb' } }, y: { beginAtZero: true, grid: { color: 'rgba(255,255,255,0.1)' }, ticks: { color: '#e5e7eb' } },
x: { grid: { display: false }, ticks: { color: '#e5e7eb' } } x: {
grid: { display: false },
ticks: { color: '#e5e7eb', autoSkip: true, maxTicksLimit: 10 },
title: { display: true, text: 'Time (oldest to newest)', color: '#e5e7eb' }
}
}, },
plugins: { plugins: {
tooltip: { mode: 'index', intersect: false }, tooltip: { mode: 'index', intersect: false },
@@ -375,12 +380,12 @@
}; };
charts.dockerNet = new Chart(canvases.dockerNet.getContext('2d'), { charts.dockerNet = new Chart(canvases.dockerNet.getContext('2d'), {
type: 'bar', type: 'line',
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'In', data: [], backgroundColor: '#38bdf8', stack: 'Stack 0' }, { label: 'In', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Out', data: [], backgroundColor: '#fb7185', stack: 'Stack 0' } { label: 'Out', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -391,10 +396,7 @@
stacked: true, stacked: true,
title: { display: true, text: 'Speed', color: '#e5e7eb' } title: { display: true, text: 'Speed', color: '#e5e7eb' }
}, },
x: { x: commonOptions.scales.x
...commonOptions.scales.x,
stacked: true
}
} }
} }
}); });
@@ -404,8 +406,8 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'User (%)', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: 'User (%)', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'System (%)', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 } { label: 'System (%)', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -413,6 +415,7 @@
scales: { scales: {
y: { y: {
...commonOptions.scales.y, ...commonOptions.scales.y,
stacked: true,
max: 100, max: 100,
title: { display: true, text: 'Usage (%)', color: '#e5e7eb' } title: { display: true, text: 'Usage (%)', color: '#e5e7eb' }
}, },
@@ -426,8 +429,8 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'Used (MB)', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: 'Used (MB)', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Free (MB)', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 } { label: 'Free (MB)', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -435,6 +438,7 @@
scales: { scales: {
y: { y: {
...commonOptions.scales.y, ...commonOptions.scales.y,
stacked: true,
title: { display: true, text: 'Memory (MB)', color: '#e5e7eb' } title: { display: true, text: 'Memory (MB)', color: '#e5e7eb' }
}, },
x: commonOptions.scales.x x: commonOptions.scales.x
@@ -443,12 +447,12 @@
}); });
charts.net = new Chart(canvases.net.getContext('2d'), { charts.net = new Chart(canvases.net.getContext('2d'), {
type: 'bar', type: 'line',
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'Received', data: [], backgroundColor: '#38bdf8', stack: 'Stack 0' }, { label: 'Received', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Sent', data: [], backgroundColor: '#fb7185', stack: 'Stack 0' } { label: 'Sent', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -459,10 +463,7 @@
stacked: true, stacked: true,
title: { display: true, text: 'Speed', color: '#e5e7eb' } title: { display: true, text: 'Speed', color: '#e5e7eb' }
}, },
x: { x: commonOptions.scales.x
...commonOptions.scales.x,
stacked: true
}
} }
} }
}); });
@@ -472,8 +473,8 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'Read', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: 'Read', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Write', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 } { label: 'Write', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -481,6 +482,7 @@
scales: { scales: {
y: { y: {
...commonOptions.scales.y, ...commonOptions.scales.y,
stacked: true,
title: { display: true, text: 'Speed', color: '#e5e7eb' } title: { display: true, text: 'Speed', color: '#e5e7eb' }
}, },
x: commonOptions.scales.x x: commonOptions.scales.x
@@ -493,9 +495,9 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: '1m', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: '1m', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0.4 },
{ label: '5m', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 }, { label: '5m', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0.4 },
{ label: '15m', data: [], borderColor: '#10b981', borderWidth: 2, fill: false, tension: 0 } { label: '15m', data: [], borderColor: '#10b981', borderWidth: 2, fill: false, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -515,8 +517,8 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'User (%)', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: 'User (%)', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'System (%)', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 } { label: 'System (%)', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -524,6 +526,7 @@
scales: { scales: {
y: { y: {
...commonOptions.scales.y, ...commonOptions.scales.y,
stacked: true,
max: 100, max: 100,
title: { display: true, text: 'Usage (%)', color: '#e5e7eb' } title: { display: true, text: 'Usage (%)', color: '#e5e7eb' }
}, },
@@ -537,8 +540,8 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'Used (MB)', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: 'Used (MB)', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Free (MB)', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 } { label: 'Free (MB)', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -546,6 +549,7 @@
scales: { scales: {
y: { y: {
...commonOptions.scales.y, ...commonOptions.scales.y,
stacked: true,
title: { display: true, text: 'Memory (MB)', color: '#e5e7eb' } title: { display: true, text: 'Memory (MB)', color: '#e5e7eb' }
}, },
x: commonOptions.scales.x x: commonOptions.scales.x
@@ -554,12 +558,12 @@
}); });
charts.jumpNet = new Chart(canvases.jumpNet.getContext('2d'), { charts.jumpNet = new Chart(canvases.jumpNet.getContext('2d'), {
type: 'bar', type: 'line',
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'Received', data: [], backgroundColor: '#38bdf8', stack: 'Stack 0' }, { label: 'Received', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Sent', data: [], backgroundColor: '#fb7185', stack: 'Stack 0' } { label: 'Sent', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -570,10 +574,7 @@
stacked: true, stacked: true,
title: { display: true, text: 'Speed', color: '#e5e7eb' } title: { display: true, text: 'Speed', color: '#e5e7eb' }
}, },
x: { x: commonOptions.scales.x
...commonOptions.scales.x,
stacked: true
}
} }
} }
}); });
@@ -583,8 +584,8 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: 'Read', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: 'Read', data: [], borderColor: '#38bdf8', backgroundColor: 'rgba(56, 189, 248, 0.5)', borderWidth: 2, fill: true, tension: 0.4 },
{ label: 'Write', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 } { label: 'Write', data: [], borderColor: '#fb7185', backgroundColor: 'rgba(251, 113, 133, 0.5)', borderWidth: 2, fill: true, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -592,6 +593,7 @@
scales: { scales: {
y: { y: {
...commonOptions.scales.y, ...commonOptions.scales.y,
stacked: true,
title: { display: true, text: 'Speed', color: '#e5e7eb' } title: { display: true, text: 'Speed', color: '#e5e7eb' }
}, },
x: commonOptions.scales.x x: commonOptions.scales.x
@@ -604,9 +606,9 @@
data: { data: {
labels: [], labels: [],
datasets: [ datasets: [
{ label: '1m', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0 }, { label: '1m', data: [], borderColor: '#38bdf8', borderWidth: 2, fill: false, tension: 0.4 },
{ label: '5m', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0 }, { label: '5m', data: [], borderColor: '#fb7185', borderWidth: 2, fill: false, tension: 0.4 },
{ label: '15m', data: [], borderColor: '#10b981', borderWidth: 2, fill: false, tension: 0 } { label: '15m', data: [], borderColor: '#10b981', borderWidth: 2, fill: false, tension: 0.4 }
] ]
}, },
options: { options: {
@@ -624,17 +626,14 @@
console.log('Charts initialized successfully.'); console.log('Charts initialized successfully.');
} }
// Update UI with data
function updateUI(data) { function updateUI(data) {
if (!data) { if (!data) {
console.error('Received empty WebSocket data.'); console.error('Received empty WebSocket data.');
return; return;
} }
// Log full payload for debugging
console.debug('Received WebSocket payload:', JSON.stringify(data, null, 2)); console.debug('Received WebSocket payload:', JSON.stringify(data, null, 2));
// Initialize defaults for missing data
if (!data.docker) { if (!data.docker) {
console.warn('Missing docker data.'); console.warn('Missing docker data.');
data.docker = {}; data.docker = {};
@@ -648,7 +647,6 @@
data.jumpNode = { cpu: [], ram: [], net: [], disk: [], anomaly: [], disk_space: [], uptime: [], load: [] }; data.jumpNode = { cpu: [], ram: [], net: [], disk: [], anomaly: [], disk_space: [], uptime: [], load: [] };
} }
// Show/hide no-data message for Jump Node
const jumpNoData = document.getElementById('jump-no-data'); const jumpNoData = document.getElementById('jump-no-data');
const hasJumpData = data.jumpNode && ( const hasJumpData = data.jumpNode && (
(data.jumpNode.cpu && data.jumpNode.cpu.length > 0) || (data.jumpNode.cpu && data.jumpNode.cpu.length > 0) ||
@@ -662,32 +660,27 @@
); );
jumpNoData.style.display = hasJumpData ? 'none' : 'block'; jumpNoData.style.display = hasJumpData ? 'none' : 'block';
// Update Docker stats
document.getElementById('total-containers').textContent = data.docker.totalContainers || 0; document.getElementById('total-containers').textContent = data.docker.totalContainers || 0;
document.getElementById('running-containers').textContent = data.docker.runningContainers || 0; document.getElementById('running-containers').textContent = data.docker.runningContainers || 0;
document.getElementById('total-cpu').textContent = `${data.docker.totalCpu || 0}%`; document.getElementById('total-cpu').textContent = `${data.docker.totalCpu || 0}%`;
document.getElementById('total-ram').textContent = `${data.docker.totalMemory || 0} GB`; document.getElementById('total-ram').textContent = `${data.docker.totalMemory || 0} GB`;
document.getElementById('holesail-processes').textContent = data.holesailProcessCount || 0; document.getElementById('holesail-processes').textContent = data.holesailProcessCount || 0;
// Update Disk Usage and Free Disk
const diskSpaceData = data.netdata.disk_space || []; const diskSpaceData = data.netdata.disk_space || [];
const latestDiskSpace = diskSpaceData.length > 0 ? diskSpaceData[diskSpaceData.length - 1] : null; const latestDiskSpace = diskSpaceData.length > 0 ? diskSpaceData[diskSpaceData.length - 1] : null;
document.getElementById('disk-usage').textContent = latestDiskSpace ? `${latestDiskSpace.used.toFixed(2)} GB` : '0 GB'; document.getElementById('disk-usage').textContent = latestDiskSpace ? `${latestDiskSpace.used.toFixed(2)} GB` : '0 GB';
document.getElementById('free-disk').textContent = latestDiskSpace ? `${latestDiskSpace.avail.toFixed(2)} GB` : '0 GB'; document.getElementById('free-disk').textContent = latestDiskSpace ? `${latestDiskSpace.avail.toFixed(2)} GB` : '0 GB';
// Update AI Fault Monitor Count
const anomalyData = data.netdata.anomaly || []; const anomalyData = data.netdata.anomaly || [];
const latestAnomaly = anomalyData.length > 0 ? anomalyData[anomalyData.length - 1] : null; const latestAnomaly = anomalyData.length > 0 ? anomalyData[anomalyData.length - 1] : null;
document.getElementById('ai-fault-count').textContent = latestAnomaly ? `${latestAnomaly.anomalous}` : '0'; document.getElementById('ai-fault-count').textContent = latestAnomaly ? `${latestAnomaly.anomalous}` : '0';
// Update Host Load Averages
const loadData = data.netdata.load || []; const loadData = data.netdata.load || [];
const latestLoad = loadData.length > 0 ? loadData[loadData.length - 1] : null; const latestLoad = loadData.length > 0 ? loadData[loadData.length - 1] : null;
document.getElementById('host-load1').textContent = latestLoad ? latestLoad.load1.toFixed(2) : '0'; document.getElementById('host-load1').textContent = latestLoad ? latestLoad.load1.toFixed(2) : '0';
document.getElementById('host-load5').textContent = latestLoad ? latestLoad.load5.toFixed(2) : '0'; document.getElementById('host-load5').textContent = latestLoad ? latestLoad.load5.toFixed(2) : '0';
document.getElementById('host-load15').textContent = latestLoad ? latestLoad.load15.toFixed(2) : '0'; document.getElementById('host-load15').textContent = latestLoad ? latestLoad.load15.toFixed(2) : '0';
// Update Jump Node stats
const jumpDiskSpaceData = data.jumpNode.disk_space || []; const jumpDiskSpaceData = data.jumpNode.disk_space || [];
const latestJumpDiskSpace = jumpDiskSpaceData.length > 0 ? jumpDiskSpaceData[jumpDiskSpaceData.length - 1] : null; const latestJumpDiskSpace = jumpDiskSpaceData.length > 0 ? jumpDiskSpaceData[jumpDiskSpaceData.length - 1] : null;
document.getElementById('jump-disk-usage').textContent = latestJumpDiskSpace ? `${latestJumpDiskSpace.used.toFixed(2)} GB` : '0 GB'; document.getElementById('jump-disk-usage').textContent = latestJumpDiskSpace ? `${latestJumpDiskSpace.used.toFixed(2)} GB` : '0 GB';
@@ -701,14 +694,12 @@
const latestJumpUptime = jumpUptimeData.length > 0 ? jumpUptimeData[jumpUptimeData.length - 1] : null; const latestJumpUptime = jumpUptimeData.length > 0 ? jumpUptimeData[jumpUptimeData.length - 1] : null;
document.getElementById('jump-uptime').textContent = latestJumpUptime ? formatUptime(latestJumpUptime.uptime) : '0 days'; document.getElementById('jump-uptime').textContent = latestJumpUptime ? formatUptime(latestJumpUptime.uptime) : '0 days';
// Update Jump Load Averages
const jumpLoadData = data.jumpNode.load || []; const jumpLoadData = data.jumpNode.load || [];
const latestJumpLoad = jumpLoadData.length > 0 ? jumpLoadData[jumpLoadData.length - 1] : null; const latestJumpLoad = jumpLoadData.length > 0 ? jumpLoadData[jumpLoadData.length - 1] : null;
document.getElementById('jump-load1').textContent = latestJumpLoad ? latestJumpLoad.load1.toFixed(2) : '0'; document.getElementById('jump-load1').textContent = latestJumpLoad ? latestJumpLoad.load1.toFixed(2) : '0';
document.getElementById('jump-load5').textContent = latestJumpLoad ? latestJumpLoad.load5.toFixed(2) : '0'; document.getElementById('jump-load5').textContent = latestJumpLoad ? latestJumpLoad.load5.toFixed(2) : '0';
document.getElementById('jump-load15').textContent = latestJumpLoad ? latestJumpLoad.load15.toFixed(2) : '0'; document.getElementById('jump-load15').textContent = latestJumpLoad ? latestJumpLoad.load15.toFixed(2) : '0';
// Update container tables
const cpuTable = document.getElementById('cpu-table'); const cpuTable = document.getElementById('cpu-table');
const memoryTable = document.getElementById('memory-table'); const memoryTable = document.getElementById('memory-table');
cpuTable.innerHTML = data.docker.sortedByCpu?.map(c => ` cpuTable.innerHTML = data.docker.sortedByCpu?.map(c => `
@@ -728,7 +719,6 @@
</tr> </tr>
`).join('') || ''; `).join('') || '';
// Update Docker network chart
if (data.docker.totalNetwork) { if (data.docker.totalNetwork) {
const networkData = { const networkData = {
time: data.docker.totalNetwork.time || Math.floor(Date.now() / 1000), time: data.docker.totalNetwork.time || Math.floor(Date.now() / 1000),
@@ -742,7 +732,6 @@
} }
} }
// Update Netdata network and disk history
if (data.netdata.net?.length) { if (data.netdata.net?.length) {
const latestNet = data.netdata.net[data.netdata.net.length - 1]; const latestNet = data.netdata.net[data.netdata.net.length - 1];
netHistory.push({ netHistory.push({
@@ -767,7 +756,6 @@
} }
} }
// Update Host Load history
if (data.netdata.load?.length) { if (data.netdata.load?.length) {
const latestLoad = data.netdata.load[data.netdata.load.length - 1]; const latestLoad = data.netdata.load[data.netdata.load.length - 1];
hostLoadHistory.push({ hostLoadHistory.push({
@@ -781,7 +769,6 @@
} }
} }
// Update Jump Node network, disk, ram, and load history
if (data.jumpNode.net?.length) { if (data.jumpNode.net?.length) {
const latestNet = data.jumpNode.net[data.jumpNode.net.length - 1]; const latestNet = data.jumpNode.net[data.jumpNode.net.length - 1];
jumpNetHistory.push({ jumpNetHistory.push({
@@ -839,9 +826,7 @@
console.debug('No jump node load data available.'); console.debug('No jump node load data available.');
} }
// Update charts with smoothing and dynamic units const defaultData = [];
const defaultLabels = Array(MAX_POINTS).fill(0).map((_, i) => i);
const defaultData = Array(MAX_POINTS).fill(0);
if (charts.dockerNet) { if (charts.dockerNet) {
const maxVal = Math.max(...dockerNetHistory.map(d => Math.max(d.in, d.out)), 1); const maxVal = Math.max(...dockerNetHistory.map(d => Math.max(d.in, d.out)), 1);
@@ -849,7 +834,7 @@
const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1; const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1;
const inData = smoothData(dockerNetHistory.map(d => d.in / scale), SMOOTHING_WINDOW); const inData = smoothData(dockerNetHistory.map(d => d.in / scale), SMOOTHING_WINDOW);
const outData = smoothData(dockerNetHistory.map(d => d.out / scale), SMOOTHING_WINDOW); const outData = smoothData(dockerNetHistory.map(d => d.out / scale), SMOOTHING_WINDOW);
charts.dockerNet.data.labels = dockerNetHistory.length ? dockerNetHistory.map((_, i) => i) : defaultLabels; charts.dockerNet.data.labels = dockerNetHistory.length ? dockerNetHistory.map(d => formatTime(d.time)) : [];
charts.dockerNet.data.datasets[0].data = inData.length ? inData : defaultData; charts.dockerNet.data.datasets[0].data = inData.length ? inData : defaultData;
charts.dockerNet.data.datasets[1].data = outData.length ? outData : defaultData; charts.dockerNet.data.datasets[1].data = outData.length ? outData : defaultData;
charts.dockerNet.options.scales.y.title.text = unitInfo.unit; charts.dockerNet.options.scales.y.title.text = unitInfo.unit;
@@ -859,7 +844,7 @@
if (charts.cpu) { if (charts.cpu) {
const userData = smoothData(data.netdata.cpu?.map(d => d.user) || [], SMOOTHING_WINDOW); const userData = smoothData(data.netdata.cpu?.map(d => d.user) || [], SMOOTHING_WINDOW);
const systemData = smoothData(data.netdata.cpu?.map(d => d.system) || [], SMOOTHING_WINDOW); const systemData = smoothData(data.netdata.cpu?.map(d => d.system) || [], SMOOTHING_WINDOW);
charts.cpu.data.labels = data.netdata.cpu?.length ? data.netdata.cpu.map((_, i) => i) : defaultLabels; charts.cpu.data.labels = data.netdata.cpu?.length ? data.netdata.cpu.map(d => formatTime(d.time)) : [];
charts.cpu.data.datasets[0].data = userData.length ? userData : defaultData; charts.cpu.data.datasets[0].data = userData.length ? userData : defaultData;
charts.cpu.data.datasets[1].data = systemData.length ? systemData : defaultData; charts.cpu.data.datasets[1].data = systemData.length ? systemData : defaultData;
charts.cpu.update(); charts.cpu.update();
@@ -868,7 +853,7 @@
if (charts.ram) { if (charts.ram) {
const usedData = smoothData(data.netdata.ram?.map(d => d.used) || [], SMOOTHING_WINDOW); const usedData = smoothData(data.netdata.ram?.map(d => d.used) || [], SMOOTHING_WINDOW);
const freeData = smoothData(data.netdata.ram?.map(d => d.free) || [], SMOOTHING_WINDOW); const freeData = smoothData(data.netdata.ram?.map(d => d.free) || [], SMOOTHING_WINDOW);
charts.ram.data.labels = data.netdata.ram?.length ? data.netdata.ram.map((_, i) => i) : defaultLabels; charts.ram.data.labels = data.netdata.ram?.length ? data.netdata.ram.map(d => formatTime(d.time)) : [];
charts.ram.data.datasets[0].data = usedData.length ? usedData : defaultData; charts.ram.data.datasets[0].data = usedData.length ? usedData : defaultData;
charts.ram.data.datasets[1].data = freeData.length ? freeData : defaultData; charts.ram.data.datasets[1].data = freeData.length ? freeData : defaultData;
charts.ram.update(); charts.ram.update();
@@ -880,7 +865,7 @@
const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1; const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1;
const receivedData = smoothData(netHistory.map(d => d.received / scale), SMOOTHING_WINDOW); const receivedData = smoothData(netHistory.map(d => d.received / scale), SMOOTHING_WINDOW);
const sentData = smoothData(netHistory.map(d => d.sent / scale), SMOOTHING_WINDOW); const sentData = smoothData(netHistory.map(d => d.sent / scale), SMOOTHING_WINDOW);
charts.net.data.labels = netHistory.length ? netHistory.map((_, i) => i) : defaultLabels; charts.net.data.labels = netHistory.length ? netHistory.map(d => formatTime(d.time)) : [];
charts.net.data.datasets[0].data = receivedData.length ? receivedData : defaultData; charts.net.data.datasets[0].data = receivedData.length ? receivedData : defaultData;
charts.net.data.datasets[1].data = sentData.length ? sentData : defaultData; charts.net.data.datasets[1].data = sentData.length ? sentData : defaultData;
charts.net.options.scales.y.title.text = unitInfo.unit; charts.net.options.scales.y.title.text = unitInfo.unit;
@@ -893,7 +878,7 @@
const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1; const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1;
const inData = smoothData(diskHistory.map(d => d.in / scale), SMOOTHING_WINDOW); const inData = smoothData(diskHistory.map(d => d.in / scale), SMOOTHING_WINDOW);
const outData = smoothData(diskHistory.map(d => d.out / scale), SMOOTHING_WINDOW); const outData = smoothData(diskHistory.map(d => d.out / scale), SMOOTHING_WINDOW);
charts.disk.data.labels = diskHistory.length ? diskHistory.map((_, i) => i) : defaultLabels; charts.disk.data.labels = diskHistory.length ? diskHistory.map(d => formatTime(d.time)) : [];
charts.disk.data.datasets[0].data = inData.length ? inData : defaultData; charts.disk.data.datasets[0].data = inData.length ? inData : defaultData;
charts.disk.data.datasets[1].data = outData.length ? outData : defaultData; charts.disk.data.datasets[1].data = outData.length ? outData : defaultData;
charts.disk.options.scales.y.title.text = unitInfo.unit; charts.disk.options.scales.y.title.text = unitInfo.unit;
@@ -904,7 +889,7 @@
const load1Data = smoothData(hostLoadHistory.map(d => d.load1), SMOOTHING_WINDOW); const load1Data = smoothData(hostLoadHistory.map(d => d.load1), SMOOTHING_WINDOW);
const load5Data = smoothData(hostLoadHistory.map(d => d.load5), SMOOTHING_WINDOW); const load5Data = smoothData(hostLoadHistory.map(d => d.load5), SMOOTHING_WINDOW);
const load15Data = smoothData(hostLoadHistory.map(d => d.load15), SMOOTHING_WINDOW); const load15Data = smoothData(hostLoadHistory.map(d => d.load15), SMOOTHING_WINDOW);
charts.load.data.labels = hostLoadHistory.length ? hostLoadHistory.map((_, i) => i) : defaultLabels; charts.load.data.labels = hostLoadHistory.length ? hostLoadHistory.map(d => formatTime(d.time)) : [];
charts.load.data.datasets[0].data = load1Data.length ? load1Data : defaultData; charts.load.data.datasets[0].data = load1Data.length ? load1Data : defaultData;
charts.load.data.datasets[1].data = load5Data.length ? load5Data : defaultData; charts.load.data.datasets[1].data = load5Data.length ? load5Data : defaultData;
charts.load.data.datasets[2].data = load15Data.length ? load15Data : defaultData; charts.load.data.datasets[2].data = load15Data.length ? load15Data : defaultData;
@@ -914,23 +899,19 @@
if (charts.jumpCpu) { if (charts.jumpCpu) {
const userData = smoothData(data.jumpNode.cpu?.map(d => d.user) || [], SMOOTHING_WINDOW); const userData = smoothData(data.jumpNode.cpu?.map(d => d.user) || [], SMOOTHING_WINDOW);
const systemData = smoothData(data.jumpNode.cpu?.map(d => d.system) || [], SMOOTHING_WINDOW); const systemData = smoothData(data.jumpNode.cpu?.map(d => d.system) || [], SMOOTHING_WINDOW);
charts.jumpCpu.data.labels = data.jumpNode.cpu?.length ? data.jumpNode.cpu.map((_, i) => i) : defaultLabels; charts.jumpCpu.data.labels = data.jumpNode.cpu?.length ? data.jumpNode.cpu.map(d => formatTime(d.time)) : [];
charts.jumpCpu.data.datasets[0].data = userData.length ? userData : defaultData; charts.jumpCpu.data.datasets[0].data = userData.length ? userData : defaultData;
charts.jumpCpu.data.datasets[1].data = systemData.length ? systemData : defaultData; charts.jumpCpu.data.datasets[1].data = systemData.length ? systemData : defaultData;
charts.jumpCpu.update(); charts.jumpCpu.update();
} else {
console.debug('Jump CPU chart not initialized.');
} }
if (charts.jumpRam) { if (charts.jumpRam) {
const usedData = smoothData(jumpRamHistory.map(d => d.used) || [], SMOOTHING_WINDOW); const usedData = smoothData(jumpRamHistory.map(d => d.used) || [], SMOOTHING_WINDOW);
const freeData = smoothData(jumpRamHistory.map(d => d.free) || [], SMOOTHING_WINDOW); const freeData = smoothData(jumpRamHistory.map(d => d.free) || [], SMOOTHING_WINDOW);
charts.jumpRam.data.labels = jumpRamHistory.length ? jumpRamHistory.map((_, i) => i) : defaultLabels; charts.jumpRam.data.labels = jumpRamHistory.length ? jumpRamHistory.map(d => formatTime(d.time)) : [];
charts.jumpRam.data.datasets[0].data = usedData.length ? usedData : defaultData; charts.jumpRam.data.datasets[0].data = usedData.length ? usedData : defaultData;
charts.jumpRam.data.datasets[1].data = freeData.length ? freeData : defaultData; charts.jumpRam.data.datasets[1].data = freeData.length ? freeData : defaultData;
charts.jumpRam.update(); charts.jumpRam.update();
} else {
console.debug('Jump RAM chart not initialized.');
} }
if (charts.jumpNet) { if (charts.jumpNet) {
@@ -939,13 +920,11 @@
const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1; const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1;
const receivedData = smoothData(jumpNetHistory.map(d => d.received / scale), SMOOTHING_WINDOW); const receivedData = smoothData(jumpNetHistory.map(d => d.received / scale), SMOOTHING_WINDOW);
const sentData = smoothData(jumpNetHistory.map(d => d.sent / scale), SMOOTHING_WINDOW); const sentData = smoothData(jumpNetHistory.map(d => d.sent / scale), SMOOTHING_WINDOW);
charts.jumpNet.data.labels = jumpNetHistory.length ? jumpNetHistory.map((_, i) => i) : defaultLabels; charts.jumpNet.data.labels = jumpNetHistory.length ? jumpNetHistory.map(d => formatTime(d.time)) : [];
charts.jumpNet.data.datasets[0].data = receivedData.length ? receivedData : defaultData; charts.jumpNet.data.datasets[0].data = receivedData.length ? receivedData : defaultData;
charts.jumpNet.data.datasets[1].data = sentData.length ? sentData : defaultData; charts.jumpNet.data.datasets[1].data = sentData.length ? sentData : defaultData;
charts.jumpNet.options.scales.y.title.text = unitInfo.unit; charts.jumpNet.options.scales.y.title.text = unitInfo.unit;
charts.jumpNet.update(); charts.jumpNet.update();
} else {
console.debug('Jump Network chart not initialized.');
} }
if (charts.jumpDisk) { if (charts.jumpDisk) {
@@ -954,26 +933,22 @@
const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1; const scale = unitInfo.unit === 'GB/s' ? 1e9 : unitInfo.unit === 'MB/s' ? 1e6 : unitInfo.unit === 'KB/s' ? 1e3 : 1;
const inData = smoothData(jumpDiskHistory.map(d => d.in / scale), SMOOTHING_WINDOW); const inData = smoothData(jumpDiskHistory.map(d => d.in / scale), SMOOTHING_WINDOW);
const outData = smoothData(jumpDiskHistory.map(d => d.out / scale), SMOOTHING_WINDOW); const outData = smoothData(jumpDiskHistory.map(d => d.out / scale), SMOOTHING_WINDOW);
charts.jumpDisk.data.labels = jumpDiskHistory.length ? jumpDiskHistory.map((_, i) => i) : defaultLabels; charts.jumpDisk.data.labels = jumpDiskHistory.length ? jumpDiskHistory.map(d => formatTime(d.time)) : [];
charts.jumpDisk.data.datasets[0].data = inData.length ? inData : defaultData; charts.jumpDisk.data.datasets[0].data = inData.length ? inData : defaultData;
charts.jumpDisk.data.datasets[1].data = outData.length ? outData : defaultData; charts.jumpDisk.data.datasets[1].data = outData.length ? outData : defaultData;
charts.jumpDisk.options.scales.y.title.text = unitInfo.unit; charts.jumpDisk.options.scales.y.title.text = unitInfo.unit;
charts.jumpDisk.update(); charts.jumpDisk.update();
} else {
console.debug('Jump Disk chart not initialized.');
} }
if (charts.jumpLoad) { if (charts.jumpLoad) {
const load1Data = smoothData(jumpLoadHistory.map(d => d.load1), SMOOTHING_WINDOW); const load1Data = smoothData(jumpLoadHistory.map(d => d.load1), SMOOTHING_WINDOW);
const load5Data = smoothData(jumpLoadHistory.map(d => d.load5), SMOOTHING_WINDOW); const load5Data = smoothData(jumpLoadHistory.map(d => d.load5), SMOOTHING_WINDOW);
const load15Data = smoothData(jumpLoadHistory.map(d => d.load15), SMOOTHING_WINDOW); const load15Data = smoothData(jumpLoadHistory.map(d => d.load15), SMOOTHING_WINDOW);
charts.jumpLoad.data.labels = jumpLoadHistory.length ? jumpLoadHistory.map((_, i) => i) : defaultLabels; charts.jumpLoad.data.labels = jumpLoadHistory.length ? jumpLoadHistory.map(d => formatTime(d.time)) : [];
charts.jumpLoad.data.datasets[0].data = load1Data.length ? load1Data : defaultData; charts.jumpLoad.data.datasets[0].data = load1Data.length ? load1Data : defaultData;
charts.jumpLoad.data.datasets[1].data = load5Data.length ? load5Data : defaultData; charts.jumpLoad.data.datasets[1].data = load5Data.length ? load5Data : defaultData;
charts.jumpLoad.data.datasets[2].data = load15Data.length ? load15Data : defaultData; charts.jumpLoad.data.datasets[2].data = load15Data.length ? load15Data : defaultData;
charts.jumpLoad.update(); charts.jumpLoad.update();
} else {
console.debug('Jump Load chart not initialized.');
} }
} }
+1 -1
View File
@@ -322,6 +322,6 @@ wss.on('connection', (ws) => {
}); });
}); });
server.listen(process.env.PORT, () => { server.listen(process.env.PORT, "0.0.0.0", () => {
console.log(`Server running on http://localhost:${process.env.PORT}`); console.log(`Server running on http://localhost:${process.env.PORT}`);
}); });