mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
refactor: update docker stats
This commit is contained in:
@@ -90,9 +90,11 @@ const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`Read ${payload[0].payload.readMb.toFixed(2)} MB`}</p>
|
||||
<p>{`Write: ${payload[0].payload.writeMb.toFixed(3)} MB`}</p>
|
||||
{payload[0].payload.time && (
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
)}
|
||||
<p>{`Read ${payload[0].payload.readMb} `}</p>
|
||||
<p>{`Write: ${payload[0].payload.writeMb} `}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export const DockerCpuChart = ({ acummulativeData }: Props) => {
|
||||
return {
|
||||
name: `Point ${index + 1}`,
|
||||
time: item.time,
|
||||
usage: item.value.toFixed(2),
|
||||
usage: item.value.toString().split("%")[0],
|
||||
};
|
||||
});
|
||||
return (
|
||||
@@ -75,7 +75,9 @@ const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
{payload[0].payload.time && (
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
)}
|
||||
<p>{`CPU Usage: ${payload[0].payload.usage}%`}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
YAxis,
|
||||
} from "recharts";
|
||||
import type { DockerStatsJSON } from "./show";
|
||||
import { convertMemoryToBytes } from "./show";
|
||||
|
||||
interface Props {
|
||||
acummulativeData: DockerStatsJSON["memory"];
|
||||
@@ -23,7 +24,8 @@ export const DockerMemoryChart = ({
|
||||
return {
|
||||
time: item.time,
|
||||
name: `Point ${index + 1}`,
|
||||
usage: (item.value.used / 1024 ** 3).toFixed(2),
|
||||
// @ts-ignore
|
||||
usage: (convertMemoryToBytes(item.value.used) / 1024 ** 3).toFixed(2),
|
||||
};
|
||||
});
|
||||
return (
|
||||
@@ -75,10 +77,13 @@ interface CustomTooltipProps {
|
||||
}
|
||||
|
||||
const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
if (active && payload && payload.length && payload[0] && payload[0].payload) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
{payload[0].payload.time && (
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
)}
|
||||
|
||||
<p>{`Memory usage: ${payload[0].payload.usage} GB`}</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -19,8 +19,8 @@ export const DockerNetworkChart = ({ acummulativeData }: Props) => {
|
||||
return {
|
||||
time: item.time,
|
||||
name: `Point ${index + 1}`,
|
||||
inMB: item.value.inputMb.toFixed(2),
|
||||
outMB: item.value.outputMb.toFixed(2),
|
||||
inMB: item.value.inputMb,
|
||||
outMB: item.value.outputMb,
|
||||
};
|
||||
});
|
||||
return (
|
||||
@@ -86,9 +86,11 @@ const CustomTooltip = ({ active, payload }: CustomTooltipProps) => {
|
||||
if (active && payload && payload.length && payload[0]) {
|
||||
return (
|
||||
<div className="custom-tooltip bg-background p-2 shadow-lg rounded-md text-primary border">
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
<p>{`In MB Usage: ${payload[0].payload.inMB} MB`}</p>
|
||||
<p>{`Out MB Usage: ${payload[0].payload.outMB} MB`}</p>
|
||||
{payload[0].payload.time && (
|
||||
<p>{`Date: ${format(new Date(payload[0].payload.time), "PPpp")}`}</p>
|
||||
)}
|
||||
<p>{`In Usage: ${payload[0].payload.inMB} `}</p>
|
||||
<p>{`Out Usage: ${payload[0].payload.outMB} `}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ const defaultData = {
|
||||
memory: {
|
||||
value: {
|
||||
used: 0,
|
||||
free: 0,
|
||||
usedPercentage: 0,
|
||||
total: 0,
|
||||
},
|
||||
time: "",
|
||||
@@ -60,8 +58,6 @@ export interface DockerStats {
|
||||
memory: {
|
||||
value: {
|
||||
used: number;
|
||||
free: number;
|
||||
usedPercentage: number;
|
||||
total: number;
|
||||
};
|
||||
time: string;
|
||||
@@ -100,6 +96,30 @@ export type DockerStatsJSON = {
|
||||
disk: DockerStats["disk"][];
|
||||
};
|
||||
|
||||
export const convertMemoryToBytes = (
|
||||
memoryString: string | undefined,
|
||||
): number => {
|
||||
if (!memoryString || typeof memoryString !== "string") {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const value = Number.parseFloat(memoryString) || 0;
|
||||
const unit = memoryString.replace(/[0-9.]/g, "").trim();
|
||||
|
||||
switch (unit) {
|
||||
case "KiB":
|
||||
return value * 1024;
|
||||
case "MiB":
|
||||
return value * 1024 * 1024;
|
||||
case "GiB":
|
||||
return value * 1024 * 1024 * 1024;
|
||||
case "TiB":
|
||||
return value * 1024 * 1024 * 1024 * 1024;
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
export const DockerMonitoring = ({
|
||||
appName,
|
||||
appType = "application",
|
||||
@@ -208,7 +228,7 @@ export const DockerMonitoring = ({
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Used: {currentData.cpu.value.toFixed(2)}%
|
||||
Used: {currentData.cpu.value}%
|
||||
</span>
|
||||
<Progress
|
||||
value={currentData.cpu.value}
|
||||
@@ -218,7 +238,6 @@ export const DockerMonitoring = ({
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-background">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">
|
||||
@@ -228,20 +247,26 @@ export const DockerMonitoring = ({
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`Used: ${(currentData.memory.value.used / 1024 ** 3).toFixed(2)} GB / Limit: ${(currentData.memory.value.total / 1024 ** 3).toFixed(2)} GB`}
|
||||
{`Used: ${currentData.memory.value.used} / Limit: ${currentData.memory.value.total} `}
|
||||
</span>
|
||||
<Progress
|
||||
value={currentData.memory.value.usedPercentage}
|
||||
value={
|
||||
(convertMemoryToBytes(currentData.memory.value.used) /
|
||||
convertMemoryToBytes(currentData.memory.value.total)) *
|
||||
100
|
||||
}
|
||||
className="w-[100%]"
|
||||
/>
|
||||
<DockerMemoryChart
|
||||
acummulativeData={acummulativeData.memory}
|
||||
memoryLimitGB={currentData.memory.value.total / 1024 ** 3}
|
||||
memoryLimitGB={
|
||||
convertMemoryToBytes(currentData.memory.value.total) /
|
||||
1024 ** 3
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{appName === "dokploy" && (
|
||||
<Card className="bg-background">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
@@ -274,17 +299,12 @@ export const DockerMonitoring = ({
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`Read: ${currentData.block.value.readMb.toFixed(
|
||||
2,
|
||||
)} MB / Write: ${currentData.block.value.writeMb.toFixed(
|
||||
3,
|
||||
)} MB`}
|
||||
{`Read: ${currentData.block.value.readMb} / Write: ${currentData.block.value.writeMb} `}
|
||||
</span>
|
||||
<DockerBlockChart acummulativeData={acummulativeData.block} />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-background">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium">
|
||||
@@ -294,11 +314,7 @@ export const DockerMonitoring = ({
|
||||
<CardContent>
|
||||
<div className="flex flex-col gap-2 w-full">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
{`In MB: ${currentData.network.value.inputMb.toFixed(
|
||||
2,
|
||||
)} MB / Out MB: ${currentData.network.value.outputMb.toFixed(
|
||||
2,
|
||||
)} MB`}
|
||||
{`In MB: ${currentData.network.value.inputMb} / Out MB: ${currentData.network.value.outputMb} `}
|
||||
</span>
|
||||
<DockerNetworkChart
|
||||
acummulativeData={acummulativeData.network}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type http from "node:http";
|
||||
import {
|
||||
docker,
|
||||
execAsync,
|
||||
getLastAdvancedStatsFile,
|
||||
recordAdvancedStats,
|
||||
validateWebSocketRequest,
|
||||
@@ -70,12 +71,16 @@ export const setupDockerStatsMonitoringSocketServer = (
|
||||
ws.close(4000, "Container not running");
|
||||
return;
|
||||
}
|
||||
const { stdout, stderr } = await execAsync(
|
||||
`docker stats ${container.Id} --no-stream --format \'{"BlockIO":"{{.BlockIO}}","CPUPerc":"{{.CPUPerc}}","Container":"{{.Container}}","ID":"{{.ID}}","MemPerc":"{{.MemPerc}}","MemUsage":"{{.MemUsage}}","Name":"{{.Name}}","NetIO":"{{.NetIO}}"}\'`,
|
||||
);
|
||||
if (stderr) {
|
||||
console.error("Docker stats error:", stderr);
|
||||
return;
|
||||
}
|
||||
const stat = JSON.parse(stdout);
|
||||
|
||||
const stats = await docker.getContainer(container.Id).stats({
|
||||
stream: false,
|
||||
});
|
||||
|
||||
await recordAdvancedStats(stats, appName);
|
||||
await recordAdvancedStats(stat, appName);
|
||||
const data = await getLastAdvancedStatsFile(appName);
|
||||
|
||||
ws.send(
|
||||
|
||||
Reference in New Issue
Block a user