mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-01-09 19:29:45 -06:00
Fixed the processing to be done in backend now.
This commit is contained in:
@@ -91,6 +91,49 @@ const getFormattedPercentage = (value) => {
|
||||
return `${(value * 100).toFixed(2)}%`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Custom tick component for rendering network bytes per second.
|
||||
*
|
||||
* @param {Object} props - The properties object.
|
||||
* @param {number} props.x - The x-coordinate for the tick.
|
||||
* @param {number} props.y - The y-coordinate for the tick.
|
||||
* @param {Object} props.payload - The payload object containing tick data.
|
||||
* @param {number} props.index - The index of the tick.
|
||||
* @returns {JSX.Element|null} The rendered tick component or null for the first tick.
|
||||
*/
|
||||
export const NetworkTick = ({ x, y, payload, index }) => {
|
||||
const theme = useTheme();
|
||||
if (index === 0) return null;
|
||||
|
||||
const formatBytes = (bytes) => {
|
||||
if (bytes >= 1_000_000_000) return `${(bytes / 1_000_000_000).toFixed(1)} GB/s`;
|
||||
if (bytes >= 1_000_000) return `${(bytes / 1_000_000).toFixed(1)} MB/s`;
|
||||
if (bytes >= 1_000) return `${(bytes / 1_000).toFixed(1)} KB/s`;
|
||||
return `${bytes} B/s`;
|
||||
};
|
||||
|
||||
return (
|
||||
<Text
|
||||
x={x - 20}
|
||||
y={y}
|
||||
textAnchor="middle"
|
||||
fill={theme.palette.primary.contrastTextTertiary}
|
||||
fontSize={11}
|
||||
fontWeight={400}
|
||||
>
|
||||
{formatBytes(payload?.value)}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
NetworkTick.propTypes = {
|
||||
x: PropTypes.number,
|
||||
y: PropTypes.number,
|
||||
payload: PropTypes.object,
|
||||
index: PropTypes.number,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Custom tooltip component for displaying infrastructure data.
|
||||
*
|
||||
|
||||
@@ -7,6 +7,7 @@ import InfraAreaChart from "../../../../../Pages/Infrastructure/Details/Componen
|
||||
import {
|
||||
TzTick,
|
||||
InfrastructureTooltip,
|
||||
NetworkTick,
|
||||
} from "../../../../../Components/Charts/Utils/chartUtils";
|
||||
import { useTheme } from "@emotion/react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -23,6 +24,7 @@ const NetworkCharts = ({ eth0Data, dateRange }) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
const configs = [
|
||||
{
|
||||
type: "network-bytes",
|
||||
@@ -33,6 +35,7 @@ const NetworkCharts = ({ eth0Data, dateRange }) => {
|
||||
gradientStartColor: theme.palette.info.main,
|
||||
yLabel: t("bytesPerSecond"),
|
||||
xTick: <TzTick dateRange={dateRange} />,
|
||||
yTick: <NetworkTick />,
|
||||
toolTip: (
|
||||
<InfrastructureTooltip
|
||||
dotColor={theme.palette.info.main}
|
||||
|
||||
@@ -4,23 +4,32 @@ import NetworkCharts from "./NetworkCharts";
|
||||
import MonitorTimeFrameHeader from "../../../../../Components/MonitorTimeFrameHeader";
|
||||
|
||||
const Network = ({ net, checks, isLoading, dateRange, setDateRange }) => {
|
||||
const eth0Data = getEth0TimeSeries(checks);
|
||||
const eth0Data = (checks || [])
|
||||
.map((check) => {
|
||||
const en0 = (check.net || []).find((iface) => iface.name === "en0");
|
||||
if (!en0) return null;
|
||||
|
||||
return {
|
||||
_id: check._id,
|
||||
bytesPerSec: en0.avgBytesRecv,
|
||||
packetsPerSec: en0.avgPacketsRecv,
|
||||
errors: (en0.avgErrOut ?? 0),
|
||||
drops: (en0.avgDropOut ?? 0)
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
|
||||
console.log(eth0Data);
|
||||
|
||||
return (
|
||||
<>
|
||||
<NetworkStatBoxes
|
||||
shouldRender={!isLoading}
|
||||
net={net}
|
||||
/>
|
||||
<NetworkStatBoxes shouldRender={!isLoading} net={net} />
|
||||
<MonitorTimeFrameHeader
|
||||
isLoading={isLoading}
|
||||
dateRange={dateRange}
|
||||
setDateRange={setDateRange}
|
||||
/>
|
||||
<NetworkCharts
|
||||
eth0Data={eth0Data}
|
||||
dateRange={dateRange}
|
||||
/>
|
||||
<NetworkCharts eth0Data={eth0Data} dateRange={dateRange} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -34,65 +43,3 @@ Network.propTypes = {
|
||||
};
|
||||
|
||||
export default Network;
|
||||
|
||||
/* ---------- Helper functions ---------- */
|
||||
function getEth0TimeSeries(checks) {
|
||||
const sorted = [...(checks || [])].sort((a, b) => new Date(a._id) - new Date(b._id));
|
||||
const series = [];
|
||||
let prev = null;
|
||||
|
||||
for (const check of sorted) {
|
||||
const eth = (check.net || []).find((iface) => iface.name === "en0");
|
||||
if (!eth) {
|
||||
prev = check;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (prev) {
|
||||
const prevEth = (prev.net || []).find((iface) => iface.name === "en0");
|
||||
const t1 = new Date(check._id);
|
||||
const t0 = new Date(prev._id);
|
||||
|
||||
if (!prevEth || isNaN(t1) || isNaN(t0)) {
|
||||
prev = check;
|
||||
continue;
|
||||
}
|
||||
|
||||
const dt = (t1 - t0) / 1000;
|
||||
|
||||
if (dt > 0) {
|
||||
const bytesField = eth.avgBytesSent;
|
||||
const prevBytesField = prevEth.avgBytesSent;
|
||||
|
||||
if (bytesField !== undefined && prevBytesField !== undefined) {
|
||||
const dataPoint = {
|
||||
_id: check._id,
|
||||
bytesPerSec: (bytesField - prevBytesField) / dt,
|
||||
packetsPerSec: (eth.avgPacketsSent - prevEth.avgPacketsSent) / dt,
|
||||
errors: (eth.avgErrIn ?? 0) + (eth.avgErrOut ?? 0),
|
||||
drops: 0,
|
||||
};
|
||||
series.push(dataPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
prev = check;
|
||||
}
|
||||
|
||||
// If we only have one check, create a single data point with absolute values
|
||||
if (series.length === 0 && sorted.length === 1) {
|
||||
const check = sorted[0];
|
||||
const eth = (check.net || []).find((iface) => iface.name === "en0");
|
||||
if (eth) {
|
||||
series.push({
|
||||
_id: check._id,
|
||||
bytesPerSec: eth.avgBytesSent || 0,
|
||||
packetsPerSec: eth.avgPacketsSent || 0,
|
||||
errors: (eth.avgErrIn ?? 0) + (eth.avgErrOut ?? 0),
|
||||
drops: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
@@ -326,10 +326,53 @@ class MonitorModule {
|
||||
}
|
||||
};
|
||||
|
||||
processNetworkRates = (checks) => {
|
||||
if (!Array.isArray(checks) || checks.length === 0) return [];
|
||||
|
||||
const sorted = [...checks].sort((a, b) => new Date(a._id) - new Date(b._id));
|
||||
const lastSeen = {};
|
||||
|
||||
for (const check of sorted) {
|
||||
if (!Array.isArray(check.net)) {
|
||||
check.net = [];
|
||||
continue;
|
||||
}
|
||||
|
||||
const newNet = [];
|
||||
|
||||
for (const iface of check.net) {
|
||||
const prev = lastSeen[iface.name];
|
||||
const t1 = new Date(check._id);
|
||||
|
||||
if (prev) {
|
||||
const t0 = new Date(prev._id);
|
||||
const dt = (t1 - t0) / 1000;
|
||||
|
||||
if (dt > 0) {
|
||||
newNet.push({
|
||||
name: iface.name,
|
||||
avgBytesRecv: (iface.avgBytesRecv - prev.avgBytesRecv),
|
||||
avgPacketsRecv: (iface.avgPacketsRecv - prev.avgPacketsRecv),
|
||||
avgErrOut: iface.avgErrOut - prev.avgErrOut,
|
||||
avgDropOut: iface.avgDropOut,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
lastSeen[iface.name] = { ...iface, _id: check._id };
|
||||
}
|
||||
|
||||
check.net = newNet;
|
||||
}
|
||||
|
||||
return sorted;
|
||||
};
|
||||
|
||||
getHardwareDetailsById = async ({ monitorId, dateRange }) => {
|
||||
try {
|
||||
const monitor = await this.Monitor.findById(monitorId);
|
||||
const dates = this.getDateRange(dateRange);
|
||||
|
||||
const formatLookup = {
|
||||
recent: "%Y-%m-%dT%H:%M:00Z",
|
||||
day: "%Y-%m-%dT%H:00:00Z",
|
||||
@@ -337,13 +380,19 @@ class MonitorModule {
|
||||
month: "%Y-%m-%dT00:00:00Z",
|
||||
};
|
||||
const dateString = formatLookup[dateRange];
|
||||
|
||||
const hardwareStats = await this.HardwareCheck.aggregate(buildHardwareDetailsPipeline(monitor, dates, dateString));
|
||||
|
||||
const monitorStats = {
|
||||
const stats = hardwareStats[0];
|
||||
if (stats && stats.checks) {
|
||||
// Replace net with per-second rates
|
||||
stats.checks = this.processNetworkRates(stats.checks);
|
||||
}
|
||||
|
||||
return {
|
||||
...monitor.toObject(),
|
||||
stats: hardwareStats[0],
|
||||
stats,
|
||||
};
|
||||
return monitorStats;
|
||||
} catch (error) {
|
||||
error.service = SERVICE_NAME;
|
||||
error.method = "getHardwareDetailsById";
|
||||
|
||||
@@ -393,7 +393,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
0,
|
||||
],
|
||||
},
|
||||
bytesSent: {
|
||||
avgBytesSent: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
@@ -404,7 +404,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
bytesRecv: {
|
||||
avgBytesRecv: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
@@ -415,7 +415,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
packetsSent: {
|
||||
avgPacketsSent: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
@@ -426,7 +426,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
packetsRecv: {
|
||||
avgPacketsRecv: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
@@ -437,7 +437,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
errIn: {
|
||||
avgErrIn: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
@@ -448,7 +448,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
errOut: {
|
||||
avgErrOut: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
@@ -459,6 +459,28 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
avgDropIn: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
as: "netArray",
|
||||
in: {
|
||||
$arrayElemAt: ["$$netArray.drop_in", "$$netIndex"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
avgDropOut: {
|
||||
$avg: {
|
||||
$map: {
|
||||
input: "$net",
|
||||
as: "netArray",
|
||||
in: {
|
||||
$arrayElemAt: ["$$netArray.drop_out", "$$netIndex"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user