158 lines
4.3 KiB
JavaScript
158 lines
4.3 KiB
JavaScript
|
/* eslint max-classes-per-file: ["error", 2] */
|
||
|
/* eslint no-underscore-dangle: ["error", { "allow": ["_getLocationKeys"] }] */
|
||
|
|
||
|
const flatted = require('flatted');
|
||
|
const levels = require('./levels');
|
||
|
|
||
|
class SerDe {
|
||
|
constructor() {
|
||
|
const deserialise = {
|
||
|
__LOG4JS_undefined__: undefined,
|
||
|
__LOG4JS_NaN__: Number('abc'),
|
||
|
__LOG4JS_Infinity__: 1 / 0,
|
||
|
'__LOG4JS_-Infinity__': -1 / 0,
|
||
|
};
|
||
|
this.deMap = deserialise;
|
||
|
this.serMap = {};
|
||
|
Object.keys(this.deMap).forEach((key) => {
|
||
|
const value = this.deMap[key];
|
||
|
this.serMap[value] = key;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
canSerialise(key) {
|
||
|
if (typeof key === 'string') return false;
|
||
|
return key in this.serMap;
|
||
|
}
|
||
|
|
||
|
serialise(key) {
|
||
|
if (this.canSerialise(key)) return this.serMap[key];
|
||
|
return key;
|
||
|
}
|
||
|
|
||
|
canDeserialise(key) {
|
||
|
return key in this.deMap;
|
||
|
}
|
||
|
|
||
|
deserialise(key) {
|
||
|
if (this.canDeserialise(key)) return this.deMap[key];
|
||
|
return key;
|
||
|
}
|
||
|
}
|
||
|
const serde = new SerDe();
|
||
|
|
||
|
/**
|
||
|
* @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
|
||
|
* @param {Error} [error]
|
||
|
* @author Seth Chisamore
|
||
|
*/
|
||
|
constructor(categoryName, level, data, context, location, error) {
|
||
|
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;
|
||
|
this.error = error;
|
||
|
|
||
|
if (typeof location !== 'undefined') {
|
||
|
if (!location || typeof location !== 'object' || Array.isArray(location))
|
||
|
throw new TypeError(
|
||
|
'Invalid location type passed to LoggingEvent constructor'
|
||
|
);
|
||
|
|
||
|
this.constructor._getLocationKeys().forEach((key) => {
|
||
|
if (typeof location[key] !== 'undefined') this[key] = location[key];
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** @private */
|
||
|
static _getLocationKeys() {
|
||
|
return [
|
||
|
'fileName',
|
||
|
'lineNumber',
|
||
|
'columnNumber',
|
||
|
'callStack',
|
||
|
'className',
|
||
|
'functionName',
|
||
|
'functionAlias',
|
||
|
'callerName',
|
||
|
];
|
||
|
}
|
||
|
|
||
|
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 (semi) correctly.
|
||
|
if (value instanceof Error) {
|
||
|
// eslint-disable-next-line prefer-object-spread
|
||
|
value = Object.assign(
|
||
|
{ message: value.message, stack: value.stack },
|
||
|
value
|
||
|
);
|
||
|
}
|
||
|
// JSON.stringify({a: Number('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.
|
||
|
// JSON.stringify([undefined]) returns [null].
|
||
|
// The following allows us to serialize to undefined correctly.
|
||
|
return serde.serialise(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 serde.deserialise(value);
|
||
|
});
|
||
|
this._getLocationKeys().forEach((key) => {
|
||
|
if (typeof rehydratedEvent[key] !== 'undefined') {
|
||
|
if (!rehydratedEvent.location) rehydratedEvent.location = {};
|
||
|
rehydratedEvent.location[key] = rehydratedEvent[key];
|
||
|
}
|
||
|
});
|
||
|
event = new LoggingEvent(
|
||
|
rehydratedEvent.categoryName,
|
||
|
levels.getLevel(rehydratedEvent.level.levelStr),
|
||
|
rehydratedEvent.data,
|
||
|
rehydratedEvent.context,
|
||
|
rehydratedEvent.location,
|
||
|
rehydratedEvent.error
|
||
|
);
|
||
|
event.startTime = new Date(rehydratedEvent.startTime);
|
||
|
event.pid = rehydratedEvent.pid;
|
||
|
if (rehydratedEvent.cluster) {
|
||
|
event.cluster = rehydratedEvent.cluster;
|
||
|
}
|
||
|
} catch (e) {
|
||
|
event = new LoggingEvent('log4js', levels.ERROR, [
|
||
|
'Unable to parse log:',
|
||
|
serialised,
|
||
|
'because: ',
|
||
|
e,
|
||
|
]);
|
||
|
}
|
||
|
|
||
|
return event;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module.exports = LoggingEvent;
|