Feat/monitoring (#1267) Cloud Version

* feat: add start monitoring remote servers

* reafctor: update

* refactor: update

* refactor: update

* refactor: update

* refactor: update

* refactor: update

* refactor: update

* refactor:

* refactor: add metrics

* feat: add disk monitoring

* refactor: translate to english

* refacotor: add stats

* refactor: remove color

* feat: add log server metrics

* refactor: remove unused deps

* refactor: add origin

* refactor: add logs

* refactor: update

* feat: add series monitoring

* refactor: add system monitoring

* feat: add benchmark to optimize data

* refactor: update fn

* refactor: remove comments

* refactor: update

* refactor: exclude items

* feat: add refresh rate

* feat: add monitoring remote servers

* refactor: update

* refactor: remove unsued volumes

* refactor: update monitoring

* refactor: add more presets

* feat: add container metrics

* feat: add docker monitoring

* refactor: update conversion

* refactor: remove unused code

* refactor: update

* refactor: add docker compose logs

* refactor: add docker cli

* refactor: add install curl

* refactor: add get update

* refactor: add monitoring remote servers

* refactor: add containers config

* feat: add container specification

* refactor: update path

* refactor: add server filter

* refactor: simplify logic

* fix: verify if file exist before get stats

* refactor: update

* refactor: remove unused deps

* test: add test for containers

* refactor: update

* refactor add memory collector

* refactor: update

* refactor: update

* refactor: update

* refactor: remove

* refactor: add memory

* refactor: add server memory usage

* refactor: change memory

* refactor: update

* refactor: update

* refactor: add container metrics

* refactor: comment code

* refactor: mount proc bind

* refactor: change interval with node cron

* refactor: remove opening file

* refactor: use streams

* refactor: remove unused ws

* refactor: disable live when is all

* refactor: add sqlite

* refactor: update

* feat: add golang benchmark

* refactor: update go

* refactor: update dockerfile

* refactor: update db

* refactor: add env

* refactor: separate logic

* refactor: split logic

* refactor: update logs

* refactor: update dockerfile

* refactor: hide .env

* refactor: update

* chore: hide ,.ebnv

* refactor: add end angle

* refactor: update

* refactor: update

* refactor: update

* refactor: update

* refactor: update

* refactor: update monitoring

* refactor: add mount db

* refactor: add metrics and url callback

* refactor: add middleware

* refactor: add threshold property

* feat: add memory and cpu threshold notification

* feat: send notifications to the server

* feat: add metrics for dokploy server

* refactor: add dokploy server to monitoring

* refactor: update methods

* refactor: add admin to useeffect

* refactor: stop monitoring containers if elements are 0

* refactor: cancel request if appName is empty

* refactor: reuse methods

* chore; add feat monitoring

* refactor: set base url

* refactor: adjust monitoring

* refactor: delete migrations

* feat: add columns

* fix: add missing flag

* refactor: add free metrics

* refactor: add paid monitoring

* refactor: update methods

* feat: improve ui

* feat: add container stats

* refactor: add all container metrics

* refactor: add color primary

* refactor: change default rate limiting refresher

* refactor: update retention days

* refactor: use json instead of individual properties

* refactor: lint

* refactor: pass json env

* refactor: update

* refactor: delete

* refactor: update

* refactor: fix types

* refactor: add retention days

* chore: add license

* refactor: create db

* refactor: update path

* refactor: update setup

* refactor: update

* refactor: create files

* refactor: update

* refactor: delete

* refactor: update

* refactor: update token metrics

* fix: typechecks

* refactor: setup web server

* refactor: update error handling and add monitoring

* refactor: add local storage save

* refactor: add spacing

* refactor: update

* refactor: upgrade drizzle

* refactor: delete

* refactor: uppgrade drizzle kit

* refactor: update search with jsonB

* chore: upgrade drizzle

* chore: update packages

* refactor: add missing type

* refactor: add serverType

* refactor: update url

* refactor: update

* refactor: update

* refactor: hide monitoring on self hosted

* refactor: update server

* refactor: update

* refactor: update

* refactor: pin node version
This commit is contained in:
Mauricio Siu
2025-02-02 14:08:06 -06:00
committed by GitHub
parent 8c69d2a085
commit 74a0f5e992
150 changed files with 36173 additions and 11538 deletions

View File

@@ -5,20 +5,29 @@ import {
apiFindOneToken,
apiRemoveUser,
apiUpdateAdmin,
apiUpdateWebServerMonitoring,
users,
} from "@/server/db/schema";
import {
IS_CLOUD,
createInvitation,
findAdminById,
findUserByAuthId,
findUserById,
getUserByToken,
removeUserByAuthId,
setupWebMonitoring,
updateAdmin,
updateAdminById,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import { eq } from "drizzle-orm";
import { adminProcedure, createTRPCRouter, publicProcedure } from "../trpc";
import {
adminProcedure,
createTRPCRouter,
protectedProcedure,
publicProcedure,
} from "../trpc";
export const adminRouter = createTRPCRouter({
one: adminProcedure.query(async ({ ctx }) => {
@@ -38,6 +47,7 @@ export const adminRouter = createTRPCRouter({
});
}
const { authId } = await findAdminById(ctx.user.adminId);
// @ts-ignore
return updateAdmin(authId, input);
}),
createUserInvitation: adminProcedure
@@ -102,4 +112,61 @@ export const adminRouter = createTRPCRouter({
throw error;
}
}),
setupMonitoring: adminProcedure
.input(apiUpdateWebServerMonitoring)
.mutation(async ({ input, ctx }) => {
try {
if (IS_CLOUD) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "Feature disabled on cloud",
});
}
const admin = await findAdminById(ctx.user.adminId);
if (admin.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to setup this server",
});
}
await updateAdminById(admin.adminId, {
metricsConfig: {
server: {
type: "Dokploy",
refreshRate: input.metricsConfig.server.refreshRate,
port: input.metricsConfig.server.port,
token: input.metricsConfig.server.token,
cronJob: input.metricsConfig.server.cronJob,
urlCallback: input.metricsConfig.server.urlCallback,
retentionDays: input.metricsConfig.server.retentionDays,
thresholds: {
cpu: input.metricsConfig.server.thresholds.cpu,
memory: input.metricsConfig.server.thresholds.memory,
},
},
containers: {
refreshRate: input.metricsConfig.containers.refreshRate,
services: {
include: input.metricsConfig.containers.services.include || [],
exclude: input.metricsConfig.containers.services.exclude || [],
},
},
},
});
const currentServer = await setupWebMonitoring(admin.adminId);
return currentServer;
} catch (error) {
throw error;
}
}),
getMetricsToken: protectedProcedure.query(async ({ ctx }) => {
const admin = await findAdminById(ctx.user.adminId);
return {
serverIp: admin.serverIp,
enabledFeatures: admin.enablePaidFeatures,
metricsConfig: admin?.metricsConfig,
};
}),
});

