import * as Sentry from '@sentry/node'; import { ErrorRequestHandler } from 'express'; import { InternalServerError } from '../utils/errors'; import { getLogger } from '../utils/logger'; import RequestError, { LogLevel } from '../utils/requestError'; import { getNodeEnv } from '../config'; export const requestErrorHandler: ErrorRequestHandler = async ( error: RequestError | Error, req, res, next ) => { if (res.headersSent) return next(); if (await getNodeEnv() !== "production") { /* eslint-disable no-console */ console.error(error); } //TODO: Find better way to type check for error. In current setting you need to cast type to get the functions and variables from RequestError if (!(error instanceof RequestError)) { error = InternalServerError({ context: { exception: error.message }, stack: error.stack, }); (await getLogger('backend-main')).log( (error).levelName.toLowerCase(), (error).message ); } //* Set Sentry user identification if req.user is populated if (req.user !== undefined && req.user !== null) { Sentry.setUser({ email: (req.user as any).email }); } //* Only sent error to Sentry if LogLevel is one of the following level 'ERROR', 'EMERGENCY' or 'CRITICAL' //* with this we will eliminate false-positive errors like 'BadRequestError', 'UnauthorizedRequestError' and so on if ( [LogLevel.ERROR, LogLevel.EMERGENCY, LogLevel.CRITICAL].includes( (error).level ) ) { Sentry.captureException(error); } res .status((error).statusCode) .json((error).format(req)); next(); };