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

View File

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

View File

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

View File

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