View File

@@ -6,6 +6,7 @@ import {
} from "@/server/api/trpc";
import { db } from "@/server/db";
import {
admins,
apiCreateDiscord,
apiCreateEmail,
apiCreateGotify,
@@ -23,6 +24,7 @@ import {
apiUpdateSlack,
apiUpdateTelegram,
notifications,
server,
} from "@/server/db/schema";
import {
IS_CLOUD,
@@ -36,6 +38,7 @@ import {
sendDiscordNotification,
sendEmailNotification,
sendGotifyNotification,
sendServerThresholdNotifications,
sendSlackNotification,
sendTelegramNotification,
updateDiscordNotification,
@@ -45,7 +48,8 @@ import {
updateTelegramNotification,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
import { desc, eq } from "drizzle-orm";
import { desc, eq, sql } from "drizzle-orm";
import { z } from "zod";
// TODO: Uncomment the validations when is cloud ready
export const notificationRouter = createTRPCRouter({
@@ -314,6 +318,70 @@ export const notificationRouter = createTRPCRouter({
// TODO: Remove this line when the cloud version is ready
});
}),
receiveNotification: publicProcedure
.input(
z.object({
ServerType: z.enum(["Dokploy", "Remote"]).default("Dokploy"),
Type: z.enum(["Memory", "CPU"]),
Value: z.number(),
Threshold: z.number(),
Message: z.string(),
Timestamp: z.string(),
Token: z.string(),
}),
)
.mutation(async ({ input }) => {
try {
let adminId = "";
let ServerName = "";
if (input.ServerType === "Dokploy") {
const result = await db
.select()
.from(admins)
.where(
sql`${admins.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
);
if (!result?.[0]?.adminId) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Token not found",
});
}
adminId = result?.[0]?.adminId;
ServerName = "Dokploy";
} else {
const result = await db
.select()
.from(server)
.where(
sql`${server.metricsConfig}::jsonb -> 'server' ->> 'token' = ${input.Token}`,
);
if (!result?.[0]?.adminId) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Token not found",
});
}
adminId = result?.[0]?.adminId;
ServerName = "Remote";
}
await sendServerThresholdNotifications(adminId, {
...input,
ServerName,
});
} catch (error) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "Error sending the notification",
cause: error,
});
}
}),
createGotify: adminProcedure
.input(apiCreateGotify)
.mutation(async ({ input, ctx }) => {

View File

@@ -197,6 +197,7 @@ export const projectRouter = createTRPCRouter({
orderBy: desc(projects.createdAt),
});
}),
remove: protectedProcedure
.input(apiRemoveProject)
.mutation(async ({ input, ctx }) => {

View File

@@ -6,6 +6,7 @@ import {
apiFindOneServer,
apiRemoveServer,
apiUpdateServer,
apiUpdateServerMonitoring,
applications,
compose,
mariadb,
@@ -29,6 +30,7 @@ import {
serverAudit,
serverSetup,
serverValidate,
setupMonitoring,
updateServerById,
} from "@dokploy/server";
import { TRPCError } from "@trpc/server";
@@ -247,6 +249,48 @@ export const serverRouter = createTRPCRouter({
});
}
}),
setupMonitoring: protectedProcedure
.input(apiUpdateServerMonitoring)
.mutation(async ({ input, ctx }) => {
try {
const server = await findServerById(input.serverId);
if (server.adminId !== ctx.user.adminId) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: "You are not authorized to setup this server",
});
}
await updateServerById(input.serverId, {
metricsConfig: {
server: {
type: "Remote",
refreshRate: input.metricsConfig.server.refreshRate,
retentionDays: input.metricsConfig.server.retentionDays,
port: input.metricsConfig.server.port,
token: input.metricsConfig.server.token,
urlCallback: input.metricsConfig.server.urlCallback,
cronJob: input.metricsConfig.server.cronJob,
thresholds: {
cpu: input.metricsConfig.server.thresholds.cpu,
memory: input.metricsConfig.server.thresholds.memory,
},
},
containers: {
refreshRate: input.metricsConfig.containers.refreshRate,
services: {
include: input.metricsConfig.containers.services.include || [],
exclude: input.metricsConfig.containers.services.exclude || [],
},
},
},
});
const currentServer = await setupMonitoring(input.serverId);
return currentServer;
} catch (error) {
throw error;
}
}),
remove: protectedProcedure
.input(apiRemoveServer)
.mutation(async ({ input, ctx }) => {