const flatted = require('flatted'); const levels = require('./levels'); /** * @name LoggingEvent * @namespace Log4js */ class LoggingEvent { /** * Models a logging event. * @constructor * @param {string} categoryName name of category * @param {Log4js.Level} level level of message * @param {Array} data objects to log * @author Seth Chisamore */ constructor(categoryName, level, data, context, location) { this.startTime = new Date(); this.categoryName = categoryName; this.data = data; this.level = level; this.context = Object.assign({}, context); // eslint-disable-line prefer-object-spread this.pid = process.pid; if (location) { this.functionName = location.functionName; this.fileName = location.fileName; this.lineNumber = location.lineNumber; this.columnNumber = location.columnNumber; this.callStack = location.callStack; } } serialise() { return flatted.stringify(this, (key, value) => { // JSON.stringify(new Error('test')) returns {}, which is not really useful for us. // The following allows us to serialize errors correctly. // duck-typing for Error object if (value && value.message && value.stack) { // eslint-disable-next-line prefer-object-spread value = Object.assign( { message: value.message, stack: value.stack }, value ); } // JSON.stringify({a: parseInt('abc'), b: 1/0, c: -1/0}) returns {a: null, b: null, c: null}. // The following allows us to serialize to NaN, Infinity and -Infinity correctly. else if ( typeof value === 'number' && (Number.isNaN(value) || !Number.isFinite(value)) ) { value = value.toString(); } // JSON.stringify([undefined]) returns [null]. // The following allows us to serialize to undefined correctly. else if (typeof value === 'undefined') { value = typeof value; } return value; }); } static deserialise(serialised) { let event; try { const rehydratedEvent = flatted.parse(serialised, (key, value) => { if (value && value.message && value.stack) { const fakeError = new Error(value); Object.keys(value).forEach((k) => { fakeError[k] = value[k]; }); value = fakeError; } return value; }); rehydratedEvent.location = { functionName: rehydratedEvent.functionName, fileName: rehydratedEvent.fileName, lineNumber: rehydratedEvent.lineNumber, columnNumber: rehydratedEvent.columnNumber, callStack: rehydratedEvent.callStack, }; event = new LoggingEvent( rehydratedEvent.categoryName, levels.getLevel(rehydratedEvent.level.levelStr), rehydratedEvent.data, rehydratedEvent.context, rehydratedEvent.location ); event.startTime = new Date(rehydratedEvent.startTime); event.pid = rehydratedEvent.pid; event.cluster = rehydratedEvent.cluster; } catch (e) { event = new LoggingEvent('log4js', levels.ERROR, [ 'Unable to parse log:', serialised, 'because: ', e, ]); } return event; } } module.exports = LoggingEvent;