This commit is contained in:
2025-12-28 02:38:27 +01:00
parent b58d732764
commit 6f5906cf9b
3 changed files with 197 additions and 51 deletions
+103
View File
@@ -0,0 +1,103 @@
import { NextRequest, NextResponse } from "next/server";
import testAuth from "../auth";
import { StatusCodes } from "http-status-codes";
import si from "systeminformation";
function average<T>(values: Array<T>, p: (v: T) => number) {
return values.length > 0
? values.reduce((sum, value) => sum + p(value), 0) / values.length
: 0;
}
type Usage = {
cpu: number;
memory: number;
in: number;
out: number;
};
const usageSecs: Usage[] = [];
const usageMins: (Usage & { time: string })[] = [];
const usageHours: (Usage & { time: string })[] = new Array(12).fill({
time: "00:00",
cpu: 0,
memory: 0,
in: 0,
out: 0,
});
var hr = 0;
setInterval(async () => {
const [mem, load, network] = await Promise.all([
si.mem(),
si.currentLoad(),
si.networkStats(),
]);
usageSecs.push({
cpu: load.currentLoad,
memory: ((mem.total - mem.available) / mem.total) * 100,
in: average(network, (n) => n.rx_bytes),
out: average(network, (n) => n.tx_bytes),
});
if (usageSecs.length >= 60) {
const now = new Date();
const hours = String(now.getHours()).padStart(2, "0");
const minutes = String(now.getMinutes()).padStart(2, "0");
const time = `${hours}:${minutes}`;
usageMins.push({
time,
cpu: average(usageSecs, (s) => s.cpu),
memory: average(usageSecs, (s) => s.memory),
in: average(usageSecs, (s) => s.in),
out: average(usageSecs, (s) => s.out),
});
if (usageMins.length >= 60) {
if (hr >= 12) {
usageHours.shift();
usageHours.push({
time,
cpu: average(usageMins, (s) => s.cpu),
memory: average(usageMins, (s) => s.memory),
in: average(usageMins, (s) => s.in),
out: average(usageMins, (s) => s.out),
});
} else {
usageHours[hr] = {
time,
cpu: average(usageMins, (s) => s.cpu),
memory: average(usageMins, (s) => s.memory),
in: average(usageMins, (s) => s.in),
out: average(usageMins, (s) => s.out),
};
hr++;
}
usageMins.splice(0, usageSecs.length);
}
usageSecs.splice(0, usageSecs.length);
}
}, 1);
export async function GET(req: NextRequest): Promise<NextResponse> {
const auth = await testAuth(req);
if (auth) {
return NextResponse.json(
{ message: auth },
{ status: StatusCodes.UNAUTHORIZED }
);
}
return NextResponse.json({
message: "ok",
metrics: usageHours,
});
}
+27 -51
View File
@@ -5,54 +5,8 @@ import { Progress } from "@/components/ui/progress";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { type ChartConfig } from "@/components/ui/chart";
import GradientAreaChart from "@/components/GradientAreaChart";
const cpuData = [
{ time: "00:00", cpu: 45 },
{ time: "01:00", cpu: 52 },
{ time: "02:00", cpu: 38 },
{ time: "03:00", cpu: 42 },
{ time: "04:00", cpu: 35 },
{ time: "05:00", cpu: 48 },
{ time: "06:00", cpu: 55 },
{ time: "07:00", cpu: 62 },
{ time: "08:00", cpu: 78 },
{ time: "09:00", cpu: 85 },
{ time: "10:00", cpu: 72 },
{ time: "11:00", cpu: 68 },
{ time: "12:00", cpu: 75 },
];
const memoryData = [
{ time: "00:00", memory: 62 },
{ time: "01:00", memory: 64 },
{ time: "02:00", memory: 58 },
{ time: "03:00", memory: 61 },
{ time: "04:00", memory: 59 },
{ time: "05:00", memory: 63 },
{ time: "06:00", memory: 67 },
{ time: "07:00", memory: 72 },
{ time: "08:00", memory: 78 },
{ time: "09:00", memory: 82 },
{ time: "10:00", memory: 76 },
{ time: "11:00", memory: 74 },
{ time: "12:00", memory: 71 },
];
const networkData = [
{ time: "00:00", in: 12, out: 8 },
{ time: "01:00", in: 15, out: 10 },
{ time: "02:00", in: 8, out: 5 },
{ time: "03:00", in: 10, out: 7 },
{ time: "04:00", in: 6, out: 4 },
{ time: "05:00", in: 14, out: 9 },
{ time: "06:00", in: 22, out: 15 },
{ time: "07:00", in: 35, out: 28 },
{ time: "08:00", in: 48, out: 38 },
{ time: "09:00", in: 52, out: 42 },
{ time: "10:00", in: 45, out: 35 },
{ time: "11:00", in: 42, out: 32 },
{ time: "12:00", in: 38, out: 28 },
];
import { getMetrics } from "@/core/client/metrics";
import { useEffect, useState } from "react";
const containerMetrics = [
{ name: "api-gateway-1", cpu: 45, memory: 62, network: "12.4 MB/s" },
@@ -79,6 +33,28 @@ const networkChartConfig = {
} satisfies ChartConfig;
export default function MonitoringPage() {
const [data, setData] = useState<
{
time: string;
cpu: number;
memory: number;
in: number;
out: number;
}[]
>([]);
useEffect(() => {
async function fetchMetrics() {
setData(await getMetrics());
}
fetchMetrics();
const i = setInterval(fetchMetrics, 30000);
return () => clearInterval(i);
}, []);
return (
<DashboardLayout
title="Monitoring"
@@ -130,12 +106,12 @@ export default function MonitoringPage() {
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6">
<GradientAreaChart
title="CPU Usage"
data={cpuData}
data={data}
config={cpuChartConfig}
/>
<GradientAreaChart
title="Memory Usage"
data={memoryData}
data={data}
config={memoryChartConfig}
/>
</div>
@@ -143,7 +119,7 @@ export default function MonitoringPage() {
<div className="mb-6">
<GradientAreaChart
title="Network I/O"
data={networkData}
data={data}
config={networkChartConfig}
/>
</div>
+67
View File
@@ -0,0 +1,67 @@
"use server";
import { Node } from "@/lib/types";
import axios from "axios";
import { getNodes } from "./node";
export async function getMetrics(): Promise<
{
time: string;
cpu: number;
memory: number;
in: number;
out: number;
}[]
> {
const nodes = await getNodes();
const nodeMetrics = await Promise.all(nodes.map(getNodeMetrics));
if (nodeMetrics.length === 0) return [];
const numNodes = nodeMetrics.length;
const numPoints = nodeMetrics[0].length;
const averaged: (typeof nodeMetrics)[0] = [];
for (let i = 0; i < numPoints; i++) {
const sum = nodeMetrics.reduce(
(acc, metrics) => {
const m = metrics[i];
acc.cpu += m.cpu;
acc.memory += m.memory;
acc.in += m.in;
acc.out += m.out;
return acc;
},
{ cpu: 0, memory: 0, in: 0, out: 0 }
);
averaged.push({
time: nodeMetrics[0][i].time,
cpu: sum.cpu / numNodes,
memory: sum.memory / numNodes,
in: sum.in / numNodes,
out: sum.out / numNodes,
});
}
return averaged;
}
export async function getNodeMetrics(node: Node): Promise<
{
time: string;
cpu: number;
memory: number;
in: number;
out: number;
}[]
> {
const data = await (
await axios.get(`http://${node.ip}:3000/api/metrics`, {
headers: { Authorization: `ApiKey ${node.key}` },
})
).data;
return data.metrics;
}