mirror of
https://github.com/Dokploy/dokploy.git
synced 2026-06-15 20:25:23 +02:00
feat: add readLogs procedure to multiple routers for container log retrieval
- Implemented a new `readLogs` procedure across various routers (application, compose, libsql, mariadb, mongo, mysql, postgres, redis) to enable users to retrieve logs from containers. - Each procedure includes input validation for parameters such as `tail`, `since`, and `search`, ensuring robust access control and authorization checks. - Enhanced the `getContainerLogs` service to support fetching logs from both Docker containers and services, improving the logging capabilities of the application. This feature enhances observability and troubleshooting for users by providing direct access to container logs.
This commit is contained in:
@@ -6,7 +6,9 @@ import {
|
||||
findEnvironmentById,
|
||||
findGitProviderById,
|
||||
findProjectById,
|
||||
getAccessibleServerIds,
|
||||
getApplicationStats,
|
||||
getContainerLogs,
|
||||
IS_CLOUD,
|
||||
mechanizeDockerContainer,
|
||||
readConfig,
|
||||
@@ -26,7 +28,6 @@ import {
|
||||
updateDeploymentStatus,
|
||||
writeConfig,
|
||||
writeConfigRemote,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -1101,4 +1102,39 @@ export const applicationRouter = createTRPCRouter({
|
||||
total: countResult[0]?.count ?? 0,
|
||||
};
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOneApplication.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.applicationId, "read");
|
||||
const application = await findApplicationById(input.applicationId);
|
||||
if (
|
||||
application.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this application",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
application.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
application.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -16,7 +16,9 @@ import {
|
||||
findGitProviderById,
|
||||
findProjectById,
|
||||
findServerById,
|
||||
getAccessibleServerIds,
|
||||
getComposeContainer,
|
||||
getContainerLogs,
|
||||
getWebServerSettings,
|
||||
IS_CLOUD,
|
||||
loadServices,
|
||||
@@ -30,7 +32,6 @@ import {
|
||||
stopCompose,
|
||||
updateCompose,
|
||||
updateDeploymentStatus,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -1130,4 +1131,43 @@ export const composeRouter = createTRPCRouter({
|
||||
total: countResult[0]?.count ?? 0,
|
||||
};
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindCompose.extend({
|
||||
containerId: z
|
||||
.string()
|
||||
.min(1)
|
||||
.regex(/^[a-zA-Z0-9.\-_]+$/, "Invalid container id."),
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.composeId, "read");
|
||||
const compose = await findComposeById(input.composeId);
|
||||
if (
|
||||
compose.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this compose",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
input.containerId,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
compose.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
findEnvironmentById,
|
||||
findLibsqlById,
|
||||
findProjectById,
|
||||
getContainerLogs,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
removeLibsqlById,
|
||||
@@ -466,4 +467,39 @@ export const libsqlRouter = createTRPCRouter({
|
||||
});
|
||||
return true;
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOneLibsql.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.libsqlId, "read");
|
||||
const libsql = await findLibsqlById(input.libsqlId);
|
||||
if (
|
||||
libsql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this LibSQL",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
libsql.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
libsql.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
findEnvironmentById,
|
||||
findMariadbById,
|
||||
findProjectById,
|
||||
getAccessibleServerIds,
|
||||
getContainerLogs,
|
||||
getServiceContainerCommand,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -19,7 +21,6 @@ import {
|
||||
stopService,
|
||||
stopServiceRemote,
|
||||
updateMariadbById,
|
||||
getAccessibleServerIds,
|
||||
} from "@dokploy/server";
|
||||
import { db } from "@dokploy/server/db";
|
||||
import {
|
||||
@@ -590,4 +591,39 @@ export const mariadbRouter = createTRPCRouter({
|
||||
]);
|
||||
return { items, total: countResult[0]?.count ?? 0 };
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOneMariaDB.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.mariadbId, "read");
|
||||
const mariadb = await findMariadbById(input.mariadbId);
|
||||
if (
|
||||
mariadb.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this MariaDB",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
mariadb.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
mariadb.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
findMongoById,
|
||||
findProjectById,
|
||||
getAccessibleServerIds,
|
||||
getContainerLogs,
|
||||
getServiceContainerCommand,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -601,4 +602,39 @@ export const mongoRouter = createTRPCRouter({
|
||||
]);
|
||||
return { items, total: countResult[0]?.count ?? 0 };
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOneMongo.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.mongoId, "read");
|
||||
const mongo = await findMongoById(input.mongoId);
|
||||
if (
|
||||
mongo.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this MongoDB",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
mongo.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
mongo.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
findEnvironmentById,
|
||||
findMySqlById,
|
||||
findProjectById,
|
||||
getContainerLogs,
|
||||
getServiceContainerCommand,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -604,4 +605,39 @@ export const mysqlRouter = createTRPCRouter({
|
||||
]);
|
||||
return { items, total: countResult[0]?.count ?? 0 };
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOneMySql.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.mysqlId, "read");
|
||||
const mysql = await findMySqlById(input.mysqlId);
|
||||
if (
|
||||
mysql.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this MySQL",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
mysql.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
mysql.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
findEnvironmentById,
|
||||
findPostgresById,
|
||||
findProjectById,
|
||||
getContainerLogs,
|
||||
getMountPath,
|
||||
getServiceContainerCommand,
|
||||
IS_CLOUD,
|
||||
@@ -614,4 +615,39 @@ export const postgresRouter = createTRPCRouter({
|
||||
]);
|
||||
return { items, total: countResult[0]?.count ?? 0 };
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOnePostgres.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.postgresId, "read");
|
||||
const postgres = await findPostgresById(input.postgresId);
|
||||
if (
|
||||
postgres.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this Postgres",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
postgres.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
postgres.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
findEnvironmentById,
|
||||
findProjectById,
|
||||
findRedisById,
|
||||
getContainerLogs,
|
||||
getServiceContainerCommand,
|
||||
IS_CLOUD,
|
||||
rebuildDatabase,
|
||||
@@ -587,4 +588,39 @@ export const redisRouter = createTRPCRouter({
|
||||
]);
|
||||
return { items, total: countResult[0]?.count ?? 0 };
|
||||
}),
|
||||
|
||||
readLogs: protectedProcedure
|
||||
.input(
|
||||
apiFindOneRedis.extend({
|
||||
tail: z.number().int().min(1).max(10000).default(100),
|
||||
since: z
|
||||
.string()
|
||||
.regex(/^(all|\d+[smhd])$/, "Invalid since format")
|
||||
.default("all"),
|
||||
search: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9 ._-]{0,500}$/)
|
||||
.optional(),
|
||||
}),
|
||||
)
|
||||
.query(async ({ input, ctx }) => {
|
||||
await checkServiceAccess(ctx, input.redisId, "read");
|
||||
const redis = await findRedisById(input.redisId);
|
||||
if (
|
||||
redis.environment.project.organizationId !==
|
||||
ctx.session.activeOrganizationId
|
||||
) {
|
||||
throw new TRPCError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "You are not authorized to access this Redis",
|
||||
});
|
||||
}
|
||||
return await getContainerLogs(
|
||||
redis.appName,
|
||||
input.tail,
|
||||
input.since,
|
||||
input.search,
|
||||
redis.serverId,
|
||||
);
|
||||
}),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user