Spaces:
Paused
Paused
| /** | |
| * Crash logger | |
| * Pokemon Showdown - http://pokemonshowdown.com/ | |
| * | |
| * Logs crashes, sends an e-mail notification if you've set up | |
| * config.js to do that. | |
| * | |
| * @license MIT | |
| */ | |
| import * as fs from 'fs'; | |
| import * as path from 'path'; | |
| const CRASH_EMAIL_THROTTLE = 5 * 60 * 1000; // 5 minutes | |
| const logPath = path.resolve( | |
| // not sure why this is necessary, but in Windows testing it was | |
| __dirname, '../', __dirname.includes(`${path.sep}dist${path.sep}`) ? '..' : '', | |
| path.join((global as any).Config?.logsdir || 'logs', 'errors.txt') | |
| ); | |
| let lastCrashLog = 0; | |
| let transport: any; | |
| /** | |
| * Logs when a crash happens to console, then e-mails those who are configured | |
| * to receive them. | |
| */ | |
| export function crashlogger( | |
| error: unknown, | |
| description: string, | |
| data: AnyObject | null = null, | |
| emailConfig: AnyObject | null = null, | |
| ): string | null { | |
| const datenow = Date.now(); | |
| let stack = (typeof error === 'string' ? error : (error as Error)?.stack) || ''; | |
| if (data) { | |
| stack += `\n\nAdditional information:\n`; | |
| for (const k in data) { | |
| stack += ` ${k} = ${data[k]}\n`; | |
| } | |
| } | |
| console.error(`\nCRASH: ${stack}\n`); | |
| const out = fs.createWriteStream(logPath, { flags: 'a' }); | |
| out.on('open', () => { | |
| out.write(`\n${stack}\n`); | |
| out.end(); | |
| }).on('error', (err: Error) => { | |
| console.error(`\nSUBCRASH: ${err.stack}\n`); | |
| }); | |
| const emailOpts = emailConfig || (global as any).Config?.crashguardemail; | |
| if (emailOpts && ((datenow - lastCrashLog) > CRASH_EMAIL_THROTTLE)) { | |
| lastCrashLog = datenow; | |
| if (!transport) { | |
| try { | |
| require.resolve('nodemailer'); | |
| } catch { | |
| throw new Error( | |
| 'nodemailer is not installed, but it is required if Config.crashguardemail is configured! ' + | |
| 'Run npm install --no-save nodemailer and restart the server.' | |
| ); | |
| } | |
| } | |
| let text = `${description} crashed `; | |
| if (transport) { | |
| text += `again with this stack trace:\n${stack}`; | |
| } else { | |
| try { | |
| transport = require('nodemailer').createTransport(emailOpts.options); | |
| } catch { | |
| throw new Error("Failed to start nodemailer; are you sure you've configured Config.crashguardemail correctly?"); | |
| } | |
| text += `with this stack trace:\n${stack}`; | |
| } | |
| transport.sendMail({ | |
| from: emailOpts.from, | |
| to: emailOpts.to, | |
| subject: emailOpts.subject, | |
| text, | |
| }, (err: Error | null) => { | |
| if (err) console.error(`Error sending email: ${err}`); | |
| }); | |
| } | |
| return null; | |
| } | |