3 const jsonReplacers
= require('./json-replacers');
4 const dataSanitizers
= require('./data-sanitizers');
7 * Log as JSON to stdout/stderr.
10 const nop
= () => { /**/ };
15 * Wrap backend calls with payload normalization.
16 * @param {Object} options
17 * @param {String} options.nodeId - unique identifier for running instance, usually a uuid
18 * @param {Object} options.logger
19 * @param {String} options.logger.ignoreBelowLevel - minimum level to log
21 constructor(options
) {
22 const logLevels
= Object
.keys(Logger
.nullLogger
);
23 const ignoreBelowLevel
= options
&& options
.logger
&& options
.logger
.ignoreBelowLevel
|| 'debug';
24 this.backend
= console
;
25 this.nodeId
= options
.nodeId
;
26 this.jsonReplacers
= Object
.values(jsonReplacers
);
27 this.dataSanitizers
= Object
.values(dataSanitizers
);
29 if (!logLevels
.includes(ignoreBelowLevel
)) {
30 throw new RangeError(`unrecognized minimum log level '${ignoreBelowLevel}'`);
32 const ignoreLevelIdx
= logLevels
.indexOf(ignoreBelowLevel
);
33 logLevels
.forEach((level
) => {
34 // eslint-disable-next-line security/detect-object-injection
35 this[level
] = (logLevels
.indexOf(level
) > ignoreLevelIdx
) ?
37 (...args
) => this.backend
[level
](this.payload(level
, ...args
)); // eslint-disable-line security/detect-object-injection
43 * All the expected Console levels, but do nothing.
44 * Ordered from highest priority to lowest.
46 static get nullLogger() {
58 * Structure all expected log data into JSON string.
59 * @param {String} level
60 * @param {String} scope
61 * @param {String} message
62 * @param {Object} data
63 * @param {...any} other
64 * @returns {String} JSON string
66 payload(level
, scope
, message
, data
, ...other
) {
67 if (this.sanitizationNeeded(data
)) {
68 // Create copy of data so we are not changing anything important.
69 data
= JSON
.parse(JSON
.stringify(data
, this.jsonReplacer
.bind(this)));
73 const now
= new Date();
74 return JSON
.stringify({
76 timestamp: now
.toISOString(),
77 timestampMs: now
.getTime(),
79 scope: scope
|| '[unknown]',
80 message: message
|| '',
82 ...(other
.length
&& { other
}),
83 }, this.jsonReplacer
.bind(this));
88 * Determine if data needs sanitizing.
89 * @param {Object} data
92 sanitizationNeeded(data
) {
93 return this.dataSanitizers
.some((sanitizer
) => sanitizer(data
, false));
99 * @param {Object} data
102 this.dataSanitizers
.forEach((sanitizer
) => sanitizer(data
));
107 * Convert data into JSON.
108 * @param {String} _key
110 * @returns {String} serialized value
112 jsonReplacer(key
, value
) {
115 // Try applying all our replacers, until one does something.
116 this.jsonReplacers
.every((replacer
) => {
117 ({ replaced
, value
} = replacer(key
, value
));
125 module
.exports
= Logger
;