0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Added err.context & err.help to stack traces

- When we handle errors in Ghost, we are supposed to use a pattern of supplying 3 messages:
   - message: what went wrong
   - context: details about why how or where the error happened
   - help: where the user can go to get help with this error
- We do this in many places and our JSON error handler and CLI error logging tools are designed to output this extra information
- However, stack traces, which start with message as the first line and then output the stack are totally missing this
- By injecting the additional messages into the stack once an error has been "ghostified" we should get clearer messages everywhere

Notes:
- I've additionally injected a "Stack Trace:" line that makes it easier to read the error vs the stack
- This code looks a little weird because the lines are inserted backwards, but that allows us to always to the insert at position 1 as per the comment,
   so we don't have to keep track of whether we already injected something or not
This commit is contained in:
Hannah Wolfe 2021-11-24 12:38:51 +00:00
parent 0799f02e80
commit 5e931e2e37
No known key found for this signature in database
GPG key ID: AB586C3B5AE5C037

View file

@ -60,6 +60,32 @@ _private.createHbsEngine = () => {
return engine.express4();
};
_private.updateStack = (err) => {
let stackbits = err.stack.split(/\n/g);
// We build this up backwards, so we always insert at position 1
if (process.env.NODE_ENV === 'production' || err.statusCode === 404) {
// In production mode, remove the stack trace
stackbits.splice(1, stackbits.length - 1);
} else {
// In dev mode, clearly mark the strack trace
stackbits.splice(1, 0, `Stack Trace:`);
}
// Add in our custom cotext and help methods
if (err.help) {
stackbits.splice(1, 0, `${err.help}`);
}
if (err.context) {
stackbits.splice(1, 0, `${err.context}`);
}
return stackbits.join('\n');
};
/**
* Get an error ready to be shown the the user
*
@ -102,6 +128,8 @@ _private.prepareError = (err, req, res, next) => {
// alternative for res.status();
res.statusCode = err.statusCode;
err.stack = _private.updateStack(err);
// never cache errors
res.set({
'Cache-Control': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
@ -263,7 +291,7 @@ function createHtmlDocument(status, message) {
<pre>${status} ${body}</pre>\n
</body>\n
</html>\n`;
}
}
_private.HTMLErrorRenderer = (err, req, res, next) => { // eslint-disable-line no-unused-vars
return res.send(createHtmlDocument(res.statusCode, err.stack));