Skip to content

Commit d492ff8

Browse files
authored
Fix/monitoring (#1270)
* refactor: make request to dokploy server to proxy requests * refactor: lint * refactor: use dokploy/monitoring tag image
1 parent 74a0f5e commit d492ff8

File tree

12 files changed

+212
-168
lines changed

12 files changed

+212
-168
lines changed

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,5 +98,5 @@ jobs:
9898
file: ./Dockerfile.monitoring
9999
push: true
100100
tags: |
101-
siumauricio/monitoring:${{ github.ref_name == 'main' && 'latest' || 'canary' }}
101+
dokploy/monitoring:${{ github.ref_name == 'main' && 'latest' || 'canary' }}
102102
platforms: linux/amd64

apps/dokploy/components/dashboard/monitoring/paid/container/show-paid-container-monitoring.tsx

Lines changed: 35 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
SelectTrigger,
77
SelectValue,
88
} from "@/components/ui/select";
9+
import { api } from "@/utils/api";
910
import { Cpu, HardDrive, Loader2, MemoryStick, Network } from "lucide-react";
1011
import { useEffect, useState } from "react";
1112
import { ContainerBlockChart } from "./container-block-chart";
@@ -70,84 +71,36 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
7071
const [metrics, setMetrics] = useState<ContainerMetric>(
7172
{} as ContainerMetric,
7273
);
73-
const [isLoading, setIsLoading] = useState(true);
74-
const [error, setError] = useState<string | null>(null);
7574
const [dataPoints, setDataPoints] =
7675
useState<keyof typeof DATA_POINTS_OPTIONS>("50");
7776
const [refreshInterval, setRefreshInterval] = useState<string>("5000");
7877

79-
const fetchMetrics = async () => {
80-
try {
81-
const url = new URL(`${baseUrl}/metrics/containers`);
82-
83-
// if (dataPoints !== "all") {
84-
url.searchParams.append("limit", dataPoints);
85-
// }
86-
87-
if (!appName) {
88-
throw new Error(
89-
[
90-
"No Application Selected:",
91-
"",
92-
"Make Sure to select an application to monitor.",
93-
].join("\n"),
94-
);
95-
}
96-
97-
url.searchParams.append("appName", appName);
98-
99-
const response = await fetch(url.toString(), {
100-
headers: {
101-
Authorization: `Bearer ${token}`,
102-
},
103-
});
104-
105-
if (!response.ok) {
106-
throw new Error(
107-
`Error ${response.status}: ${response.statusText}. Please verify that the application "${appName}" is running and this service is included in the monitoring configuration.`,
108-
);
109-
}
110-
111-
const data = await response.json();
112-
if (!Array.isArray(data) || data.length === 0) {
113-
throw new Error(
114-
[
115-
`No monitoring data available for "${appName}". This could be because:`,
116-
"",
117-
"1. The container was recently started - wait a few minutes for data to be collected",
118-
"2. The container is not running - verify its status",
119-
"3. The service is not included in your monitoring configuration",
120-
].join("\n"),
121-
);
122-
}
123-
124-
setHistoricalData(data);
125-
setMetrics(data[data.length - 1]);
126-
setError(null);
127-
} catch (err) {
128-
setError(
129-
err instanceof Error
130-
? err.message
131-
: "Failed to fetch metrics, Please check your monitoring Instance is Configured correctly.",
132-
);
133-
} finally {
134-
setIsLoading(false);
135-
}
136-
};
78+
const {
79+
data,
80+
isLoading,
81+
error: queryError,
82+
} = api.admin.getContainerMetrics.useQuery(
83+
{
84+
url: baseUrl,
85+
token,
86+
dataPoints,
87+
appName,
88+
},
89+
{
90+
refetchInterval:
91+
dataPoints === "all" ? undefined : Number.parseInt(refreshInterval),
92+
enabled: !!appName,
93+
},
94+
);
13795

