Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Output stack trace on failure #718

Merged
merged 1 commit into from Jun 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -99,6 +99,7 @@ All CLI options are optional:
--providedRuntime Sets the runtime for "provided" lambda runtimes
--disableModelValidation Disables the model validation
--showDuration Show the execution time duration of the lambda function.
--hideStackTraces Hide the stack trace on lambda failure. Default: false
```

Any of the CLI options can be added to your `serverless.yml`. For example:
Expand Down
4 changes: 4 additions & 0 deletions manual_test_nodejs/handler.js
Expand Up @@ -97,3 +97,7 @@ module.exports.pathParams = (event, context, cb) => {

cb(null, response);
};

module.exports.failure = (event, context, cb) => {
throw new Error('Unexpected error!')
};
21 changes: 15 additions & 6 deletions manual_test_nodejs/serverless.yml
Expand Up @@ -158,19 +158,28 @@ functions:
method: POST
private: true

catchAll:
handler: handler.catchAll
events:
- http:
path: /{proxy+}
method: ANY
pathParams:
handler: handler.pathParams
events:
- http:
path: /pathParams/{id}
method: GET

failure:
handler: handler.failure
events:
- http:
path: /failure
method: GET

catchAll:
handler: handler.catchAll
events:
- http:
path: /{proxy+}
method: ANY


# you can add CloudFormation resource templates here
resources:
Resources:
Expand Down
29 changes: 14 additions & 15 deletions src/index.js
Expand Up @@ -87,6 +87,9 @@ class Offline {
exec: {
usage: 'When provided, a shell script is executed when the server starts up, and the server will shut down after handling this command.',
},
hideStackTraces: {
usage: 'Hide the stack trace on lambda failure. Default: false',
},
host: {
usage: 'The host name to listen on. Default: localhost',
shortcut: 'o',
Expand Down Expand Up @@ -284,6 +287,7 @@ class Offline {
resourceRoutes: false,
skipCacheInvalidation: false,
useSeparateProcesses: false,
hideStackTraces: false,
};

// In the constructor, stage and regions are set to undefined
Expand Down Expand Up @@ -776,8 +780,8 @@ class Offline {

this.serverlessLog(`Failure: ${errorMessage}`);

if (result.stackTrace) {
debugLog(result.stackTrace.join('\n '));
if (!this.options.hideStackTraces) {
console.error(err.stack);
}

for (const key in endpoint.responses) {
Expand Down Expand Up @@ -1175,36 +1179,31 @@ class Offline {
}

// Bad news
_replyError(responseCode, response, message, err) {
const stackTrace = this._getArrayStackTrace(err.stack);
_replyError(responseCode, response, message, error) {
const stackTrace = this._getArrayStackTrace(error.stack);

this.serverlessLog(message);
if (stackTrace && stackTrace.length > 0) {
console.log(stackTrace);
}
else {
console.log(err);
}

console.error(error);

response.header('Content-Type', 'application/json');

/* eslint-disable no-param-reassign */
response.statusCode = responseCode;
response.source = {
errorMessage: message,
errorType: err.constructor.name,
errorType: error.constructor.name,
stackTrace,
offlineInfo: 'If you believe this is an issue with the plugin please submit it, thanks. https://github.com/dherault/serverless-offline/issues',
offlineInfo: 'If you believe this is an issue with serverless-offline please submit it, thanks. https://github.com/dherault/serverless-offline/issues',
};
/* eslint-enable no-param-reassign */
this.serverlessLog('Replying error in handler');

return response;
}

_reply500(response, message, err) {
_reply500(response, message, error) {
// APIG replies 200 by default on failures
return this._replyError(200, response, message, err);
return this._replyError(200, response, message, error);
}

_replyTimeout(response, resolve, funName, funTimeout, requestId) {
Expand Down