lib/src/lifecycle/RunLevelErrorHandler.ts

93 lines
2.6 KiB
TypeScript
Raw Normal View History

2021-03-03 00:57:41 +00:00
import * as color from 'colors/safe'
2021-06-03 03:36:25 +00:00
import {Logging} from '../service/Logging'
import {Inject} from '../di'
import {ErrorWithContext} from '../util'
2021-03-03 00:57:41 +00:00
2021-03-25 13:50:13 +00:00
/**
* Class with logic for handling errors that are thrown at the run-level of the application.
*
* Colloquially, these are errors thrown ourside the request-lifecycle that are not caught by a unit.
*/
2021-03-03 00:57:41 +00:00
export class RunLevelErrorHandler {
@Inject()
protected logging!: Logging
/**
* Get the error handler function.
* @type (e: Error) => void
*/
get handle(): (e: Error) => void {
return (e: Error) => {
this.display(e)
process.exit(1)
}
}
2021-03-25 13:50:13 +00:00
/**
* Wrap the given base Error instance into an ErrorWithContext.
* @param e
* @param context
*/
2021-03-03 00:57:41 +00:00
wrapContext(e: Error, context: {[key: string]: any}): ErrorWithContext {
if ( e instanceof ErrorWithContext ) {
2021-06-03 03:36:25 +00:00
e.context = {...e.context,
...context}
2021-03-03 00:57:41 +00:00
return e
}
const error = new ErrorWithContext(e.message)
error.originalError = e
error.context = context
error.stack = e.stack
2021-03-03 00:57:41 +00:00
return error
}
/**
* Log the error to the logger.
* @param {Error} e
*/
2021-06-03 03:36:25 +00:00
display(e: Error): void {
2021-03-03 00:57:41 +00:00
let operativeError = e
let context: {[key: string]: string} = {}
if ( e instanceof ErrorWithContext ) {
2021-06-03 03:36:25 +00:00
if ( e.originalError ) {
operativeError = e.originalError
}
2021-03-03 00:57:41 +00:00
context = e.context
}
2021-06-03 03:36:25 +00:00
const contextDisplay = Object.keys(context).map(key => ` - ${key}: ${context[key]}`)
.join('\n')
2021-03-03 00:57:41 +00:00
try {
let errorString = `RunLevelErrorHandler invoked:
${color.bgRed(' ')}
${color.bgRed(' UNCAUGHT RUN-LEVEL ERROR ')}
${color.bgRed(' ')}
${operativeError.constructor ? operativeError.constructor.name : operativeError.name}
2021-03-03 00:57:41 +00:00
${color.red(`---------------------------------------------------`)}
${operativeError.stack}
2021-03-03 00:57:41 +00:00
`
if ( contextDisplay ) {
errorString += `
With the following context:
${contextDisplay}
`
}
2021-06-03 03:36:25 +00:00
2021-03-03 00:57:41 +00:00
this.logging.error(errorString, true)
2021-10-18 18:03:28 +00:00
} catch (displayError: unknown) {
if ( displayError instanceof Error ) {
// The error display encountered an error...
// just throw the original so it makes it out
console.error('RunLevelErrorHandler encountered an error:', displayError.message) // eslint-disable-line no-console
}
2021-03-03 00:57:41 +00:00
throw operativeError
}
}
}