mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
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:
@@ -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,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -197,6 +197,7 @@ export const projectRouter = createTRPCRouter({
|
||||
orderBy: desc(projects.createdAt),
|
||||
});
|
||||
}),
|
||||
|
||||
remove: protectedProcedure
|
||||
.input(apiRemoveProject)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
Reference in New Issue
Block a user