diff --git a/cli/src/client/contract.ts b/cli/src/client/contract.ts index 24d786b2..4dd30662 100644 --- a/cli/src/client/contract.ts +++ b/cli/src/client/contract.ts @@ -503,10 +503,11 @@ export const definition = { }), query: z.object({ next: z.string().optional(), + start: z.date().optional(), + end: z.date().optional(), }), body: z.undefined(), responses: { - 400: z.undefined(), 401: z.undefined(), 404: z.undefined(), 200: z.object({ diff --git a/cli/src/commands/deploy-logs.ts b/cli/src/commands/deploy-logs.ts index 6db7c16b..a7437668 100644 --- a/cli/src/commands/deploy-logs.ts +++ b/cli/src/commands/deploy-logs.ts @@ -8,6 +8,8 @@ interface DeployLogsArgs { cluster?: string; service?: string; deployment?: string; + start?: number; + end?: number; } export const DeployLogs: CommandModule<{}, DeployLogsArgs> = { command: "logs", @@ -28,8 +30,18 @@ export const DeployLogs: CommandModule<{}, DeployLogsArgs> = { describe: "Deployment ID", demandOption: false, type: "string", + }) + .option("start", { + describe: "Start time (Unix timestamp, milliseconds)", + demandOption: false, + type: "number", + }) + .option("end", { + describe: "End time (Unix timestamp, milliseconds)", + demandOption: false, + type: "number", }), - handler: async ({ cluster, service, deployment }) => { + handler: async ({ cluster, service, deployment, start, end }) => { if (!cluster) { cluster = await selectCluster(); if (!cluster) { @@ -62,6 +74,10 @@ export const DeployLogs: CommandModule<{}, DeployLogsArgs> = { clusterId: cluster, serviceName: service, deploymentId: deployment, + options: { + ...(start !== undefined && { start: new Date(start) }), + ...(end !== undefined && { end: new Date(end) }), + }, }); logs.forEach((log) => { console.log(log.message); @@ -73,10 +89,12 @@ const getDeploymentLogs = async ({ clusterId, serviceName, deploymentId, + options, }: { clusterId: string; serviceName: string; deploymentId: string; + options?: { start?: Date; end?: Date }; }) => { const result = await client.getDeploymentLogs({ params: { @@ -84,6 +102,7 @@ const getDeploymentLogs = async ({ serviceName, deploymentId, }, + query: options, }); if (result.status !== 200) { diff --git a/control-plane/src/modules/contract.ts b/control-plane/src/modules/contract.ts index a9b14c7f..1d1be22f 100644 --- a/control-plane/src/modules/contract.ts +++ b/control-plane/src/modules/contract.ts @@ -503,6 +503,8 @@ export const definition = { }), query: z.object({ next: z.string().optional(), + start: z.coerce.date().optional(), + end: z.coerce.date().optional(), }), body: z.undefined(), responses: { diff --git a/control-plane/src/modules/deployment/deployment-provider.ts b/control-plane/src/modules/deployment/deployment-provider.ts index 0afbb637..6046d5bf 100644 --- a/control-plane/src/modules/deployment/deployment-provider.ts +++ b/control-plane/src/modules/deployment/deployment-provider.ts @@ -51,7 +51,11 @@ export interface DeploymentProvider { ) => Promise; getLogs: ( deployment: Deployment, - nextToken?: string, + options: { + start?: Date; + end?: Date; + next?: string; + }, ) => Promise<{ message: string }[]>; // How frequently the provider should be notified of new jobs minimumNotificationInterval: () => number; diff --git a/control-plane/src/modules/deployment/deployment.ts b/control-plane/src/modules/deployment/deployment.ts index bc341fc0..da5d0c66 100644 --- a/control-plane/src/modules/deployment/deployment.ts +++ b/control-plane/src/modules/deployment/deployment.ts @@ -201,10 +201,25 @@ export const releaseDeployment = async ( export const getDeploymentLogs = async ( deployment: Deployment, - nextToken?: string, + options: { + start?: Date; + end?: Date; + next?: string; + } = {}, ): Promise<{ message: string }[]> => { + let start = options.start ?? new Date(Date.now() - 3600000); + let end = options.end ?? new Date(); + + if (start >= end) { + throw new Error("Log start time must be before end time"); + } + const provider = getDeploymentProvider(deployment.provider); - return await provider.getLogs(deployment, nextToken); + return await provider.getLogs(deployment, { + next: options.next, + start, + end, + }); }; const inactivateExistingDeployments = async ( diff --git a/control-plane/src/modules/deployment/lambda-cfn-provider.ts b/control-plane/src/modules/deployment/lambda-cfn-provider.ts index d28a811b..e32ef6c6 100644 --- a/control-plane/src/modules/deployment/lambda-cfn-provider.ts +++ b/control-plane/src/modules/deployment/lambda-cfn-provider.ts @@ -118,7 +118,11 @@ export class LambdaCfnProvider implements DeploymentProvider { public async getLogs( deployment: Deployment, - nextToken?: string, + options: { + start?: Date; + end?: Date; + next?: string; + } = {}, ): Promise<{ message: string }[]> { const logGroupName = `/aws/lambda/${this.buildFunctionName(deployment)}`; @@ -128,9 +132,11 @@ export class LambdaCfnProvider implements DeploymentProvider { ); const request = new FilterLogEventsCommand({ - nextToken, + startTime: options.start?.getTime(), + endTime: options.end?.getTime(), + nextToken: options.next, logGroupName, - limit: 500, + limit: 1000, }); try { diff --git a/control-plane/src/modules/router.ts b/control-plane/src/modules/router.ts index 823d3174..5ad912eb 100644 --- a/control-plane/src/modules/router.ts +++ b/control-plane/src/modules/router.ts @@ -461,7 +461,7 @@ export const router = s.router(contract, { } const { clusterId, deploymentId } = request.params; - const { next } = request.query; + const { start, end, next } = request.query; const deployment = await getDeployment(deploymentId); @@ -474,7 +474,7 @@ export const router = s.router(contract, { return { status: 200, body: { - events: await getDeploymentLogs(deployment, next), + events: await getDeploymentLogs(deployment, { start, end, next }), }, }; },