Skip to content

Commit

Permalink
refactor(CLI): Modern logs for invoke local command
Browse files Browse the repository at this point in the history
  • Loading branch information
pgrzesik committed Oct 7, 2021
1 parent 0c9941f commit 82dd1e4
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 27 deletions.
99 changes: 74 additions & 25 deletions lib/plugins/aws/invokeLocal/index.js
Expand Up @@ -5,6 +5,7 @@ const os = require('os');
const fsp = require('fs').promises;
const fse = require('fs-extra');
const path = require('path');
const stripAnsi = require('strip-ansi');
const validate = require('../lib/validate');
const chalk = require('chalk');
const stdin = require('get-stdin');
Expand All @@ -23,9 +24,13 @@ const isStandalone = require('../../../utils/isStandaloneExecutable');
const ensureArtifact = require('../../../utils/ensureArtifact');
const resolveCfImportValue = require('../utils/resolveCfImportValue');
const resolveCfRefValue = require('../utils/resolveCfRefValue');
const { legacy, writeText, progress, log } = require('@serverless/utils/log');

const cachePath = path.join(cachedir('serverless'), 'invokeLocal');

const mainProgress = progress.get('main');
const dockerProgress = progress.get('invokeLocalDocker');

const ensureRuntimeWrappers = isStandalone
? async () =>
ensureArtifact('runtimeWrappers/validationFile', async (runtimeCachePath) => {
Expand Down Expand Up @@ -310,7 +315,8 @@ class AwsInvokeLocal {
async pullDockerImage() {
const runtime = this.getRuntime();

this.serverless.cli.log('Downloading base Docker image...');
legacy.log('Downloading base Docker image...');
dockerProgress.notice('Downloading base Docker image');
return spawnExt('docker', [
'pull',
'--disable-content-trust=false',
Expand All @@ -326,6 +332,7 @@ class AwsInvokeLocal {
return Promise.all(
(this.options.functionObj.layers || this.serverless.service.provider.layers || []).map(
async (layer) => {
const layerProgress = progress.get(`layer:${layer}`);
if (layer.Ref) {
const targetLayer = layers[layer.Ref];

Expand All @@ -338,7 +345,8 @@ class AwsInvokeLocal {
if (exists) {
return layerArtifactContentPath;
}
this.serverless.cli.log(`Unziping ${layer.Ref}...`);
legacy.log(`Unzipping ${layer.Ref}...`);
layerProgress.notice(`Unzipping ${layer.Ref}`);
await decompress(targetLayer.package.artifact, layerArtifactContentPath);
return layerArtifactContentPath;
}
Expand All @@ -354,7 +362,8 @@ class AwsInvokeLocal {
if (!exists) {
const cacheExists = await dirExists(layerContentsCachePath);
if (!cacheExists) {
this.serverless.cli.log(`Downloading layer ${layer}...`);
legacy.log(`Downloading layer ${layer}...`);
layerProgress.notice(`Downloading layer ${layer}`);
await ensureDir(path.join(layerContentsCachePath));

const layerInfo = await this.provider.request('Lambda', 'getLayerVersion', {
Expand All @@ -368,6 +377,7 @@ class AwsInvokeLocal {
}
}
await fse.copy(layerContentsCachePath, layerContentsPath);
layerProgress.remove();
return layerContentsPath;
}
)
Expand Down Expand Up @@ -405,13 +415,15 @@ class AwsInvokeLocal {
ensureDir(path.join(cachePath, 'dockerfiles', runtime)),
]);

this.serverless.cli.log('Writing Dockerfile...');
dockerProgress.notice('Writing Dockerfile');
legacy.log('Writing Dockerfile...');
await Promise.all([
fsp.writeFile(dockerfilePath, dockerFileContent),
fsp.writeFile(dockerfileCachePath, dockerFileContent),
]);

this.serverless.cli.log('Building Docker image...');
dockerProgress.notice('Building Docker image');
legacy.log('Building Docker image...');
try {
await spawnExt('docker', [
'build',
Expand All @@ -424,12 +436,15 @@ class AwsInvokeLocal {
return imageName;
} catch (err) {
if (err.stdBuffer) {
process.stdout.write(err.stdBuffer);
legacy.consoleLog(err.stdBuffer.toString().trimRight());
log.info(stripAnsi(err.stdBuffer.toString().trimRight()));
}
throw new ServerlessError(
`Failed to build docker image (exit code ${err.code}})`,
'DOCKER_IMAGE_BUILD_FAILED'
);
} finally {
dockerProgress.remove();
}
}

Expand Down Expand Up @@ -486,6 +501,7 @@ class AwsInvokeLocal {
const runtime = this.getRuntime();

await this.ensurePackage();
mainProgress.notice('Invoking function locally', { isMainEvent: true });
await this.checkDockerDaemonStatus();
const results = await Promise.all([
this.checkDockerImage(`lambci/lambda:${runtime}`).then((exists) => {
Expand Down Expand Up @@ -530,12 +546,14 @@ class AwsInvokeLocal {
try {
const { stdBuffer } = await spawnExt('docker', dockerArgs);
if (stdBuffer) {
process.stdout.write(stdBuffer);
legacy.consoleLog(stdBuffer.toString().trimRight());
writeText(stripAnsi(stdBuffer.toString().trimRight()));
}
return imageName;
} catch (err) {
if (err.stdBuffer) {
process.stdout.write(err.stdBuffer);
legacy.consoleLog(err.stdBuffer.toString().trimRight());
writeText(stripAnsi(err.stdBuffer.toString().trimRight()));
}
throw new ServerlessError(
`Failed to run docker for ${runtime} image (exit code ${err.code}})`,
Expand Down Expand Up @@ -587,8 +605,14 @@ class AwsInvokeLocal {
{ env: process.env },
{ shell: true }
);
python.stdout.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
python.stderr.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
python.stdout.on('data', (buf) => {
legacy.consoleLog(buf.toString());
writeText(buf.toString());
});
python.stderr.on('data', (buf) => {
legacy.consoleLog(buf.toString());
writeText(buf.toString());
});
python.on('close', () => resolve());
let isRejected = false;
python.on('error', (error) => {
Expand Down Expand Up @@ -619,15 +643,22 @@ class AwsInvokeLocal {
{ shell: true }
);

// TODO: CONSIDER IT AS A WARNING
this.serverless.cli.log(
[
'In order to get human-readable output,',
' please implement "toString()" method of your "ApiGatewayResponse" object.',
].join('')
);

java.stdout.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
java.stderr.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
java.stdout.on('data', (buf) => {
legacy.consoleLog(buf.toString());
writeText(buf.toString());
});
java.stderr.on('data', (buf) => {
legacy.consoleLog(buf.toString());
writeText(buf.toString());
});
java.on('close', () => resolve());
let isRejected = false;
java.on('error', (error) => {
Expand Down Expand Up @@ -673,19 +704,20 @@ class AwsInvokeLocal {
await fsp.stat(executablePath);
} catch (err) {
return new Promise((resolve, reject) => {
const javaBridgeProgress = progress.get('javaBridge');
javaBridgeProgress.notice('Building Java bridge', { isMainEvent: true });
const mvn = spawn('mvn', ['package', '-f', path.join(javaBridgePath, 'pom.xml')], {
shell: true,
});

this.serverless.cli.log('Building Java bridge, first invocation might take a bit longer.');
legacy.log('Building Java bridge, first invocation might take a bit longer.');

mvn.stderr.on('data', (buf) =>
this.serverless.cli.consoleLog(`mvn(stderr) - ${buf.toString()}`)
);
mvn.stderr.on('data', (buf) => {
legacy.consoleLog(`mvn(stderr) - ${buf.toString()}`);
log.info(`mvn(stderr) - ${buf.toString()}`);
});
const chunk = [];
if (process.env.SLS_DEBUG) {
mvn.stdout.on('data', (buf) => chunk.push(buf));
}
mvn.stdout.on('data', (buf) => chunk.push(buf));

let isRejected = false;
mvn.on('error', (error) => {
Expand All @@ -696,6 +728,7 @@ class AwsInvokeLocal {
});

mvn.on('exit', (code, signal) => {
javaBridgeProgress.remove();
if (code === 0) {
resolve(this.callJavaBridge(artifactPath, className, handlerName, input));
} else if (!isRejected) {
Expand All @@ -705,9 +738,16 @@ class AwsInvokeLocal {
.join('')
.split(/\n/)
.forEach((line) => {
this.serverless.cli.consoleLog(`mvn(stdout) - ${line}`);
legacy.consoleLog(`mvn(stdout) - ${line}`);
});
}
chunk
.map((elem) => elem.toString())
.join('')
.split(/\n/)
.forEach((line) => {
log.info(`mvn(stdout) - ${line}`);
});
isRejected = true;
reject(
new ServerlessError(
Expand Down Expand Up @@ -739,8 +779,14 @@ class AwsInvokeLocal {
env: process.env,
shell: true,
});
ruby.stdout.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
ruby.stderr.on('data', (buf) => this.serverless.cli.consoleLog(buf.toString()));
ruby.stdout.on('data', (buf) => {
legacy.consoleLog(buf.toString());
writeText(buf.toString());
});
ruby.stderr.on('data', (buf) => {
legacy.consoleLog(buf.toString());
writeText(buf.toString());
});
ruby.on('close', () => resolve());
let isRejected = false;
ruby.on('error', (error) => {
Expand Down Expand Up @@ -773,7 +819,8 @@ class AwsInvokeLocal {
const handlersContainer = require(pathToHandler);
lambda = handlersContainer[handlerName];
} catch (error) {
this.serverless.cli.consoleLog(chalk.red(inspect(error)));
legacy.consoleLog(chalk.red(inspect(error)));
log.error(inspect(error));
throw new ServerlessError(
`Exception encountered when loading ${pathToHandler}`,
'INVOKE_LOCAL_LAMBDA_INITIALIZATION_FAILED'
Expand Down Expand Up @@ -801,7 +848,8 @@ class AwsInvokeLocal {
};
}

this.serverless.cli.consoleLog(chalk.red(JSON.stringify(errorResult, null, 4)));
legacy.consoleLog(chalk.red(JSON.stringify(errorResult, null, 4)));
writeText(JSON.stringify(errorResult, null, 4));
process.exitCode = 1;
}

Expand Down Expand Up @@ -834,7 +882,8 @@ class AwsInvokeLocal {
}
}

this.serverless.cli.consoleLog(JSON.stringify(result, null, 4));
legacy.consoleLog(JSON.stringify(result, null, 4));
writeText(JSON.stringify(result, null, 4));
}

return new Promise((resolve) => {
Expand Down
4 changes: 3 additions & 1 deletion lib/plugins/aws/package/compile/layers.js
Expand Up @@ -6,6 +6,7 @@ const _ = require('lodash');
const path = require('path');
const fsAsync = BbPromise.promisifyAll(require('fs'));
const getLambdaLayerArtifactPath = require('../../utils/getLambdaLayerArtifactPath');
const { legacy, log } = require('@serverless/utils/log');

class AwsCompileLayers {
constructor(serverless, options) {
Expand Down Expand Up @@ -151,7 +152,8 @@ class AwsCompileLayers {
layerResource.Properties.Content.S3Key = lastS3Key.OutputValue;
const layerObject = this.serverless.service.getLayer(layerName);
layerObject.artifactAlreadyUploaded = true;
this.serverless.cli.log(`Layer ${layerName} is already uploaded.`);
legacy.log(`Layer ${layerName} is already uploaded.`);
log.info(`Layer ${layerName} is already uploaded.`);
},
(e) => {
if (e.message.includes('does not exist')) {
Expand Down
2 changes: 1 addition & 1 deletion test/unit/lib/plugins/aws/invokeLocal/index.test.js
Expand Up @@ -1170,7 +1170,7 @@ describe('test/unit/lib/plugins/aws/invokeLocal/index.test.js', () => {
const [firstRemainingMs, secondRemainingMs, thirdRemainingMs] = JSON.parse(body).data;
expect(firstRemainingMs).to.be.lte(3000);
expect(secondRemainingMs).to.be.lte(2900);
expect(thirdRemainingMs).to.be.lt(secondRemainingMs);
expect(thirdRemainingMs).to.be.lte(secondRemainingMs);
});
});

Expand Down

0 comments on commit 82dd1e4

Please sign in to comment.