Skip to content

Commit

Permalink
feat: Add time selection to log query (#206)
Browse files Browse the repository at this point in the history
Adds the ability to fetch deployment logs within a selected time period

<img width="804" alt="image"
src="https://github.com/differentialhq/differential/assets/9162298/7bb161f2-21c7-42fb-9ab6-9103bf0aba46">
  • Loading branch information
johnjcsmith authored Apr 1, 2024
1 parent 83389b0 commit 2be0f4d
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 10 deletions.
3 changes: 2 additions & 1 deletion cli/src/client/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
21 changes: 20 additions & 1 deletion cli/src/commands/deploy-logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface DeployLogsArgs {
cluster?: string;
service?: string;
deployment?: string;
start?: number;
end?: number;
}
export const DeployLogs: CommandModule<{}, DeployLogsArgs> = {
command: "logs",
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -73,17 +89,20 @@ const getDeploymentLogs = async ({
clusterId,
serviceName,
deploymentId,
options,
}: {
clusterId: string;
serviceName: string;
deploymentId: string;
options?: { start?: Date; end?: Date };
}) => {
const result = await client.getDeploymentLogs({
params: {
clusterId,
serviceName,
deploymentId,
},
query: options,
});

if (result.status !== 200) {
Expand Down
2 changes: 2 additions & 0 deletions control-plane/src/modules/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
6 changes: 5 additions & 1 deletion control-plane/src/modules/deployment/deployment-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ export interface DeploymentProvider {
) => Promise<any>;
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;
Expand Down
19 changes: 17 additions & 2 deletions control-plane/src/modules/deployment/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down
12 changes: 9 additions & 3 deletions control-plane/src/modules/deployment/lambda-cfn-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`;

Expand All @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions control-plane/src/modules/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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 }),
},
};
},
Expand Down

0 comments on commit 2be0f4d

Please sign in to comment.