Fix/monitoring (#1271)

* refactor: make request to dokploy server to proxy requests

* refactor: lint

* refactor: use dokploy/monitoring tag image

* refactor: use canary in development or canary tags

* refactor: adjust logic

* refactor: update name
This commit is contained in:
Mauricio Siu
2025-02-02 19:51:19 -06:00
committed by GitHub
4 changed files with 124 additions and 91 deletions

View File

@@ -131,54 +131,59 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
return (
<>
<div className="flex items-center justify-between">
<div className="flex items-center justify-between flex-wrap gap-2">
<h2 className="text-2xl font-bold tracking-tight">
Container Monitoring
</h2>
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">Data points:</span>
<Select
value={dataPoints}
onValueChange={(value: keyof typeof DATA_POINTS_OPTIONS) =>
setDataPoints(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select points" />
</SelectTrigger>
<SelectContent>
{Object.entries(DATA_POINTS_OPTIONS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
<span className="text-sm text-muted-foreground">
Refresh interval:
</span>
<Select
value={refreshInterval}
onValueChange={(value: keyof typeof REFRESH_INTERVALS) =>
setRefreshInterval(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select interval" />
</SelectTrigger>
<SelectContent>
{Object.entries(REFRESH_INTERVALS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex items-center gap-4 flex-wrap">
<div>
<span className="text-sm text-muted-foreground">Data points:</span>
<Select
value={dataPoints}
onValueChange={(value: keyof typeof DATA_POINTS_OPTIONS) =>
setDataPoints(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select points" />
</SelectTrigger>
<SelectContent>
{Object.entries(DATA_POINTS_OPTIONS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<span className="text-sm text-muted-foreground">
Refresh interval:
</span>
<Select
value={refreshInterval}
onValueChange={(value: keyof typeof REFRESH_INTERVALS) =>
setRefreshInterval(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select interval" />
</SelectTrigger>
<SelectContent>
{Object.entries(REFRESH_INTERVALS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>
{/* Stats Cards */}
<div className="grid gap-4 md:grid-cols-4">
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
<Card className="p-6 bg-transparent">
<div className="flex items-center gap-2">
<Cpu className="h-4 w-4 text-muted-foreground" />
@@ -236,13 +241,13 @@ export const ContainerPaidMonitoring = ({ appName, baseUrl, token }: Props) => {
</div>
<div>
<h4 className="text-sm font-medium text-muted-foreground">Name</h4>
<p className="mt-1">{metrics.Name}</p>
<p className="mt-1 truncate">{metrics.Name}</p>
</div>
</div>
</Card>
{/* Charts Grid */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-2">
<div className="grid gap-4 grid-cols-1 md:grid-cols-1 xl:grid-cols-2">
<ContainerCPUChart data={historicalData} />
<ContainerMemoryChart data={historicalData} />
<ContainerBlockChart data={historicalData} />

View File

@@ -151,53 +151,58 @@ export const ShowPaidMonitoring = ({
}
return (
<div className="space-y-4 pt-5 pb-10 w-full px-4">
<div className="flex justify-between items-center">
<div className="space-y-4 pt-5 pb-10 w-full md:px-4">
<div className="flex items-center justify-between flex-wrap gap-2">
<h2 className="text-2xl font-bold tracking-tight">System Monitoring</h2>
<div className="flex items-center gap-2">
<span className="text-sm text-muted-foreground">Data points:</span>
<Select
value={dataPoints}
onValueChange={(value: keyof typeof DATA_POINTS_OPTIONS) =>
setDataPoints(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select points" />
</SelectTrigger>
<SelectContent>
{Object.entries(DATA_POINTS_OPTIONS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
<span className="text-sm text-muted-foreground">
Refresh interval:
</span>
<Select
value={refreshInterval}
onValueChange={(value: keyof typeof REFRESH_INTERVALS) =>
setRefreshInterval(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select interval" />
</SelectTrigger>
<SelectContent>
{Object.entries(REFRESH_INTERVALS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
<div className="flex items-center gap-4 flex-wrap">
<div>
<span className="text-sm text-muted-foreground">Data points:</span>
<Select
value={dataPoints}
onValueChange={(value: keyof typeof DATA_POINTS_OPTIONS) =>
setDataPoints(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select points" />
</SelectTrigger>
<SelectContent>
{Object.entries(DATA_POINTS_OPTIONS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<span className="text-sm text-muted-foreground">
Refresh interval:
</span>
<Select
value={refreshInterval}
onValueChange={(value: keyof typeof REFRESH_INTERVALS) =>
setRefreshInterval(value)
}
>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Select interval" />
</SelectTrigger>
<SelectContent>
{Object.entries(REFRESH_INTERVALS).map(([value, label]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
</div>
{/* Stats Cards */}
<div className="grid gap-4 md:grid-cols-4">
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 xl:grid-cols-4">
<div className="rounded-lg border text-card-foreground shadow-sm p-6">
<div className="flex items-center gap-2">
<Clock className="h-4 w-4 text-muted-foreground" />
@@ -260,7 +265,7 @@ export const ShowPaidMonitoring = ({
</div>
{/* Charts Grid */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-2">
<div className="grid gap-4 grid-cols-1 md:grid-cols-1 xl:grid-cols-2">
<CPUChart data={historicalData} />
<MemoryChart data={historicalData} />
<DiskChart data={metrics} />

View File

@@ -58,7 +58,11 @@ export const getContainers = async (serverId?: string | null) => {
serverId,
};
})
.filter((container) => !container.name.includes("dokploy"));
.filter(
(container) =>
!container.name.includes("dokploy") ||
container.name.includes("dokploy-monitoring"),
);
return containers;
} catch (error) {

View File

@@ -1,6 +1,8 @@
import { findServerById } from "@dokploy/server/services/server";
import type { ContainerCreateOptions } from "dockerode";
import { IS_CLOUD } from "../constants";
import { findAdminById } from "../services/admin";
import { getDokployImageTag } from "../services/settings";
import { pullImage, pullRemoteImage } from "../utils/docker/utils";
import { execAsync, execAsyncRemote } from "../utils/process/execAsync";
import { getRemoteDocker } from "../utils/servers/remote-docker";
@@ -8,8 +10,17 @@ import { getRemoteDocker } from "../utils/servers/remote-docker";
export const setupMonitoring = async (serverId: string) => {
const server = await findServerById(serverId);
const containerName = "mauricio-monitoring";
const imageName = "dokploy/monitoring:canary";
const containerName = "dokploy-monitoring";
let imageName = "dokploy/monitoring:latest";
if (
(getDokployImageTag() !== "latest" ||
process.env.NODE_ENV === "development") &&
!IS_CLOUD
) {
imageName = "dokploy/monitoring:canary";
}
const settings: ContainerCreateOptions = {
name: containerName,
@@ -73,8 +84,16 @@ export const setupMonitoring = async (serverId: string) => {
export const setupWebMonitoring = async (adminId: string) => {
const admin = await findAdminById(adminId);
const containerName = "mauricio-monitoring";
const imageName = "dokploy/monitoring:canary";
const containerName = "dokploy-monitoring";
let imageName = "dokploy/monitoring:latest";
if (
(getDokployImageTag() !== "latest" ||
process.env.NODE_ENV === "development") &&
!IS_CLOUD
) {
imageName = "dokploy/monitoring:canary";
}
const settings: ContainerCreateOptions = {
name: containerName,