'use strict'; const util = require('util'), path = require('path'), mailer = require('mailer').default, KeyFileStorage = require("key-file-storage").default, debug = require('debug')('agm:errHelper'); let logFileName = path.basename(__filename); /** * Report important errors to Admin * @param {*} error Error message in text or the Error object */ async function mailErrorToAdmin(error) { const errorMsg = (error && error.message) ? error.message : error; const contentOps = { subject: '[Agm-Errors] Unexpected Errors', body: error && error.stack ? errorMsg + '\n' + error.stack : errorMsg, to: process.env.AGM_ADM_EMAIL || '"AgMission Admin" ', }; return await mailer.sendTextMail(contentOps); } async function _handleCriticalError(error, message) { const exitFunc = (err) => { debug(err); process.exit(1); }; try { const baseFilename = path.basename(logFileName); const kfs = KeyFileStorage(path.dirname(logFileName), false); let lastReport = await kfs[baseFilename]; let curDateTime = new Date(); if (kfs[baseFilename] && (lastReport = kfs[baseFilename])) { if (lastReport.when && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.*$/.test(lastReport.when)) { if (curDateTime - new Date(lastReport.when) < 2 * 60 * 1e3 && ((error.code && lastReport.code === error.code) || lastReport.message == error.message)) return exitFunc(error); // Reported the same error two shortly, at least 2 minutes => ignore to avoid flooding with the same emails } } const logObj = { code: error.code, message: error.message, when: curDateTime }; await kfs(baseFilename, logObj); } catch (err) { debug(err); } try { await mailErrorToAdmin(message); } catch (err) { debug(err); } finally { return exitFunc(error); } } /** * Register the process error handlers * @param {*} process The process object * @param {*} fileName The file name to log the error */ function registerUnCaughtProcessErrorsHandler(process, fileName) { if (!process) return; if (fileName) logFileName = fileName; process .on('uncaughtException', async (err) => { await _handleCriticalError(err, util.format('uncaughtException:', err)); }) .on('unhandledRejection', async (reason, p) => { await _handleCriticalError(reason, util.format(reason, 'Unhandled Rejection at Promise', p)); }); } module.exports = { mailErrorToAdmin, registerUnCaughtProcessErrorsHandler }