13896
useEffect(() => {
139-
fetchMetrics();
140-
141-
if (dataPoints === "all") {
142-
return;
143-
}
144-
145-
const interval = setInterval(() => {
146-
fetchMetrics();
147-
}, Number(refreshInterval));
97+
if (!data) return;
14898

149-
return () => clearInterval(interval);
150-
}, [dataPoints, appName, token, refreshInterval]);
99+
// @ts-ignore
100+
setHistoricalData(data);
101+
// @ts-ignore
102+
setMetrics(data[data.length - 1]);
103+
}, [data]);
151104

152105
if (isLoading) {
153106
return (
@@ -157,7 +110,7 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
157110
);
158111
}
159112

160-
if (error) {
113+
if (queryError) {
161114
return (
162115
<div className="mt-5 flex min-h-[55vh] w-full items-center justify-center p-4">
163116
<div className="max-w-xl text-center">
@@ -166,7 +119,9 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
166119
<strong className="text-primary">{appName}</strong>
167120
</p>
168121
<p className="whitespace-pre-line text-sm text-destructive">
169-
{error}
122+
{queryError instanceof Error
123+
? queryError.message
124+
: "Failed to fetch metrics, Please check your monitoring Instance is Configured correctly."}
170125
</p>
171126
<p className=" text-sm text-muted-foreground">URL: {baseUrl}</p>
172127
</div>
@@ -238,11 +193,11 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
238193
<h3 className="text-sm font-medium">Memory Usage</h3>
239194
</div>
240195
<p className="mt-2 text-2xl font-bold">
241-
{metrics.Memory.percentage}%
196+
{metrics?.Memory?.percentage}%
242197
</p>
243198
<p className="mt-1 text-sm text-muted-foreground">
244-
{metrics.Memory.used} {metrics.Memory.unit} / {metrics.Memory.total}{" "}
245-
{metrics.Memory.unit}
199+
{metrics?.Memory?.used} {metrics?.Memory?.unit} /{" "}
200+
{metrics?.Memory?.total} {metrics?.Memory?.unit}
246201
</p>
247202
</Card>
248203

@@ -252,8 +207,8 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
252207
<h3 className="text-sm font-medium">Network I/O</h3>
253208
</div>
254209
<p className="mt-2 text-2xl font-bold">
255-
{metrics.Network.input} {metrics.Network.inputUnit} /{" "}
256-
{metrics.Network.output} {metrics.Network.outputUnit}
210+
{metrics?.Network?.input} {metrics?.Network?.inputUnit} /{" "}
211+
{metrics?.Network?.output} {metrics?.Network?.outputUnit}
257212
</p>
258213
</Card>
259214

@@ -263,8 +218,8 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
263218
<h3 className="text-sm font-medium">Block I/O</h3>
264219
</div>
265220
<p className="mt-2 text-2xl font-bold">
266-
{metrics.BlockIO.read} {metrics.BlockIO.readUnit} /{" "}
267-
{metrics.BlockIO.write} {metrics.BlockIO.writeUnit}
221+
{metrics?.BlockIO?.read} {metrics?.BlockIO?.readUnit} /{" "}
222+
{metrics?.BlockIO?.write} {metrics?.BlockIO?.writeUnit}
268223
</p>
269224
</Card>
270225
</div>

apps/dokploy/components/dashboard/monitoring/paid/servers/show-paid-monitoring.tsx

Lines changed: 48 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
SelectTrigger,
66
SelectValue,
77
} from "@/components/ui/select";
8+
import { api } from "@/utils/api";
89
import { Clock, Cpu, HardDrive, Loader2, MemoryStick } from "lucide-react";
910
import type React from "react";
1011
import { useEffect, useState } from "react";
@@ -64,76 +65,56 @@ export const ShowPaidMonitoring = ({
6465
}: Props) => {
6566
const [historicalData, setHistoricalData] = useState<SystemMetrics[]>([]);
6667
const [metrics, setMetrics] = useState<SystemMetrics>({} as SystemMetrics);
67-
const [isLoading, setIsLoading] = useState(true);
68-
const [error, setError] = useState<string | null>(null);
6968
const [dataPoints, setDataPoints] =
7069
useState<keyof typeof DATA_POINTS_OPTIONS>("50");
7170
const [refreshInterval, setRefreshInterval] = useState<string>("5000");
7271

73-
const fetchMetrics = async () => {
74-
try {
75-
const url = new URL(BASE_URL);
76-
url.searchParams.append("limit", dataPoints);
77-
const response = await fetch(url.toString(), {
78-
headers: {
79-
Authorization: `Bearer ${token}`,
80-
},
81-
});
72+
const {
73+
data,
74+
isLoading,
75+
error: queryError,
76+
} = api.admin.getServerMetrics.useQuery(
77+
{
78+
url: BASE_URL,
79+
token,
80+
dataPoints,
81+
},
82+
{
83+
refetchInterval:
84+
dataPoints === "all" ? undefined : Number.parseInt(refreshInterval),
85+
enabled: true,
86+
},
87+
);
8288

83-
if (!response.ok) {
84-
throw new Error(
85-
`Error ${response.status}: ${response.statusText}. Ensure the container is running and this service is included in the monitoring configuration.`,
86-
);
87-
}
89+
useEffect(() => {
90+
if (!data) return;
8891

89-
const data = await response.json();
90-
if (!Array.isArray(data) || data.length === 0) {
91-
throw new Error(
92-
[
93-
"No monitoring data available. This could be because:",
94-
"",
95-
"1. You don't have setup the monitoring service, you can do in web server section.",
96-
"2. If you already have setup the monitoring service, wait a few minutes and refresh the page.",
97-
].join("\n"),
98-
);
99-
}
92+
const formattedData = data.map((metric: SystemMetrics) => ({
93+
timestamp: metric.timestamp,
94+
cpu: Number.parseFloat(metric.cpu),
95+
cpuModel: metric.cpuModel,
96+
cpuCores: metric.cpuCores,
97+
cpuPhysicalCores: metric.cpuPhysicalCores,
98+
cpuSpeed: metric.cpuSpeed,
99+
os: metric.os,
100+
distro: metric.distro,
101+
kernel: metric.kernel,
102+
arch: metric.arch,
103+
memUsed: Number.parseFloat(metric.memUsed),
104+
memUsedGB: Number.parseFloat(metric.memUsedGB),
105+
memTotal: Number.parseFloat(metric.memTotal),
106+
networkIn: Number.parseFloat(metric.networkIn),
107+
networkOut: Number.parseFloat(metric.networkOut),
108+
diskUsed: Number.parseFloat(metric.diskUsed),
109+
totalDisk: Number.parseFloat(metric.totalDisk),
110+
uptime: metric.uptime,
111+
}));
100112

101-
const formattedData = data.map((metric: SystemMetrics) => ({
102-
timestamp: metric.timestamp,
103-
cpu: Number.parseFloat(metric.cpu),
104-
cpuModel: metric.cpuModel,
105-
cpuCores: metric.cpuCores,
106-
cpuPhysicalCores: metric.cpuPhysicalCores,
107-
cpuSpeed: metric.cpuSpeed,
108-
os: metric.os,
109-
distro: metric.distro,
110-
kernel: metric.kernel,
111-
arch: metric.arch,
112-
memUsed: Number.parseFloat(metric.memUsed),
113-
memUsedGB: Number.parseFloat(metric.memUsedGB),
114-
memTotal: Number.parseFloat(metric.memTotal),
115-
networkIn: Number.parseFloat(metric.networkIn),
116-
networkOut: Number.parseFloat(metric.networkOut),
117-
diskUsed: Number.parseFloat(metric.diskUsed),
118-
totalDisk: Number.parseFloat(metric.totalDisk),
119-
uptime: metric.uptime,
120-
}));
121-
122-
// @ts-ignore
123-
setHistoricalData(formattedData);
124-
// @ts-ignore
125-
setMetrics(formattedData[formattedData.length - 1] || {});
126-
setError(null);
127-
} catch (err) {
128-
setError(
129-
err instanceof Error
130-
? err.message
131-
: "Failed to fetch metrics, Please check your monitoring Instance is Configured correctly.",
132-
);
133-
} finally {
134-
setIsLoading(false);
135-
}
136-
};
113+
// @ts-ignore
114+
setHistoricalData(formattedData);
115+
// @ts-ignore
116+
setMetrics(formattedData[formattedData.length - 1] || {});
117+
}, [data]);
137118

138119
const formatUptime = (seconds: number): string => {
139120
const days = Math.floor(seconds / (24 * 60 * 60));
@@ -143,20 +124,6 @@ export const ShowPaidMonitoring = ({
143124
return `${days}d ${hours}h ${minutes}m`;
144125
};
145126

146-
useEffect(() => {
147-
fetchMetrics();
148-
149-
if (dataPoints === "all") {
150-
return;
151-
}
152-
153-
const interval = setInterval(() => {
154-
fetchMetrics();
155-
}, Number(refreshInterval));
156-
157-
return () => clearInterval(interval);
158-
}, [dataPoints, token, refreshInterval]);
159-
160127
if (isLoading) {
161128
return (
162129
<div className="flex h-[400px] w-full items-center justify-center">
@@ -165,15 +132,17 @@ export const ShowPaidMonitoring = ({
165132
);
166133
}
167134

168-
if (error) {
135+
if (queryError) {
169136
return (
170137
<div className="flex min-h-[55vh] w-full items-center justify-center p-4">
171138
<div className="max-w-xl text-center">
172139
<p className="mb-2 text-base font-medium leading-none text-muted-foreground">
173140
Error fetching metrics{" "}
174141
</p>
175142
<p className="whitespace-pre-line text-sm text-destructive">
176-
{error}
143+
{queryError instanceof Error
144+
? queryError.message
145+
: "Failed to fetch metrics, Please check your monitoring Instance is Configured correctly."}
177146
</p>
178147
<p className=" text-sm text-muted-foreground">URL: {BASE_URL}</p>
179148
</div>

apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ export async function getServerSideProps(
399399
applicationId: params?.applicationId,
400400
});
401401

402+
await helpers.settings.isCloud.prefetch();
403+
402404
return {
403405
props: {
404406
trpcState: helpers.dehydrate(),

apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export async function getServerSideProps(
394394
await helpers.compose.one.fetch({
395395
composeId: params?.composeId,
396396
});
397-
397+
await helpers.settings.isCloud.prefetch();
398398
return {
399399
props: {
400400
trpcState: helpers.dehydrate(),

apps/dokploy/pages/dashboard/project/[projectId]/services/mariadb/[mariadbId].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ export async function getServerSideProps(
343343
await helpers.mariadb.one.fetch({
344344
mariadbId: params?.mariadbId,
345345
});
346-
346+
await helpers.settings.isCloud.prefetch();
347347
return {
348348
props: {
349349
trpcState: helpers.dehydrate(),

apps/dokploy/pages/dashboard/project/[projectId]/services/mongo/[mongoId].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ export async function getServerSideProps(
345345
await helpers.mongo.one.fetch({
346346
mongoId: params?.mongoId,
347347
});
348-
348+
await helpers.settings.isCloud.prefetch();
349349
return {
350350
props: {
351351
trpcState: helpers.dehydrate(),

apps/dokploy/pages/dashboard/project/[projectId]/services/mysql/[mysqlId].tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ export async function getServerSideProps(
350350
await helpers.mysql.one.fetch({
351351
mysqlId: params?.mysqlId,
352352
});
353-
353+
await helpers.settings.isCloud.prefetch();
354354
return {
355355
props: {
356356
trpcState: helpers.dehydrate(),

0 commit comments

Comments
 (0)