Add console logs to code step (#10786)
Works for local and lambda drivers ## After  
This commit is contained in:
@ -10,6 +10,7 @@ export type ServerlessExecuteError = {
|
||||
export type ServerlessExecuteResult = {
|
||||
data: object | null;
|
||||
duration: number;
|
||||
logs: string;
|
||||
status: ServerlessFunctionExecutionStatus;
|
||||
error?: ServerlessExecuteError;
|
||||
};
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
PublishLayerVersionCommandInput,
|
||||
ResourceNotFoundException,
|
||||
waitUntilFunctionUpdatedV2,
|
||||
LogType,
|
||||
} from '@aws-sdk/client-lambda';
|
||||
import { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
@ -262,6 +263,21 @@ export class LambdaDriver implements ServerlessDriver {
|
||||
await lambdaBuildDirectoryManager.clean();
|
||||
}
|
||||
|
||||
private extractLogs(logString: string): string {
|
||||
const formattedLogString = Buffer.from(logString, 'base64')
|
||||
.toString('utf8')
|
||||
.split('\t')
|
||||
.join(' ');
|
||||
|
||||
return formattedLogString
|
||||
.replace(/^(START|END|REPORT).*\n?/gm, '')
|
||||
.replace(
|
||||
/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z) [a-f0-9-]+ INFO /gm,
|
||||
'$1 INFO ',
|
||||
)
|
||||
.trim();
|
||||
}
|
||||
|
||||
async execute(
|
||||
serverlessFunction: ServerlessFunctionEntity,
|
||||
payload: object,
|
||||
@ -302,6 +318,7 @@ export class LambdaDriver implements ServerlessDriver {
|
||||
const params: InvokeCommandInput = {
|
||||
FunctionName: serverlessFunction.id,
|
||||
Payload: JSON.stringify(executorPayload),
|
||||
LogType: LogType.Tail,
|
||||
};
|
||||
|
||||
const command = new InvokeCommand(params);
|
||||
@ -313,6 +330,8 @@ export class LambdaDriver implements ServerlessDriver {
|
||||
? JSON.parse(result.Payload.transformToString())
|
||||
: {};
|
||||
|
||||
const logs = result.LogResult ? this.extractLogs(result.LogResult) : '';
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
|
||||
if (result.FunctionError) {
|
||||
@ -321,11 +340,13 @@ export class LambdaDriver implements ServerlessDriver {
|
||||
duration,
|
||||
status: ServerlessFunctionExecutionStatus.ERROR,
|
||||
error: parsedResult,
|
||||
logs,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
data: parsedResult,
|
||||
logs,
|
||||
duration,
|
||||
status: ServerlessFunctionExecutionStatus.SUCCESS,
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
/* eslint-disable no-console */
|
||||
import { promises as fs } from 'fs';
|
||||
import { join } from 'path';
|
||||
|
||||
@ -129,6 +130,55 @@ export class LocalDriver implements ServerlessDriver {
|
||||
}
|
||||
}
|
||||
|
||||
const originalConsole = {
|
||||
log: console.log,
|
||||
error: console.error,
|
||||
warn: console.warn,
|
||||
info: console.info,
|
||||
debug: console.debug,
|
||||
};
|
||||
|
||||
const interceptConsole = (
|
||||
callback: (type: string, message: any[]) => void,
|
||||
) => {
|
||||
Object.keys(originalConsole).forEach((method) => {
|
||||
console[method] = (...args: any[]) => {
|
||||
callback(method, args);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
let logs = '';
|
||||
|
||||
interceptConsole((type, args) => {
|
||||
const formattedArgs = args.map((arg) => {
|
||||
if (typeof arg === 'object' && arg !== null) {
|
||||
const seen = new WeakSet();
|
||||
|
||||
return JSON.stringify(
|
||||
arg,
|
||||
(key, value) => {
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
if (seen.has(value)) {
|
||||
return '[Circular]'; // Handle circular references
|
||||
}
|
||||
seen.add(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
},
|
||||
2,
|
||||
);
|
||||
}
|
||||
|
||||
return arg;
|
||||
});
|
||||
|
||||
const formattedType = type === 'log' ? 'info' : type;
|
||||
|
||||
logs += `${new Date().toISOString()} ${formattedType.toUpperCase()} ${formattedArgs.join(' ')}\n`;
|
||||
});
|
||||
|
||||
try {
|
||||
const mainFile = await import(compiledCodeFilePath);
|
||||
|
||||
@ -141,12 +191,14 @@ export class LocalDriver implements ServerlessDriver {
|
||||
|
||||
return {
|
||||
data: result,
|
||||
logs,
|
||||
duration,
|
||||
status: ServerlessFunctionExecutionStatus.SUCCESS,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
data: null,
|
||||
logs,
|
||||
duration: Date.now() - startTime,
|
||||
error: {
|
||||
errorType: 'UnhandledError',
|
||||
@ -156,6 +208,12 @@ export class LocalDriver implements ServerlessDriver {
|
||||
status: ServerlessFunctionExecutionStatus.ERROR,
|
||||
};
|
||||
} finally {
|
||||
// Restoring originalConsole
|
||||
Object.keys(originalConsole).forEach((method) => {
|
||||
console[method] = (...args: any[]) => {
|
||||
originalConsole[method](...args);
|
||||
};
|
||||
});
|
||||
await fs.rm(compiledCodeFolderPath, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user