Added delta instead of avg, and formatted the code to re-use already existing code.

This commit is contained in:
Owaise
2025-08-12 23:48:47 +05:30
parent 355a445ead
commit e27cc8a12b
7 changed files with 201 additions and 60 deletions

View File

@@ -101,16 +101,17 @@ const getFormattedPercentage = (value) => {
* @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 }) => {
export const NetworkTick = ({ x, y, payload, index, formatter}) => {
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`;
};
if (formatter === undefined) {
formatter = (value, space=false) => {
if (typeof value !== "number") return value;
// need to add space between value and unit
return `${(value / 1024).toFixed(2)}${space ? " " : ""}Kbps`;
};
}
return (
<Text
@@ -121,7 +122,7 @@ export const NetworkTick = ({ x, y, payload, index }) => {
fontSize={11}
fontWeight={400}
>
{formatBytes(payload?.value)}
{formatter(payload?.value, true)}
</Text>
);
};
@@ -131,6 +132,7 @@ NetworkTick.propTypes = {
y: PropTypes.number,
payload: PropTypes.object,
index: PropTypes.number,
formatter: PropTypes.func,
};
/**

View File

@@ -1,9 +1,7 @@
// NetworkCharts.jsx
import PropTypes from "prop-types";
import { Stack } from "@mui/material";
import { Stack, Typography } from "@mui/material";
import InfraAreaChart from "../../../../../Pages/Infrastructure/Details/Components/AreaChartBoxes/InfraAreaChart";
// Utils
import {
TzTick,
InfrastructureTooltip,
@@ -11,43 +9,42 @@ import {
} from "../../../../../Components/Charts/Utils/chartUtils";
import { useTheme } from "@emotion/react";
import { useTranslation } from "react-i18next";
import { useHardwareUtils } from "../../Hooks/useHardwareUtils";
const getFormattedNetworkMetric = (value) => {
if (typeof value !== "number" || isNaN(value)) return "0";
if (value >= 1024 ** 3) return `${(value / 1024 ** 3).toFixed(1)} GB/s`;
if (value >= 1024 ** 2) return `${(value / 1024 ** 2).toFixed(1)} MB/s`;
if (value >= 1024) return `${(value / 1024).toFixed(1)} KB/s`;
return `${Math.round(value)} B/s`;
};
const NetworkCharts = ({ eth0Data, dateRange }) => {
const NetworkCharts = ({ ethernetData, dateRange }) => {
const theme = useTheme();
const { t } = useTranslation();
const {formatBytesString} = useHardwareUtils();
if (!ethernetData?.length) {
return <Typography>{t("noNetworkStatsAvailable")}</Typography>;
}
const configs = [
{
type: "network-bytes",
data: eth0Data,
data: ethernetData,
dataKeys: ["bytesPerSec"],
heading: t("bytesPerSecond"),
strokeColor: theme.palette.info.main,
gradientStartColor: theme.palette.info.main,
yLabel: t("bytesPerSecond"),
xTick: <TzTick dateRange={dateRange} />,
yTick: <NetworkTick />,
yTick: <NetworkTick formatter={formatBytesString}/>,
toolTip: (
<InfrastructureTooltip
dotColor={theme.palette.info.main}
yKey={"bytesPerSec"}
yLabel={t("bytesPerSecond")}
dateRange={dateRange}
formatter={getFormattedNetworkMetric}
formatter={formatBytesString}
/>
),
},
{
type: "network-packets",
data: eth0Data,
data: ethernetData,
dataKeys: ["packetsPerSec"],
heading: t("packetsPerSecond"),
strokeColor: theme.palette.success.main,
@@ -66,7 +63,7 @@ const NetworkCharts = ({ eth0Data, dateRange }) => {
},
{
type: "network-errors",
data: eth0Data,
data: ethernetData,
dataKeys: ["errors"],
heading: t("errors"),
strokeColor: theme.palette.error.main,
@@ -85,7 +82,7 @@ const NetworkCharts = ({ eth0Data, dateRange }) => {
},
{
type: "network-drops",
data: eth0Data,
data: ethernetData,
dataKeys: ["drops"],
heading: t("drops"),
strokeColor: theme.palette.warning.main,
@@ -127,7 +124,7 @@ const NetworkCharts = ({ eth0Data, dateRange }) => {
};
NetworkCharts.propTypes = {
eth0Data: PropTypes.array.isRequired,
ethernetData: PropTypes.array.isRequired,
dateRange: PropTypes.string.isRequired,
};

View File

@@ -1,27 +1,19 @@
// NetworkStatBoxes.jsx
import PropTypes from "prop-types";
import StatusBoxes from "../../../../../Components/StatusBoxes";
import StatBox from "../../../../../Components/StatBox";
import { Typography } from "@mui/material";
import { useTranslation } from "react-i18next";
import { useHardwareUtils } from "../../Hooks/useHardwareUtils";
function formatBytes(bytes) {
if (bytes === 0 || bytes == null) return "0 B";
const k = 1024;
const sizes = ["B", "KB", "MB", "GB", "TB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
}
// Format numbers with commas
function formatNumber(num) {
return num != null ? num.toLocaleString() : "0";
}
const NetworkStatBoxes = ({ shouldRender, net }) => {
const NetworkStatBoxes = ({ shouldRender, net, ifaceName }) => {
const { t } = useTranslation();
const filtered =
net?.filter((iface) => iface.name === "en0" || iface.name === "wlan0") || [];
const { formatBytes } = useHardwareUtils();
const filtered = net?.filter((iface) => iface.name === ifaceName) || [];
if (!net?.length) {
return <Typography>{t("noNetworkStatsAvailable")}</Typography>;
@@ -83,6 +75,7 @@ NetworkStatBoxes.propTypes = {
err_out: PropTypes.number,
})
),
ifaceName: PropTypes.string.isRequired,
};
export default NetworkStatBoxes;

View File

@@ -3,37 +3,40 @@ import NetworkStatBoxes from "./NetworkStatBoxes";
import NetworkCharts from "./NetworkCharts";
import MonitorTimeFrameHeader from "../../../../../Components/MonitorTimeFrameHeader";
const getNetworkInterfaceData = (checks) => {
const getInterfaceName = (net) => {
const interfaceNames = ["eth0", "Ethernet", "en0"];
const found = (net || []).find((iface) => interfaceNames.includes(iface.name));
return found ? found.name : null;
};
const getNetworkInterfaceData = (checks, ifaceName) => {
return (checks || [])
.map((check) => {
const networkInterface = (check.net || []).find((iface) =>
interfaceNames.includes(iface.name)
const networkInterface = (check.net || []).find(
(iface) => iface.name === ifaceName
);
if (!networkInterface) {
return null;
}
if (!networkInterface) return null;
return {
_id: check._id,
bytesPerSec: networkInterface.avgBytesRecv,
packetsPerSec: networkInterface.avgPacketsRecv,
errors: networkInterface.avgErrOut ?? 0,
drops: networkInterface.avgDropOut ?? 0,
bytesPerSec: networkInterface.deltaBytesRecv,
packetsPerSec: networkInterface.deltaPacketsRecv,
errors: networkInterface.deltaErrOut ?? 0,
drops: networkInterface.deltaDropOut ?? 0,
};
})
.filter(Boolean);
};
const Network = ({ net, checks, isLoading, dateRange, setDateRange }) => {
const eth0Data = getNetworkInterfaceData(checks);
const ifaceName = getInterfaceName(net);
const ethernetData = getNetworkInterfaceData(checks, ifaceName);
return (
<>
<NetworkStatBoxes
shouldRender={!isLoading}
net={net}
ifaceName={ifaceName}
/>
<MonitorTimeFrameHeader
isLoading={isLoading}
@@ -41,7 +44,7 @@ const Network = ({ net, checks, isLoading, dateRange, setDateRange }) => {
setDateRange={setDateRange}
/>
<NetworkCharts
eth0Data={eth0Data}
ethernetData={ethernetData}
dateRange={dateRange}
/>
</>

View File

@@ -57,7 +57,7 @@ const useHardwareUtils = () => {
if (GB >= 1) {
return (
<>
{Number(GB.toFixed(0))}
{Number(GB.toFixed(2))}
{space ? " " : ""}
<Typography component="span">{t("gb")}</Typography>
</>
@@ -65,7 +65,7 @@ const useHardwareUtils = () => {
} else {
return (
<>
{Number(MB.toFixed(0))}
{Number(MB.toFixed(2))}
{space ? " " : ""}
<Typography component="span">{t("mb")}</Typography>
</>
@@ -73,6 +73,26 @@ const useHardwareUtils = () => {
}
};
const formatBytesString = (bytes, space = false) => {
if (
bytes === undefined ||
bytes === null ||
typeof bytes !== "number" ||
bytes === 0
) {
return `0${space ? " " : ""}${t("gb")}`;
}
const GB = bytes / (1024 * 1024 * 1024);
const MB = bytes / (1024 * 1024);
if (GB >= 1) {
return `${Number(GB.toFixed(2))}${space ? " " : ""}${t("gb")}`;
} else {
return `${Number(MB.toFixed(2))}${space ? " " : ""}${t("mb")}`;
}
};
/**
* Converts a decimal value to a percentage
*
@@ -134,6 +154,7 @@ const useHardwareUtils = () => {
decimalToPercentage,
buildTemps,
getDimensions,
formatBytesString,
};
};

View File

@@ -343,6 +343,17 @@ class MonitorModule {
const stats = hardwareStats[0];
if (stats?.net?.length) {
const elapsedSeconds = (new Date(dates.end).getTime() - new Date(dates.start).getTime()) / 1000;
stats.net = stats.net.map((iface) => ({
...iface,
bytesSentPerSec: iface.deltaBytesSent / elapsedSeconds,
bytesRecvPerSec: iface.deltaBytesRecv / elapsedSeconds,
packetsSentPerSec: iface.deltaPacketsSent / elapsedSeconds,
packetsRecvPerSec: iface.deltaPacketsRecv / elapsedSeconds,
}));
}
return {
...monitor.toObject(),
stats,

View File

@@ -395,7 +395,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
"$$netIndex",
],
},
avgBytesSent: {
deltaBytesSent: {
$subtract: [
{
$arrayElemAt: [
@@ -417,7 +417,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
},
],
},
avgBytesRecv: {
deltaBytesRecv: {
$subtract: [
{
$arrayElemAt: [
@@ -439,7 +439,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
},
],
},
avgPacketsSent: {
deltaPacketsSent: {
$subtract: [
{
$arrayElemAt: [
@@ -461,7 +461,7 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
},
],
},
avgPacketsRecv: {
deltaPacketsRecv: {
$subtract: [
{
$arrayElemAt: [
@@ -483,6 +483,120 @@ const buildHardwareDetailsPipeline = (monitor, dates, dateString) => {
},
],
},
deltaErrIn: {
$subtract: [
{
$arrayElemAt: [
{
$map: {
input: { $arrayElemAt: ["$net", { $subtract: [{ $size: "$net" }, 1] }] },
as: "iface",
in: "$$iface.err_in",
},
},
"$$netIndex",
],
},
{
$arrayElemAt: [{ $map: { input: { $arrayElemAt: ["$net", 0] }, as: "iface", in: "$$iface.err_in" } }, "$$netIndex"],
},
],
},
deltaErrOut: {
$subtract: [
{
$arrayElemAt: [
{
$map: {
input: { $arrayElemAt: ["$net", { $subtract: [{ $size: "$net" }, 1] }] },
as: "iface",
in: "$$iface.err_out",
},
},
"$$netIndex",
],
},
{
$arrayElemAt: [{ $map: { input: { $arrayElemAt: ["$net", 0] }, as: "iface", in: "$$iface.err_out" } }, "$$netIndex"],
},
],
},
deltaDropIn: {
$subtract: [
{
$arrayElemAt: [
{
$map: {
input: { $arrayElemAt: ["$net", { $subtract: [{ $size: "$net" }, 1] }] },
as: "iface",
in: "$$iface.drop_in",
},
},
"$$netIndex",
],
},
{
$arrayElemAt: [{ $map: { input: { $arrayElemAt: ["$net", 0] }, as: "iface", in: "$$iface.drop_in" } }, "$$netIndex"],
},
],
},
deltaDropOut: {
$subtract: [
{
$arrayElemAt: [
{
$map: {
input: { $arrayElemAt: ["$net", { $subtract: [{ $size: "$net" }, 1] }] },
as: "iface",
in: "$$iface.drop_out",
},
},
"$$netIndex",
],
},
{
$arrayElemAt: [{ $map: { input: { $arrayElemAt: ["$net", 0] }, as: "iface", in: "$$iface.drop_out" } }, "$$netIndex"],
},
],
},
deltaFifoIn: {
$subtract: [
{
$arrayElemAt: [
{
$map: {
input: { $arrayElemAt: ["$net", { $subtract: [{ $size: "$net" }, 1] }] },
as: "iface",
in: "$$iface.fifo_in",
},
},
"$$netIndex",
],
},
{
$arrayElemAt: [{ $map: { input: { $arrayElemAt: ["$net", 0] }, as: "iface", in: "$$iface.fifo_in" } }, "$$netIndex"],
},
],
},
deltaFifoOut: {
$subtract: [
{
$arrayElemAt: [
{
$map: {
input: { $arrayElemAt: ["$net", { $subtract: [{ $size: "$net" }, 1] }] },
as: "iface",
in: "$$iface.fifo_out",
},
},
"$$netIndex",
],
},
{
$arrayElemAt: [{ $map: { input: { $arrayElemAt: ["$net", 0] }, as: "iface", in: "$$iface.fifo_out" } }, "$$netIndex"],
},
],
},
},
},
},