UNPKG

actionhero

Version:

The reusable, scalable, and quick node.js API server for stateless and stateful applications

156 lines (142 loc) 3.76 kB
import { api, config, log, Initializer, Action } from "../index"; import { ExceptionReporter } from "../classes/exceptionReporter"; import { ParsedJob } from "node-resque"; import { ActionheroLogLevel } from "../modules/log"; export interface ExceptionHandlerAPI { reporters: Array<ExceptionReporter>; report: ExceptionsInitializer["report"]; initializer: ExceptionsInitializer["initializer"]; action: ExceptionsInitializer["action"]; task: ExceptionsInitializer["task"]; } /** * Handlers for when things go wrong. */ export class ExceptionsInitializer extends Initializer { constructor() { super(); this.name = "exceptions"; this.loadPriority = 1; } report = ( error: NodeJS.ErrnoException, type: string, name: string, objects?: any, severity?: ActionheroLogLevel, ) => { if (!severity) severity = "error"; for (const reporter of api.exceptionHandlers.reporters) { reporter(error, type, name, objects, severity); } }; initializer = (error: NodeJS.ErrnoException, fullFilePath: string) => { const name = "initializer:" + fullFilePath; api.exceptionHandlers.report( error, "initializer", name, { fullFilePath: fullFilePath }, "alert", ); }; action = ( error: NodeJS.ErrnoException, { to, action, params, duration, response, }: { to: string; action: Action["name"]; params: string; duration: number; response: string; }, ) => { api.exceptionHandlers.report( error, "action", `action: ${action}`, { to, action, params, duration, error, response }, "alert", ); }; task = ( error: NodeJS.ErrnoException, queue: string, task: ParsedJob, workerId: string | number, ) => { let simpleName; try { simpleName = task["class"]; } catch (e) { simpleName = error.message; } const name = "task:" + simpleName; api.exceptionHandlers.report( error, "task", name, { task: task, queue: queue, workerId: workerId }, config.tasks.workerLogging.failure, ); }; async initialize() { api.exceptionHandlers = { reporters: [], report: this.report, initializer: this.initializer, action: this.action, task: this.task, }; api.exceptionHandlers.reporters.push(consoleReporter); } } const consoleReporter: ExceptionReporter = ( error: NodeJS.ErrnoException & { [key: string]: any }, type, name, objects, severity, ) => { let message = ""; const data = error["data"] ?? {}; if (type === "uncaught") { message = `Uncaught ${name}`; } else if (type === "action") { // no need to log anything, it was handled already by the actionProcessor } else if (type === "initializer") { message = `Error from Initializer`; } else if (type === "task") { message = `Error from Task`; data["name"] = name; data["queue"] = objects.queue; data["worker"] = objects.workerId; data["arguments"] = objects?.task?.args ? JSON.stringify(objects.task.args[0]) : undefined; } else { message = `Error: ${error?.message || error.toString()}`; Object.getOwnPropertyNames(error) .filter((prop) => prop !== "message") .sort((a, b) => (a === "stack" || b === "stack" ? -1 : 1)) .forEach((prop) => (data[prop] = error[prop])); data["type"] = type; data["name"] = name; data["data"] = objects; } if (error["stack"]) { data["stack"] = error.stack; } else { data["stack"] = error.message ?? error.toString(); } try { if (message) log(message, severity, data); } catch (e) { console.log(message, data); } };