zeddemore-logger 1.2.1 → 1.2.3
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.
- package/lib/date.js +4 -2
- package/lib/enums.js +22 -1
- package/lib/math.js +3 -3
- package/lib/zeddemore-logger.js +86 -28
- package/package.json +1 -1
package/lib/date.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
// Copyright (c) 2025 by Beardon Services, Inc.
|
|
2
2
|
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
3
5
|
function convertMilliseconds(milliseconds, options) {
|
|
4
6
|
options = options || { };
|
|
5
|
-
const digits = options.digits
|
|
6
|
-
const spaced = options.
|
|
7
|
+
const digits = _.isInteger(options.digits) ? options.digits : 3;
|
|
8
|
+
const spaced = _.isBoolean(options.spaced) ? options.spaced : false;
|
|
7
9
|
let value = milliseconds || 0;
|
|
8
10
|
let unit = 'ms';
|
|
9
11
|
if (milliseconds) {
|
package/lib/enums.js
CHANGED
|
@@ -119,9 +119,29 @@ const morganFormats = {
|
|
|
119
119
|
COMBINED: 'combined',
|
|
120
120
|
COMMON: 'common',
|
|
121
121
|
DEV: 'dev',
|
|
122
|
-
DEV_ENHANCED: ':method :url :status-colored :response-time-format :content-length-format',
|
|
123
122
|
SHORT: 'short',
|
|
124
123
|
TINY: 'tiny',
|
|
124
|
+
ZEDDEMORE: 'zeddemore', // added for `zeddemore-logger`
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const morganFormatTokens = {
|
|
128
|
+
CONTENT_LENGTH_FORMAT: 'content-length-format', // added for `zeddemore-logger`
|
|
129
|
+
DATE: 'date', // :date[format]
|
|
130
|
+
DECODED_URL: 'decoded-url', // added for `zeddemore-logger`
|
|
131
|
+
HTTP_VERSION: 'http-version',
|
|
132
|
+
METHOD: 'method',
|
|
133
|
+
REFERRER: 'referrer',
|
|
134
|
+
REMOTE_ADDR: 'remote-addr',
|
|
135
|
+
REMOTE_USER: 'remote-user',
|
|
136
|
+
REQ: 'req', // :req[header]
|
|
137
|
+
RES: 'res', // :res[header]
|
|
138
|
+
RESPONSE_TIME: 'response-time', // :response-time[digits]
|
|
139
|
+
RESPONSE_TIME_FORMAT: 'response-time-format', // added for `zeddemore-logger`
|
|
140
|
+
STATUS: 'status',
|
|
141
|
+
STATUS_COLORED: 'status-colored', // added for `zeddemore-logger`
|
|
142
|
+
TOTAL_TIME: 'total-time', // :total-time[digits]
|
|
143
|
+
URL: 'url',
|
|
144
|
+
USER_AGENT: 'user-agent',
|
|
125
145
|
};
|
|
126
146
|
|
|
127
147
|
const winstonLogLevelNames = {
|
|
@@ -158,6 +178,7 @@ module.exports = {
|
|
|
158
178
|
httpRequestHeaders,
|
|
159
179
|
httpResponseHeaders,
|
|
160
180
|
morganFormats,
|
|
181
|
+
morganFormatTokens,
|
|
161
182
|
winstonLogLevelNames,
|
|
162
183
|
winstonLogLevels,
|
|
163
184
|
};
|
package/lib/math.js
CHANGED
|
@@ -5,9 +5,9 @@ const _ = require('lodash');
|
|
|
5
5
|
function convertBytes(bytes, options = { }) {
|
|
6
6
|
options = options || { };
|
|
7
7
|
if (!bytes) return null;
|
|
8
|
-
const useBinaryUnits = options.useBinaryUnits
|
|
9
|
-
const decimals = options.decimals
|
|
10
|
-
const spaced = options.
|
|
8
|
+
const useBinaryUnits = _.isBoolean(options.useBinaryUnits) ? options.useBinaryUnits : false;
|
|
9
|
+
const decimals = _.isInteger(options.decimals) ? options.decimals : 2;
|
|
10
|
+
const spaced = _.isBoolean(options.spaced) ? options.spaced : false;
|
|
11
11
|
const base = useBinaryUnits ? 1024 : 1000;
|
|
12
12
|
const units = useBinaryUnits
|
|
13
13
|
? [ 'B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB' ]
|
package/lib/zeddemore-logger.js
CHANGED
|
@@ -16,10 +16,11 @@ const { extractToken, getRequestResponseTime, isRequestOfMethod, parseRequest }
|
|
|
16
16
|
const { logLevelMap } = require('./mappings/log_mappings');
|
|
17
17
|
|
|
18
18
|
const { colorize, combine, label, metadata, printf, timestamp } = format;
|
|
19
|
-
const { morganFormats: mf, httpMethods: http, httpRequestHeaders: rqh, httpResponseHeaders: rsh,
|
|
20
|
-
winstonLogLevels: wll } = enums;
|
|
19
|
+
const { morganFormats: mf, morganFormatTokens: mft, httpMethods: http, httpRequestHeaders: rqh, httpResponseHeaders: rsh,
|
|
20
|
+
winstonLogLevelNames: wlln, winstonLogLevels: wll } = enums;
|
|
21
21
|
|
|
22
22
|
const COLOR_CONSOLE_WHITE_HEX = '#ECECEC';
|
|
23
|
+
const DEFAULT_MORGAN_FORMAT_TOKENS = [ mft.METHOD, mft.DECODED_URL, mft.STATUS_COLORED, mft.RESPONSE_TIME_FORMAT, mft.CONTENT_LENGTH_FORMAT ];
|
|
23
24
|
const DEFAULT_REQUEST_ID_ATTRIBUTE = 'requestId';
|
|
24
25
|
const DEFAULT_USER_LOG_LEVEL = -1;
|
|
25
26
|
const WINSTON_CONSOLE_TRANSPORT_NAME = 'console';
|
|
@@ -35,6 +36,13 @@ function massageLogLevel(logLevel) {
|
|
|
35
36
|
return winstonLogLevelIdToName(logLevel);
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Monkey patch console to allow unlimited depth with `console.dirp`
|
|
41
|
+
*/
|
|
42
|
+
function monkeyPatchConsole() {
|
|
43
|
+
console.dirp = (arguments) => console.dir(arguments, { depth: null });
|
|
44
|
+
}
|
|
45
|
+
|
|
38
46
|
/**
|
|
39
47
|
* Convert a log level ID to a Winston log level name
|
|
40
48
|
* @param levelId {number}
|
|
@@ -51,6 +59,7 @@ class ZeddemoreLogger {
|
|
|
51
59
|
/** @type {Logger} */
|
|
52
60
|
#logger = null;
|
|
53
61
|
#logLevel = wll.INFO;
|
|
62
|
+
#morganFormat = null;
|
|
54
63
|
|
|
55
64
|
constructor(options) {
|
|
56
65
|
options = options || { };
|
|
@@ -58,21 +67,22 @@ class ZeddemoreLogger {
|
|
|
58
67
|
this.apiRouteCategories = options.apiRouteCategories || [ ];
|
|
59
68
|
this.apiRoutes = options.apiRoutes || [ ];
|
|
60
69
|
this.apiVersion = options.apiVersion || null;
|
|
70
|
+
this.decodeUrls = _.isBoolean(options.decodeUrls) ? options.decodeUrls : true;
|
|
61
71
|
this.defaultLabel = options.defaultLabel || 'zeddemore-logger';
|
|
62
|
-
this.disableApiCallLogging = options.
|
|
63
|
-
this.disableRouteLogging = options.
|
|
64
|
-
this.disableMorganLogging = options.
|
|
65
|
-
this.displayCaller = options.
|
|
66
|
-
this.displayIpAddress = options.
|
|
67
|
-
this.displayRequestId = options.
|
|
72
|
+
this.disableApiCallLogging = _.isBoolean(options.disableApiCallLogging) ? options.disableApiCallLogging : false;
|
|
73
|
+
this.disableRouteLogging = _.isBoolean(options.disableRouteLogging) ? options.disableRouteLogging : false;
|
|
74
|
+
this.disableMorganLogging = _.isBoolean(options.disableMorganLogging) ? options.disableMorganLogging : false;
|
|
75
|
+
this.displayCaller = _.isBoolean(options.displayCaller) ? options.displayCaller : true;
|
|
76
|
+
this.displayIpAddress = _.isBoolean(options.displayIpAddress) ? options.displayIpAddress : true;
|
|
77
|
+
this.displayRequestId = _.isBoolean(options.displayRequestId) ? options.displayRequestId : true;
|
|
68
78
|
this.customCallerSettings = options.customCallerSettings || [ ];
|
|
69
79
|
this.defaultUserLogLevel = options.defaultUserLogLevel || DEFAULT_USER_LOG_LEVEL;
|
|
70
|
-
this.#forceLogLevel = options.
|
|
71
|
-
this.#logLevel = options.
|
|
72
|
-
this.morganFormat = options.morganFormat
|
|
80
|
+
this.#forceLogLevel = _.isBoolean(options.forceLogLevel) ? options.forceLogLevel : false;
|
|
81
|
+
this.#logLevel = _.isInteger(options.logLevel) ? options.logLevel : wll.INFO;
|
|
82
|
+
this.morganFormat = _.isString(options.morganFormat) ? options.morganFormat : null;
|
|
73
83
|
this.routeModel = options.routeModel || null;
|
|
74
|
-
this.suppressNonMutatingRequestApiCallLogging = options.
|
|
75
|
-
this.suppressSuccessfulRequestApiCallLogging = options.
|
|
84
|
+
this.suppressNonMutatingRequestApiCallLogging = _.isBoolean(options.suppressNonMutatingRequestApiCallLogging) ? options.suppressNonMutatingRequestApiCallLogging : false;
|
|
85
|
+
this.suppressSuccessfulRequestApiCallLogging = _.isBoolean(options.suppressSuccessfulRequestApiCallLogging) ? options.suppressSuccessfulRequestApiCallLogging : false;
|
|
76
86
|
this.timestampFormat = options.timestampFormat || 'YYYY-MM-DD HH:mm:ss';
|
|
77
87
|
this.requestIdAttribute = options.requestIdAttribute || DEFAULT_REQUEST_ID_ATTRIBUTE;
|
|
78
88
|
this.userGetFn = options.userGetFn || this.#userGetFn;
|
|
@@ -82,6 +92,15 @@ class ZeddemoreLogger {
|
|
|
82
92
|
return !this.disableApiCallLogging && !!this.apiCallModel;
|
|
83
93
|
}
|
|
84
94
|
|
|
95
|
+
get morganFormat() {
|
|
96
|
+
if (!!this.#morganFormat) return this.#morganFormat;
|
|
97
|
+
return mf.ZEDDEMORE;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
set morganFormat(format) {
|
|
101
|
+
if (_.isString(format) && !!format.length) this.#morganFormat = format;
|
|
102
|
+
}
|
|
103
|
+
|
|
85
104
|
get forceLogLevel() {
|
|
86
105
|
return this.#forceLogLevel;
|
|
87
106
|
}
|
|
@@ -111,6 +130,35 @@ class ZeddemoreLogger {
|
|
|
111
130
|
this.#logLevel = massageLogLevel(level);
|
|
112
131
|
}
|
|
113
132
|
|
|
133
|
+
#buildMorganFormat = (morganTokens = [ ]) => {
|
|
134
|
+
function addArgument(token, argument) {
|
|
135
|
+
if (hasArgument(token)) return token;
|
|
136
|
+
const openBracketIndex = token.indexOf('[');
|
|
137
|
+
const _token = (openBracketIndex > -1) ? token.substring(0, openBracketIndex) : token;
|
|
138
|
+
return `${ _token }[${ argument }]`;
|
|
139
|
+
}
|
|
140
|
+
function hasArgument(token) {
|
|
141
|
+
const openBracketIndex = token.indexOf('[');
|
|
142
|
+
const closeBracketIndex = token.indexOf(']');
|
|
143
|
+
return ((openBracketIndex > -1) && (closeBracketIndex > -1) && (closeBracketIndex > (openBracketIndex + 1)));
|
|
144
|
+
}
|
|
145
|
+
const DEFAULT_CONTENT_LENGTH_FORMAT_DIGITS = 0;
|
|
146
|
+
const DEFAULT_RESPONSE_TIME_DIGITS = 2;
|
|
147
|
+
if (!morganTokens || !_.isArray(morganTokens) || !morganTokens.length) return mf.DEV;
|
|
148
|
+
const _morganTokens = _.map(morganTokens, (token) => {
|
|
149
|
+
if (!_.isString(token) || !token.length) return null;
|
|
150
|
+
let _token = token.trim();
|
|
151
|
+
if (_token[ 0 ] !== ':') _token = `:${ _token }`;
|
|
152
|
+
switch (_token) {
|
|
153
|
+
case mft.CONTENT_LENGTH_FORMAT: return hasArgument(_token) ? _token : addArgument(_token, DEFAULT_CONTENT_LENGTH_FORMAT_DIGITS);
|
|
154
|
+
case mft.RESPONSE_TIME:
|
|
155
|
+
case mft.RESPONSE_TIME_FORMAT: return hasArgument(_token) ? _token : addArgument(_token, DEFAULT_RESPONSE_TIME_DIGITS);
|
|
156
|
+
default: return _token;
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
return (_.compact(_morganTokens)).join(' ');
|
|
160
|
+
}
|
|
161
|
+
|
|
114
162
|
#buildWinstonFormat = (options, additionalFormats = [ ]) => {
|
|
115
163
|
options = options || { };
|
|
116
164
|
const formats = [
|
|
@@ -213,6 +261,10 @@ class ZeddemoreLogger {
|
|
|
213
261
|
return this.createLogger(loggerOptions);
|
|
214
262
|
}
|
|
215
263
|
|
|
264
|
+
enableConsoleDirp() {
|
|
265
|
+
monkeyPatchConsole();
|
|
266
|
+
}
|
|
267
|
+
|
|
216
268
|
#generateUuid() {
|
|
217
269
|
return uuid(null, null, null);
|
|
218
270
|
}
|
|
@@ -231,22 +283,28 @@ class ZeddemoreLogger {
|
|
|
231
283
|
}
|
|
232
284
|
|
|
233
285
|
#initializeMorgan() {
|
|
234
|
-
function buildContentLengthFormatToken(res) {
|
|
235
|
-
const contentLength = convertBytes(res.get('content-length'), { digits
|
|
286
|
+
function buildContentLengthFormatToken(res, digits = 2) {
|
|
287
|
+
const contentLength = convertBytes(res.get('content-length'), { digits });
|
|
236
288
|
return contentLength ? ` - ${ contentLength }` : '';
|
|
237
289
|
}
|
|
238
|
-
function
|
|
290
|
+
function buildDecodedUrl(req) {
|
|
291
|
+
const url = req.originalUrl || req.url;
|
|
292
|
+
return decodeURI(url);
|
|
293
|
+
}
|
|
294
|
+
function buildResponseTimeFormatToken(req, res, digits = 0) {
|
|
239
295
|
const responseTime = getRequestResponseTime(req, res);
|
|
240
|
-
return responseTime ? convertMilliseconds(responseTime, { digits
|
|
296
|
+
return responseTime ? convertMilliseconds(responseTime, { digits }) : '-';
|
|
241
297
|
}
|
|
242
298
|
function buildStatusColoredToken(res) {
|
|
243
299
|
const statusCode = areHeadersSent(res) ? res.statusCode : null;
|
|
244
300
|
if (!statusCode) return '-';
|
|
245
301
|
return chalkHttpStatuses(statusCode);
|
|
246
302
|
}
|
|
247
|
-
morgan.token(
|
|
248
|
-
morgan.token(
|
|
249
|
-
morgan.token(
|
|
303
|
+
morgan.token(mft.CONTENT_LENGTH_FORMAT, (req, res, digits) => { return buildContentLengthFormatToken(res, digits); });
|
|
304
|
+
morgan.token(mft.DECODED_URL, (req, res) => { return buildDecodedUrl(req); });
|
|
305
|
+
morgan.token(mft.RESPONSE_TIME_FORMAT, (req, res, digits) => { return buildResponseTimeFormatToken(req, res, digits); });
|
|
306
|
+
morgan.token(mft.STATUS_COLORED, (req, res) => { return buildStatusColoredToken(res); });
|
|
307
|
+
morgan.format(mf.ZEDDEMORE, this.#buildMorganFormat(DEFAULT_MORGAN_FORMAT_TOKENS));
|
|
250
308
|
}
|
|
251
309
|
|
|
252
310
|
log = (logLevel) => {
|
|
@@ -257,7 +315,7 @@ class ZeddemoreLogger {
|
|
|
257
315
|
|
|
258
316
|
#logServerInfo = (options, logLevel = wll.INFO) => {
|
|
259
317
|
options = options || { };
|
|
260
|
-
const showLogLevel = options.
|
|
318
|
+
const showLogLevel = _.isBoolean(options.showLogLevel) ? options.showLogLevel : true;
|
|
261
319
|
const logLevelLabel = chalkLogLevel(this.#logLevel, this.logLevelName.toUpperCase());
|
|
262
320
|
const msgParts = [ `Server is ${ chalk.bold(chalk.yellowBright('⚡live⚡')) }` ];
|
|
263
321
|
if (showLogLevel) msgParts.push(`with log level ${ logLevelLabel }${ this.#forceLogLevel ? ` (${ chalk.italic('forced') })` : '' }`);
|
|
@@ -291,7 +349,7 @@ class ZeddemoreLogger {
|
|
|
291
349
|
|
|
292
350
|
#logServerRoutesAdded = (options, logLevel = wll.INFO) => {
|
|
293
351
|
options = options || { };
|
|
294
|
-
const showCategories = options.
|
|
352
|
+
const showCategories = _.isBoolean(options.showCategories) ? options.showCategories : true;
|
|
295
353
|
const routes = options.routes || this.apiRoutes || [ ];
|
|
296
354
|
const routesLabel = (routes.length === 1) ? 'route' : 'routes';
|
|
297
355
|
const addedLabel = chalk.green('added');
|
|
@@ -305,10 +363,10 @@ class ZeddemoreLogger {
|
|
|
305
363
|
|
|
306
364
|
logServerStartup = (options, logLevel = wll.INFO) => {
|
|
307
365
|
options = options || { };
|
|
308
|
-
const showListening = options.
|
|
309
|
-
const showPackages = options.
|
|
310
|
-
const showRoutes = options.
|
|
311
|
-
const showInfo = options.
|
|
366
|
+
const showListening = _.isBoolean(options.showListening) ? options.showListening : true;
|
|
367
|
+
const showPackages = _.isBoolean(options.showPackages) ? options.showPackages : true;
|
|
368
|
+
const showRoutes = _.isBoolean(options.showRoutes) ? options.showRoutes : true;
|
|
369
|
+
const showInfo = _.isBoolean(options.showInfo) ? options.showInfo : true;
|
|
312
370
|
if (showListening) this.#logServerListening(options, logLevel);
|
|
313
371
|
if (showPackages && options.packages) this.#logServerPackagesInfo(options, options.packages, logLevel);
|
|
314
372
|
if (showRoutes) this.#logServerRoutesAdded(options, logLevel);
|
|
@@ -329,8 +387,8 @@ class ZeddemoreLogger {
|
|
|
329
387
|
|
|
330
388
|
morganMiddleware = (options) => {
|
|
331
389
|
options = options || { };
|
|
332
|
-
const disableMorganLogging = options.
|
|
333
|
-
const morganFormat = options.morganFormat || this
|
|
390
|
+
const disableMorganLogging = _.isBoolean(options.disableMorganLogging) ? options.disableMorganLogging : this.disableMorganLogging;
|
|
391
|
+
const morganFormat = options.morganFormat || this.#buildMorganFormat(DEFAULT_MORGAN_FORMAT_TOKENS);
|
|
334
392
|
const userGetFn = (_.isFunction(options.userGetFn) ? options.userGetFn : null) || this.userGetFn;
|
|
335
393
|
return (req, res, next) => {
|
|
336
394
|
this.#initializeMorgan();
|