feat: add 95th percentile line to network traffic graph in statistics

This commit is contained in:
2026-01-25 17:16:00 -05:00
parent ebfc5c84c9
commit 8aafc9814e

View File

@@ -340,6 +340,9 @@
This graph displays network traffic over time, showing both incoming (Network In) and outgoing (Network Out) data rates. It helps you monitor bandwidth utilization, identify network bottlenecks, and track data transfer patterns.
</p>
<div class="pt-4 mt-4 border-t border-neutral/30 space-y-2.5">
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">95th Percentile Line:</span> The dashed red line shows the 95th percentile of your combined network traffic. This is a common billing metric used by data centers - it means 95% of your traffic samples fall below this line. Understanding your 95th percentile helps predict bandwidth costs and capacity needs.
</p>
<p class="block font-sans text-xs font-normal leading-relaxed text-base/75">
<span class="font-semibold text-base/90">Time Range:</span> Select from Hour, Day, Week, Month, or Year to view network usage over different time periods.
</p>
@@ -4973,6 +4976,9 @@
}, {
name: 'Network Out',
data: []
}, {
name: '95th Percentile',
data: []
}],
yaxis: {
labels: {
@@ -4984,7 +4990,16 @@
},
}
},
colors: ['#a37443', '#dcce58'],
colors: ['#a37443', '#dcce58', '#ef4444'],
stroke: {
curve: 'smooth',
width: [2, 2, 2],
dashArray: [0, 0, 5]
},
fill: {
type: ['gradient', 'gradient', 'solid'],
opacity: [0.4, 0.4, 0]
},
});
var diskOptions = Object.assign({}, baseOptions, {
@@ -5311,6 +5326,18 @@
console.warn('No Network data received', eventData);
return;
}
// Calculate 95th percentile of combined network traffic
var allTrafficValues = data.map(function(item) {
return (item.netin || 0) + (item.netout || 0);
}).filter(function(v) { return v > 0; }).sort(function(a, b) { return a - b; });
var p95Value = 0;
if (allTrafficValues.length > 0) {
var p95Index = Math.floor(allTrafficValues.length * 0.95);
p95Value = allTrafficValues[Math.min(p95Index, allTrafficValues.length - 1)];
}
networkChart.updateSeries([{
name: 'Network In',
data: data.map(function(item) {
@@ -5327,6 +5354,14 @@
y: item.netout ? item.netout : 0,
}
})
}, {
name: '95th Percentile (' + formatBytes(p95Value) + ')',
data: data.map(function(item) {
return {
x: item.time * 1000,
y: p95Value,
}
})
}]);
// Mark that this chart has successfully received data
@@ -5709,16 +5744,18 @@
alert('No data available to export');
return;
}
var csv = 'Timestamp,Network In (bytes),Network Out (bytes)\n';
var csv = 'Timestamp,Network In (bytes),Network Out (bytes),95th Percentile (bytes)\n';
var inData = series[0].data;
var outData = series[1] ? series[1].data : [];
var maxLength = Math.max(inData.length, outData.length);
var p95Data = series[2] ? series[2].data : [];
var maxLength = Math.max(inData.length, outData.length, p95Data.length);
for (var i = 0; i < maxLength; i++) {
var timestamp = inData[i] ? new Date(inData[i].x).toISOString() :
(outData[i] ? new Date(outData[i].x).toISOString() : '');
var netIn = inData[i] && inData[i].y !== undefined ? inData[i].y : '0';
var netOut = outData[i] && outData[i].y !== undefined ? outData[i].y : '0';
csv += timestamp + ',' + netIn + ',' + netOut + '\n';
var p95 = p95Data[i] && p95Data[i].y !== undefined ? p95Data[i].y : '0';
csv += timestamp + ',' + netIn + ',' + netOut + ',' + p95 + '\n';
}
window.downloadCSV(csv, 'network-usage-' + new Date().toISOString().split('T')[0] + '.csv');
} catch (error) {