'use strict'; const mailer = require('nodemailer'); const os = require('os'); /** * SMTP Appender. Sends logging events using SMTP protocol. * It can either send an email on each event or group several * logging events gathered during specified interval. * * @param _config appender configuration data * config.sendInterval time between log emails (in seconds), if 0 * then every event sends an email * config.shutdownTimeout time to give up remaining emails (in seconds; defaults to 5). * @param _layout a function that takes a logevent and returns a string (defaults to basicLayout). */ function smtpAppender(config, layout, subjectLayout) { if (!config.attachment) { config.attachment = {}; } config.attachment.enable = !!config.attachment.enable; config.attachment.message = config.attachment.message || 'See logs as attachment'; config.attachment.filename = config.attachment.filename || 'default.log'; const sendInterval = config.sendInterval * 1000 || 0; const shutdownTimeout = ('shutdownTimeout' in config ? config.shutdownTimeout : 5) * 1000; const transport = mailer.createTransport(getTransportOptions()); const logEventBuffer = []; let unsentCount = 0; let sendTimer; function sendBuffer() { if (logEventBuffer.length > 0) { const firstEvent = logEventBuffer[0]; let body = ''; const count = logEventBuffer.length; while (logEventBuffer.length > 0) { body += `${layout(logEventBuffer.shift(), config.timezoneOffset)}\n`; } const msg = { to: config.recipients, subject: config.subject || subjectLayout(firstEvent), headers: { Hostname: os.hostname() } }; if (config.attachment.enable === true) { msg[config.html ? 'html' : 'text'] = config.attachment.message; msg.attachments = [ { filename: config.attachment.filename, contentType: 'text/x-log', content: body } ]; } else { msg[config.html ? 'html' : 'text'] = body; } if (config.sender) { msg.from = config.sender; } transport.sendMail(msg, (error) => { if (error) { console.error('log4js.smtpAppender - Error happened', error); } transport.close(); unsentCount -= count; }); } } function getTransportOptions() { let options = null; if (config.SMTP) { options = config.SMTP; } else if (config.transport) { options = config.transport.options || {}; options.transport = config.transport.plugin || 'smtp'; } return options; } function scheduleSend() { if (!sendTimer) { sendTimer = setTimeout(() => { sendTimer = null; sendBuffer(); }, sendInterval); } } function shutdown(cb) { if (shutdownTimeout > 0) { setTimeout(() => { if (sendTimer) { clearTimeout(sendTimer); } sendBuffer(); }, shutdownTimeout); } (function checkDone() { if (unsentCount > 0) { setTimeout(checkDone, 100); } else { cb(); } }()); } const appender = (loggingEvent) => { unsentCount++; // eslint-disable-line no-plusplus logEventBuffer.push(loggingEvent); if (sendInterval > 0) { scheduleSend(); } else { sendBuffer(); } }; appender.shutdown = shutdown; return appender; } function configure(config, layouts) { const subjectLayout = layouts.messagePassThroughLayout; let layout = layouts.basicLayout; if (config.layout) { layout = layouts.layout(config.layout.type, config.layout); } return smtpAppender(config, layout, subjectLayout); } module.exports.configure = configure;