logjs4 0.0.1-security → 6.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of logjs4 might be problematic. Click here for more details.

package/lib/layouts.js ADDED
@@ -0,0 +1,486 @@
1
+ const dateFormat = require('date-format');
2
+ const os = require('os');
3
+ const util = require('util');
4
+ const path = require('path');
5
+ const url = require('url');
6
+ const debug = require('debug')('log4js:layouts');
7
+
8
+ const styles = {
9
+ // styles
10
+ bold: [1, 22],
11
+ italic: [3, 23],
12
+ underline: [4, 24],
13
+ inverse: [7, 27],
14
+ // grayscale
15
+ white: [37, 39],
16
+ grey: [90, 39],
17
+ black: [90, 39],
18
+ // colors
19
+ blue: [34, 39],
20
+ cyan: [36, 39],
21
+ green: [32, 39],
22
+ magenta: [35, 39],
23
+ red: [91, 39],
24
+ yellow: [33, 39],
25
+ };
26
+
27
+ function colorizeStart(style) {
28
+ return style ? `\x1B[${styles[style][0]}m` : '';
29
+ }
30
+
31
+ function colorizeEnd(style) {
32
+ return style ? `\x1B[${styles[style][1]}m` : '';
33
+ }
34
+
35
+ /**
36
+ * Taken from masylum's fork (https://github.com/masylum/log4js-node)
37
+ */
38
+ function colorize(str, style) {
39
+ return colorizeStart(style) + str + colorizeEnd(style);
40
+ }
41
+
42
+ function timestampLevelAndCategory(loggingEvent, colour) {
43
+ return colorize(
44
+ util.format(
45
+ '[%s] [%s] %s - ',
46
+ dateFormat.asString(loggingEvent.startTime),
47
+ loggingEvent.level.toString(),
48
+ loggingEvent.categoryName
49
+ ),
50
+ colour
51
+ );
52
+ }
53
+
54
+ /**
55
+ * BasicLayout is a simple layout for storing the logs. The logs are stored
56
+ * in following format:
57
+ * <pre>
58
+ * [startTime] [logLevel] categoryName - message\n
59
+ * </pre>
60
+ *
61
+ * @author Stephan Strittmatter
62
+ */
63
+ function basicLayout(loggingEvent) {
64
+ return (
65
+ timestampLevelAndCategory(loggingEvent) + util.format(...loggingEvent.data)
66
+ );
67
+ }
68
+
69
+ /**
70
+ * colouredLayout - taken from masylum's fork.
71
+ * same as basicLayout, but with colours.
72
+ */
73
+ function colouredLayout(loggingEvent) {
74
+ return (
75
+ timestampLevelAndCategory(loggingEvent, loggingEvent.level.colour) +
76
+ util.format(...loggingEvent.data)
77
+ );
78
+ }
79
+
80
+ function messagePassThroughLayout(loggingEvent) {
81
+ return util.format(...loggingEvent.data);
82
+ }
83
+
84
+ function dummyLayout(loggingEvent) {
85
+ return loggingEvent.data[0];
86
+ }
87
+
88
+ /**
89
+ * PatternLayout
90
+ * Format for specifiers is %[padding].[truncation][field]{[format]}
91
+ * e.g. %5.10p - left pad the log level by 5 characters, up to a max of 10
92
+ * both padding and truncation can be negative.
93
+ * Negative truncation = trunc from end of string
94
+ * Positive truncation = trunc from start of string
95
+ * Negative padding = pad right
96
+ * Positive padding = pad left
97
+ *
98
+ * Fields can be any of:
99
+ * - %r time in toLocaleTimeString format
100
+ * - %p log level
101
+ * - %c log category
102
+ * - %h hostname
103
+ * - %m log data
104
+ * - %m{l} where l is an integer, log data.slice(l)
105
+ * - %m{l,u} where l and u are integers, log data.slice(l, u)
106
+ * - %d date in constious formats
107
+ * - %% %
108
+ * - %n newline
109
+ * - %z pid
110
+ * - %f filename
111
+ * - %l line number
112
+ * - %o column postion
113
+ * - %s call stack
114
+ * - %C class name [#1316](https://github.com/log4js-node/log4js-node/pull/1316)
115
+ * - %M method or function name [#1316](https://github.com/log4js-node/log4js-node/pull/1316)
116
+ * - %A method or function alias [#1316](https://github.com/log4js-node/log4js-node/pull/1316)
117
+ * - %F fully qualified caller name [#1316](https://github.com/log4js-node/log4js-node/pull/1316)
118
+ * - %x{<tokenname>} add dynamic tokens to your log. Tokens are specified in the tokens parameter
119
+ * - %X{<tokenname>} add dynamic tokens to your log. Tokens are specified in logger context
120
+ * You can use %[ and %] to define a colored block.
121
+ *
122
+ * Tokens are specified as simple key:value objects.
123
+ * The key represents the token name whereas the value can be a string or function
124
+ * which is called to extract the value to put in the log message. If token is not
125
+ * found, it doesn't replace the field.
126
+ *
127
+ * A sample token would be: { 'pid' : function() { return process.pid; } }
128
+ *
129
+ * Takes a pattern string, array of tokens and returns a layout function.
130
+ * @return {Function}
131
+ * @param pattern
132
+ * @param tokens
133
+ * @param timezoneOffset
134
+ *
135
+ * @authors ['Stephan Strittmatter', 'Jan Schmidle']
136
+ */
137
+ function patternLayout(pattern, tokens) {
138
+ const TTCC_CONVERSION_PATTERN = '%r %p %c - %m%n';
139
+ const regex =
140
+ /%(-?[0-9]+)?(\.?-?[0-9]+)?([[\]cdhmnprzxXyflosCMAF%])(\{([^}]+)\})?|([^%]+)/;
141
+
142
+ pattern = pattern || TTCC_CONVERSION_PATTERN;
143
+
144
+ function categoryName(loggingEvent, specifier) {
145
+ let loggerName = loggingEvent.categoryName;
146
+ if (specifier) {
147
+ const precision = parseInt(specifier, 10);
148
+ const loggerNameBits = loggerName.split('.');
149
+ if (precision < loggerNameBits.length) {
150
+ loggerName = loggerNameBits
151
+ .slice(loggerNameBits.length - precision)
152
+ .join('.');
153
+ }
154
+ }
155
+ return loggerName;
156
+ }
157
+
158
+ function formatAsDate(loggingEvent, specifier) {
159
+ let format = dateFormat.ISO8601_FORMAT;
160
+ if (specifier) {
161
+ format = specifier;
162
+ // Pick up special cases
163
+ switch (format) {
164
+ case 'ISO8601':
165
+ case 'ISO8601_FORMAT':
166
+ format = dateFormat.ISO8601_FORMAT;
167
+ break;
168
+ case 'ISO8601_WITH_TZ_OFFSET':
169
+ case 'ISO8601_WITH_TZ_OFFSET_FORMAT':
170
+ format = dateFormat.ISO8601_WITH_TZ_OFFSET_FORMAT;
171
+ break;
172
+ case 'ABSOLUTE':
173
+ process.emitWarning(
174
+ 'Pattern %d{ABSOLUTE} is deprecated in favor of %d{ABSOLUTETIME}. ' +
175
+ 'Please use %d{ABSOLUTETIME} instead.',
176
+ 'DeprecationWarning',
177
+ 'log4js-node-DEP0003'
178
+ );
179
+ debug(
180
+ '[log4js-node-DEP0003]',
181
+ 'DEPRECATION: Pattern %d{ABSOLUTE} is deprecated and replaced by %d{ABSOLUTETIME}.'
182
+ );
183
+ // falls through
184
+ case 'ABSOLUTETIME':
185
+ case 'ABSOLUTETIME_FORMAT':
186
+ format = dateFormat.ABSOLUTETIME_FORMAT;
187
+ break;
188
+ case 'DATE':
189
+ process.emitWarning(
190
+ 'Pattern %d{DATE} is deprecated due to the confusion it causes when used. ' +
191
+ 'Please use %d{DATETIME} instead.',
192
+ 'DeprecationWarning',
193
+ 'log4js-node-DEP0004'
194
+ );
195
+ debug(
196
+ '[log4js-node-DEP0004]',
197
+ 'DEPRECATION: Pattern %d{DATE} is deprecated and replaced by %d{DATETIME}.'
198
+ );
199
+ // falls through
200
+ case 'DATETIME':
201
+ case 'DATETIME_FORMAT':
202
+ format = dateFormat.DATETIME_FORMAT;
203
+ break;
204
+ // no default
205
+ }
206
+ }
207
+ // Format the date
208
+ return dateFormat.asString(format, loggingEvent.startTime);
209
+ }
210
+
211
+ function hostname() {
212
+ return os.hostname().toString();
213
+ }
214
+
215
+ function formatMessage(loggingEvent, specifier) {
216
+ let dataSlice = loggingEvent.data;
217
+ if (specifier) {
218
+ const [lowerBound, upperBound] = specifier.split(',');
219
+ dataSlice = dataSlice.slice(lowerBound, upperBound);
220
+ }
221
+ return util.format(...dataSlice);
222
+ }
223
+
224
+ function endOfLine() {
225
+ return os.EOL;
226
+ }
227
+
228
+ function logLevel(loggingEvent) {
229
+ return loggingEvent.level.toString();
230
+ }
231
+
232
+ function startTime(loggingEvent) {
233
+ return dateFormat.asString('hh:mm:ss', loggingEvent.startTime);
234
+ }
235
+
236
+ function startColour(loggingEvent) {
237
+ return colorizeStart(loggingEvent.level.colour);
238
+ }
239
+
240
+ function endColour(loggingEvent) {
241
+ return colorizeEnd(loggingEvent.level.colour);
242
+ }
243
+
244
+ function percent() {
245
+ return '%';
246
+ }
247
+
248
+ function pid(loggingEvent) {
249
+ return loggingEvent && loggingEvent.pid
250
+ ? loggingEvent.pid.toString()
251
+ : process.pid.toString();
252
+ }
253
+
254
+ function clusterInfo() {
255
+ // this used to try to return the master and worker pids,
256
+ // but it would never have worked because master pid is not available to workers
257
+ // leaving this here to maintain compatibility for patterns
258
+ return pid();
259
+ }
260
+
261
+ function userDefined(loggingEvent, specifier) {
262
+ if (typeof tokens[specifier] !== 'undefined') {
263
+ return typeof tokens[specifier] === 'function'
264
+ ? tokens[specifier](loggingEvent)
265
+ : tokens[specifier];
266
+ }
267
+
268
+ return null;
269
+ }
270
+
271
+ function contextDefined(loggingEvent, specifier) {
272
+ const resolver = loggingEvent.context[specifier];
273
+
274
+ if (typeof resolver !== 'undefined') {
275
+ return typeof resolver === 'function' ? resolver(loggingEvent) : resolver;
276
+ }
277
+
278
+ return null;
279
+ }
280
+
281
+ function fileName(loggingEvent, specifier) {
282
+ let filename = loggingEvent.fileName || '';
283
+
284
+ // support for ESM as it uses url instead of path for file
285
+ /* istanbul ignore next: unsure how to simulate ESM for test coverage */
286
+ const convertFileURLToPath = function (filepath) {
287
+ const urlPrefix = 'file://';
288
+ if (filepath.startsWith(urlPrefix)) {
289
+ // https://nodejs.org/api/url.html#urlfileurltopathurl
290
+ if (typeof url.fileURLToPath === 'function') {
291
+ filepath = url.fileURLToPath(filepath);
292
+ }
293
+ // backward-compatible for nodejs pre-10.12.0 (without url.fileURLToPath method)
294
+ else {
295
+ // posix: file:///hello/world/foo.txt -> /hello/world/foo.txt -> /hello/world/foo.txt
296
+ // win32: file:///C:/path/foo.txt -> /C:/path/foo.txt -> \C:\path\foo.txt -> C:\path\foo.txt
297
+ // win32: file://nas/foo.txt -> //nas/foo.txt -> nas\foo.txt -> \\nas\foo.txt
298
+ filepath = path.normalize(
299
+ filepath.replace(new RegExp(`^${urlPrefix}`), '')
300
+ );
301
+ if (process.platform === 'win32') {
302
+ if (filepath.startsWith('\\')) {
303
+ filepath = filepath.slice(1);
304
+ } else {
305
+ filepath = path.sep + path.sep + filepath;
306
+ }
307
+ }
308
+ }
309
+ }
310
+ return filepath;
311
+ };
312
+ filename = convertFileURLToPath(filename);
313
+
314
+ if (specifier) {
315
+ const fileDepth = parseInt(specifier, 10);
316
+ const fileList = filename.split(path.sep);
317
+ if (fileList.length > fileDepth) {
318
+ filename = fileList.slice(-fileDepth).join(path.sep);
319
+ }
320
+ }
321
+
322
+ return filename;
323
+ }
324
+
325
+ function lineNumber(loggingEvent) {
326
+ return loggingEvent.lineNumber ? `${loggingEvent.lineNumber}` : '';
327
+ }
328
+
329
+ function columnNumber(loggingEvent) {
330
+ return loggingEvent.columnNumber ? `${loggingEvent.columnNumber}` : '';
331
+ }
332
+
333
+ function callStack(loggingEvent) {
334
+ return loggingEvent.callStack || '';
335
+ }
336
+
337
+ function className(loggingEvent) {
338
+ return loggingEvent.className || '';
339
+ }
340
+
341
+ function functionName(loggingEvent) {
342
+ return loggingEvent.functionName || '';
343
+ }
344
+
345
+ function functionAlias(loggingEvent) {
346
+ return loggingEvent.functionAlias || '';
347
+ }
348
+
349
+ function callerName(loggingEvent) {
350
+ return loggingEvent.callerName || '';
351
+ }
352
+
353
+ const replacers = {
354
+ c: categoryName,
355
+ d: formatAsDate,
356
+ h: hostname,
357
+ m: formatMessage,
358
+ n: endOfLine,
359
+ p: logLevel,
360
+ r: startTime,
361
+ '[': startColour,
362
+ ']': endColour,
363
+ y: clusterInfo,
364
+ z: pid,
365
+ '%': percent,
366
+ x: userDefined,
367
+ X: contextDefined,
368
+ f: fileName,
369
+ l: lineNumber,
370
+ o: columnNumber,
371
+ s: callStack,
372
+ C: className,
373
+ M: functionName,
374
+ A: functionAlias,
375
+ F: callerName,
376
+ };
377
+
378
+ function replaceToken(conversionCharacter, loggingEvent, specifier) {
379
+ return replacers[conversionCharacter](loggingEvent, specifier);
380
+ }
381
+
382
+ function truncate(truncation, toTruncate) {
383
+ let len;
384
+ if (truncation) {
385
+ len = parseInt(truncation.slice(1), 10);
386
+ // negative truncate length means truncate from end of string
387
+ return len > 0 ? toTruncate.slice(0, len) : toTruncate.slice(len);
388
+ }
389
+
390
+ return toTruncate;
391
+ }
392
+
393
+ function pad(padding, toPad) {
394
+ let len;
395
+ if (padding) {
396
+ if (padding.charAt(0) === '-') {
397
+ len = parseInt(padding.slice(1), 10);
398
+ // Right pad with spaces
399
+ while (toPad.length < len) {
400
+ toPad += ' ';
401
+ }
402
+ } else {
403
+ len = parseInt(padding, 10);
404
+ // Left pad with spaces
405
+ while (toPad.length < len) {
406
+ toPad = ` ${toPad}`;
407
+ }
408
+ }
409
+ }
410
+ return toPad;
411
+ }
412
+
413
+ function truncateAndPad(toTruncAndPad, truncation, padding) {
414
+ let replacement = toTruncAndPad;
415
+ replacement = truncate(truncation, replacement);
416
+ replacement = pad(padding, replacement);
417
+ return replacement;
418
+ }
419
+
420
+ return function (loggingEvent) {
421
+ let formattedString = '';
422
+ let result;
423
+ let searchString = pattern;
424
+
425
+ while ((result = regex.exec(searchString)) !== null) {
426
+ // const matchedString = result[0];
427
+ const padding = result[1];
428
+ const truncation = result[2];
429
+ const conversionCharacter = result[3];
430
+ const specifier = result[5];
431
+ const text = result[6];
432
+
433
+ // Check if the pattern matched was just normal text
434
+ if (text) {
435
+ formattedString += text.toString();
436
+ } else {
437
+ // Create a raw replacement string based on the conversion
438
+ // character and specifier
439
+ const replacement = replaceToken(
440
+ conversionCharacter,
441
+ loggingEvent,
442
+ specifier
443
+ );
444
+ formattedString += truncateAndPad(replacement, truncation, padding);
445
+ }
446
+ searchString = searchString.slice(result.index + result[0].length);
447
+ }
448
+ return formattedString;
449
+ };
450
+ }
451
+
452
+ const layoutMakers = {
453
+ messagePassThrough() {
454
+ return messagePassThroughLayout;
455
+ },
456
+ basic() {
457
+ return basicLayout;
458
+ },
459
+ colored() {
460
+ return colouredLayout;
461
+ },
462
+ coloured() {
463
+ return colouredLayout;
464
+ },
465
+ pattern(config) {
466
+ return patternLayout(config && config.pattern, config && config.tokens);
467
+ },
468
+ dummy() {
469
+ return dummyLayout;
470
+ },
471
+ };
472
+
473
+ module.exports = {
474
+ basicLayout,
475
+ messagePassThroughLayout,
476
+ patternLayout,
477
+ colouredLayout,
478
+ coloredLayout: colouredLayout,
479
+ dummyLayout,
480
+ addLayout(name, serializerGenerator) {
481
+ layoutMakers[name] = serializerGenerator;
482
+ },
483
+ layout(name, config) {
484
+ return layoutMakers[name] && layoutMakers[name](config);
485
+ },
486
+ };
package/lib/levels.js ADDED
@@ -0,0 +1,155 @@
1
+ const configuration = require('./configuration');
2
+
3
+ const validColours = [
4
+ 'white',
5
+ 'grey',
6
+ 'black',
7
+ 'blue',
8
+ 'cyan',
9
+ 'green',
10
+ 'magenta',
11
+ 'red',
12
+ 'yellow',
13
+ ];
14
+
15
+ class Level {
16
+ constructor(level, levelStr, colour) {
17
+ this.level = level;
18
+ this.levelStr = levelStr;
19
+ this.colour = colour;
20
+ }
21
+
22
+ toString() {
23
+ return this.levelStr;
24
+ }
25
+
26
+ /**
27
+ * converts given String to corresponding Level
28
+ * @param {(Level|string)} sArg -- String value of Level OR Log4js.Level
29
+ * @param {Level} [defaultLevel] -- default Level, if no String representation
30
+ * @return {Level}
31
+ */
32
+ static getLevel(sArg, defaultLevel) {
33
+ if (!sArg) {
34
+ return defaultLevel;
35
+ }
36
+
37
+ if (sArg instanceof Level) {
38
+ return sArg;
39
+ }
40
+
41
+ // a json-serialised level won't be an instance of Level (see issue #768)
42
+ if (sArg instanceof Object && sArg.levelStr) {
43
+ sArg = sArg.levelStr;
44
+ }
45
+
46
+ return Level[sArg.toString().toUpperCase()] || defaultLevel;
47
+ }
48
+
49
+ static addLevels(customLevels) {
50
+ if (customLevels) {
51
+ const levels = Object.keys(customLevels);
52
+ levels.forEach((l) => {
53
+ const levelStr = l.toUpperCase();
54
+ Level[levelStr] = new Level(
55
+ customLevels[l].value,
56
+ levelStr,
57
+ customLevels[l].colour
58
+ );
59
+ const existingLevelIndex = Level.levels.findIndex(
60
+ (lvl) => lvl.levelStr === levelStr
61
+ );
62
+ if (existingLevelIndex > -1) {
63
+ Level.levels[existingLevelIndex] = Level[levelStr];
64
+ } else {
65
+ Level.levels.push(Level[levelStr]);
66
+ }
67
+ });
68
+ Level.levels.sort((a, b) => a.level - b.level);
69
+ }
70
+ }
71
+
72
+ isLessThanOrEqualTo(otherLevel) {
73
+ if (typeof otherLevel === 'string') {
74
+ otherLevel = Level.getLevel(otherLevel);
75
+ }
76
+ return this.level <= otherLevel.level;
77
+ }
78
+
79
+ isGreaterThanOrEqualTo(otherLevel) {
80
+ if (typeof otherLevel === 'string') {
81
+ otherLevel = Level.getLevel(otherLevel);
82
+ }
83
+ return this.level >= otherLevel.level;
84
+ }
85
+
86
+ isEqualTo(otherLevel) {
87
+ if (typeof otherLevel === 'string') {
88
+ otherLevel = Level.getLevel(otherLevel);
89
+ }
90
+ return this.level === otherLevel.level;
91
+ }
92
+ }
93
+
94
+ Level.levels = [];
95
+ Level.addLevels({
96
+ ALL: { value: Number.MIN_VALUE, colour: 'grey' },
97
+ TRACE: { value: 5000, colour: 'blue' },
98
+ DEBUG: { value: 10000, colour: 'cyan' },
99
+ INFO: { value: 20000, colour: 'green' },
100
+ WARN: { value: 30000, colour: 'yellow' },
101
+ ERROR: { value: 40000, colour: 'red' },
102
+ FATAL: { value: 50000, colour: 'magenta' },
103
+ MARK: { value: 9007199254740992, colour: 'grey' }, // 2^53
104
+ OFF: { value: Number.MAX_VALUE, colour: 'grey' },
105
+ });
106
+
107
+ configuration.addListener((config) => {
108
+ const levelConfig = config.levels;
109
+ if (levelConfig) {
110
+ configuration.throwExceptionIf(
111
+ config,
112
+ configuration.not(configuration.anObject(levelConfig)),
113
+ 'levels must be an object'
114
+ );
115
+ const newLevels = Object.keys(levelConfig);
116
+ newLevels.forEach((l) => {
117
+ configuration.throwExceptionIf(
118
+ config,
119
+ configuration.not(configuration.validIdentifier(l)),
120
+ `level name "${l}" is not a valid identifier (must start with a letter, only contain A-Z,a-z,0-9,_)`
121
+ );
122
+ configuration.throwExceptionIf(
123
+ config,
124
+ configuration.not(configuration.anObject(levelConfig[l])),
125
+ `level "${l}" must be an object`
126
+ );
127
+ configuration.throwExceptionIf(
128
+ config,
129
+ configuration.not(levelConfig[l].value),
130
+ `level "${l}" must have a 'value' property`
131
+ );
132
+ configuration.throwExceptionIf(
133
+ config,
134
+ configuration.not(configuration.anInteger(levelConfig[l].value)),
135
+ `level "${l}".value must have an integer value`
136
+ );
137
+ configuration.throwExceptionIf(
138
+ config,
139
+ configuration.not(levelConfig[l].colour),
140
+ `level "${l}" must have a 'colour' property`
141
+ );
142
+ configuration.throwExceptionIf(
143
+ config,
144
+ configuration.not(validColours.indexOf(levelConfig[l].colour) > -1),
145
+ `level "${l}".colour must be one of ${validColours.join(', ')}`
146
+ );
147
+ });
148
+ }
149
+ });
150
+
151
+ configuration.addListener((config) => {
152
+ Level.addLevels(config.levels);
153
+ });
154
+
155
+ module.exports = Level;