zeddemore-logger 1.2.4 → 2.0.0

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.
@@ -1,587 +1,13 @@
1
1
  // Copyright (c) 2025 by Beardon Services, Inc.
2
2
 
3
- const _ = require('lodash');
4
- const chalk = require('chalk');
5
- const { createLogger: createWinstonLogger, format, Logger, transports } = require('winston');
6
- const morgan = require('morgan');
7
- const sizeof = require('object-sizeof');
8
- const { v4: uuid } = require('uuid');
9
-
10
- const { areHeadersSent, isResponseSuccessful } = require('./response');
11
- const { chalkHttpStatuses, chalkHttpVerbs, chalkLogLevel, chalkPackage, chalkTarget, stringToIdempotentHexColor } = require('./color');
12
- const { convertBytes } = require('./math');
13
- const { convertMilliseconds } = require('./date');
14
- const enums = require('./enums');
15
- const { extractToken, getRequestResponseTime, isRequestOfMethod, parseRequest } = require('./request');
16
- const { logLevelMap } = require('./mappings/log_mappings');
17
-
18
- const { colorize, combine, label, metadata, printf, timestamp } = format;
19
- const { morganFormats: mf, morganFormatTokens: mft, httpMethods: http, httpRequestHeaders: rqh, httpResponseHeaders: rsh,
20
- winstonLogLevelNames: wlln, winstonLogLevels: wll } = enums;
21
-
22
- const COLOR_CONSOLE_WHITE_HEX = '#ECECEC';
23
- const DEFAULT_CONTENT_LENGTH_DIGITS = 2;
24
- const DEFAULT_MORGAN_FORMAT_TOKENS = [ mft.METHOD, mft.DECODED_URL, mft.STATUS_COLORED, mft.RESPONSE_TIME_FORMAT, mft.CONTENT_LENGTH_FORMAT ];
25
- const DEFAULT_REQUEST_ID_ATTRIBUTE = 'requestId';
26
- const DEFAULT_RESPONSE_TIME_DIGITS = 0;
27
- const DEFAULT_USER_LOG_LEVEL = -1;
28
- const WINSTON_CONSOLE_TRANSPORT_NAME = 'console';
29
-
30
- /**
31
- * Convert a log level to a Winston log level name
32
- * @param logLevel {number|string}
33
- * @returns {string}
34
- */
35
- function massageLogLevel(logLevel) {
36
- if (!logLevel) return wlln.VERBOSE;
37
- if (!_.isInteger(logLevel)) return logLevel;
38
- return winstonLogLevelIdToName(logLevel);
39
- }
40
-
41
- /**
42
- * Monkey patch console to allow unlimited depth with `console.dirp`
43
- */
44
- function monkeyPatchConsole() {
45
- console.dirp = (arguments) => console.dir(arguments, { depth: null });
46
- }
47
-
48
- /**
49
- * Convert a log level ID to a Winston log level name
50
- * @param levelId {number}
51
- * @returns {string}
52
- */
53
- function winstonLogLevelIdToName(levelId) {
54
- const logLevelEntry = _.find(logLevelMap, { winstonLevel: levelId });
55
- return logLevelEntry ? logLevelEntry.winstonName : wlln.HTTP;
56
- }
57
-
58
- class ZeddemoreLogger {
59
-
60
- #forceLogLevel = false;
61
- /** @type {Logger} */
62
- #logger = null;
63
- #logLevel = wll.INFO;
64
- #morganFormat = null;
65
-
66
- constructor(options) {
67
- options = options || { };
68
- this.apiCallModel = options.apiCallModel || null;
69
- this.apiRouteCategories = options.apiRouteCategories || [ ];
70
- this.apiRoutes = options.apiRoutes || [ ];
71
- this.apiVersion = options.apiVersion || null;
72
- this.contentLengthDigits = _.isInteger(options.contentLengthDigits) ? options.contentLengthDigits : DEFAULT_CONTENT_LENGTH_DIGITS;
73
- this.decodeUrls = _.isBoolean(options.decodeUrls) ? options.decodeUrls : true;
74
- this.defaultLabel = options.defaultLabel || 'zeddemore-logger';
75
- this.disableApiCallLogging = _.isBoolean(options.disableApiCallLogging) ? options.disableApiCallLogging : false;
76
- this.disableRouteLogging = _.isBoolean(options.disableRouteLogging) ? options.disableRouteLogging : false;
77
- this.disableMorganLogging = _.isBoolean(options.disableMorganLogging) ? options.disableMorganLogging : false;
78
- this.displayCaller = _.isBoolean(options.displayCaller) ? options.displayCaller : true;
79
- this.displayIpAddress = _.isBoolean(options.displayIpAddress) ? options.displayIpAddress : true;
80
- this.displayRequestId = _.isBoolean(options.displayRequestId) ? options.displayRequestId : true;
81
- this.customCallerSettings = options.customCallerSettings || [ ];
82
- this.defaultUserLogLevel = options.defaultUserLogLevel || DEFAULT_USER_LOG_LEVEL;
83
- this.#forceLogLevel = _.isBoolean(options.forceLogLevel) ? options.forceLogLevel : false;
84
- this.#logLevel = _.isInteger(options.logLevel) ? options.logLevel : wll.INFO;
85
- this.morganFormat = _.isString(options.morganFormat) ? options.morganFormat : null;
86
- this.responseTimeDigits = _.isInteger(options.responseTimeDigits) ? options.responseTimeDigits : DEFAULT_RESPONSE_TIME_DIGITS;
87
- this.routeModel = options.routeModel || null;
88
- this.suppressNonMutatingRequestApiCallLogging = _.isBoolean(options.suppressNonMutatingRequestApiCallLogging) ? options.suppressNonMutatingRequestApiCallLogging : false;
89
- this.suppressSuccessfulRequestApiCallLogging = _.isBoolean(options.suppressSuccessfulRequestApiCallLogging) ? options.suppressSuccessfulRequestApiCallLogging : false;
90
- this.timestampFormat = options.timestampFormat || 'YYYY-MM-DD HH:mm:ss';
91
- this.requestIdAttribute = options.requestIdAttribute || DEFAULT_REQUEST_ID_ATTRIBUTE;
92
- this.userGetFn = options.userGetFn || this.#userGetFn;
93
- }
94
-
95
- get apiCallLoggingEnabled() {
96
- return !this.disableApiCallLogging && !!this.apiCallModel;
97
- }
98
-
99
- get morganFormat() {
100
- if (!!this.#morganFormat) return this.#morganFormat;
101
- return mf.ZEDDEMORE;
102
- }
103
-
104
- set morganFormat(format) {
105
- if (_.isString(format) && !!format.length) this.#morganFormat = format;
106
- }
107
-
108
- get forceLogLevel() {
109
- return this.#forceLogLevel;
110
- }
111
-
112
- get logger() {
113
- if (!this.#logger) this.#logger = this.createLogger();
114
- return this.#logger;
115
- }
116
-
117
- get logLevel() {
118
- return this.#logLevel;
119
- }
120
-
121
- get logLevelName() {
122
- return winstonLogLevelIdToName(this.#logLevel);
123
- }
124
-
125
- get routeLoggingEnabled() {
126
- return !this.disableRouteLogging && !!this.routeModel;
127
- }
128
-
129
- set forceLogLevel(doForce) {
130
- this.#forceLogLevel = !!doForce;
131
- }
132
-
133
- set logLevel(level) {
134
- this.#logLevel = massageLogLevel(level);
135
- }
136
-
137
- #buildMorganFormat = (morganTokens = [ ]) => {
138
- function addArgument(token, argument) {
139
- if (hasArgument(token)) return token;
140
- const openBracketIndex = token.indexOf('[');
141
- const _token = (openBracketIndex > -1) ? token.substring(0, openBracketIndex) : token;
142
- return `${ _token }[${ argument }]`;
143
- }
144
- function hasArgument(token) {
145
- const openBracketIndex = token.indexOf('[');
146
- const closeBracketIndex = token.indexOf(']');
147
- return ((openBracketIndex > -1) && (closeBracketIndex > -1) && (closeBracketIndex > (openBracketIndex + 1)));
148
- }
149
- if (!morganTokens || !_.isArray(morganTokens) || !morganTokens.length) return mf.DEV;
150
- const _morganTokens = _.map(morganTokens, (token) => {
151
- if (!_.isString(token) || !token.length) return null;
152
- let _token = token.trim();
153
- if (_token[ 0 ] !== ':') _token = `:${ _token }`;
154
- switch (_token) {
155
- case mft.CONTENT_LENGTH_FORMAT: return hasArgument(_token) ? _token : addArgument(_token, this.contentLengthDigits);
156
- case mft.RESPONSE_TIME:
157
- case mft.RESPONSE_TIME_FORMAT: return hasArgument(_token) ? _token : addArgument(_token, this.responseTimeDigits);
158
- default: return _token;
159
- }
160
- });
161
- return (_.compact(_morganTokens)).join(' ');
162
- }
163
-
164
- #buildWinstonFormat = (options, additionalFormats = [ ]) => {
165
- options = options || { };
166
- const formats = [
167
- format((info) => {
168
- info.id = info.id || options.id || null;
169
- info.ip = info.ip || options.ip || null;
170
- info.user = info.user || options.user || null;
171
- return info;
172
- })(),
173
- colorize(),
174
- label({ label: options.label || this.defaultLabel }),
175
- timestamp({ format: this.timestampFormat }),
176
- metadata(),
177
- printf(this.#colorizedTemplate),
178
- ];
179
- return combine(...additionalFormats.concat(formats));
180
- }
181
-
182
- #buildWinstonTransport = (logLevel = this.#logLevel) => {
183
- logLevel = logLevel || this.#logLevel;
184
- const level = winstonLogLevelIdToName(logLevel);
185
- return new transports.Console({ level, name: WINSTON_CONSOLE_TRANSPORT_NAME });
186
- }
187
-
188
- #buildWinstonTransports = (logLevel = this.#logLevel, additionalTransports = [ ]) => {
189
- return additionalTransports.concat([ this.#buildWinstonTransport(logLevel) ]);
190
- }
191
-
192
- #callerToHexColor = (caller) => {
193
- if (!caller) return COLOR_CONSOLE_WHITE_HEX;
194
- const customCallerSetting = _.find(this.customCallerSettings, { caller });
195
- if (customCallerSetting && customCallerSetting.color && customCallerSetting.color.fore) return customCallerSetting.color.fore;
196
- return stringToIdempotentHexColor(caller, true);
197
- }
198
-
199
- #colorizeResponse(message) {
200
- const verb = message.split(' ')[ 0 ];
201
- return chalkHttpVerbs(verb, message);
202
- }
203
-
204
- #colorizedTemplate = (info) => {
205
- const id = info.metadata.id ? info.metadata.id.substring(0, 8) : null;
206
- const subId = info.metadata.subId || null;
207
- const caller = info.metadata.caller || info.metadata.user || null;
208
- const ipAddress = info.metadata.ip || null;
209
- const prefix = info.metadata.prefix || null;
210
- const isError = (info.level.indexOf(wlln.ERROR) > -1);
211
- const leaveUncompressed = isError || info.metadata.raw;
212
- const idHexColor = stringToIdempotentHexColor(id, true);
213
- const callerColorSource = caller || ipAddress;
214
- const callerHexColor = this.#callerToHexColor(callerColorSource);
215
- const parts = [ ];
216
- parts.push(info.metadata.timestamp);
217
- parts.push(`[${ info.metadata.target || info.metadata.label }]`);
218
- parts.push(`${ info.level }:`);
219
- const fullId = '🧵' + id + (subId ? `[${ subId }]` : '');
220
- if (id && this.displayRequestId) parts.push(chalk.bold.hex(idHexColor)(fullId));
221
- const callerParts = [ ];
222
- if (caller && this.displayCaller) {
223
- const customCallerSettings = _.find(this.customCallerSettings, { caller });
224
- const logPrefix = customCallerSettings ? customCallerSettings.logPrefix : null;
225
- callerParts.push(logPrefix ? logPrefix + caller : caller);
226
- }
227
- if (ipAddress && this.displayIpAddress) callerParts.push(ipAddress);
228
- const fullCaller = callerParts.join('@');
229
- if (fullCaller) parts.push(`<${ chalk.underline.hex(callerHexColor).bold(fullCaller) }>`);
230
- if (prefix) parts.push(`[${ prefix }]`);
231
- let message = Array.isArray(info.message) ? info.message.join('\n') : info.message;
232
- message = _.isObject(message) ? JSON.stringify(message) : message;
233
- parts.push(leaveUncompressed ? message : message.replace(/(\n?\s+)/g, ' '));
234
- if (info.err) parts.push(info.err);
235
- return isError ? chalk.red(parts.join(' ')) : parts.join(' ');
236
- }
237
-
238
- /**
239
- * Create a Winston Logger
240
- * @param [options] {Object}
241
- * @returns {Logger}
242
- */
243
- createLogger = (options) => {
244
- options = options || { };
245
- return createWinstonLogger({
246
- format: this.#buildWinstonFormat(options, options.formats),
247
- transports: this.#buildWinstonTransports(options.level, options.transports),
248
- });
249
- }
250
-
251
- createRequestLogger = (requestId = null, ipAddress = null) => {
252
- requestId = requestId || this.#generateUuid();
253
- const loggerOptions = { id: requestId };
254
- if (ipAddress) loggerOptions.ip = ipAddress;
255
- return this.createLogger(loggerOptions);
256
- }
257
-
258
- createUserLogger = (requestId = null, username = null, logLevel = this.defaultUserLogLevel, ipAddress = null) => {
259
- requestId = requestId || this.#generateUuid();
260
- logLevel = logLevel || this.defaultUserLogLevel;
261
- const loggerOptions = { id: requestId, level: logLevel, user: username };
262
- if (ipAddress) loggerOptions.ip = ipAddress;
263
- return this.createLogger(loggerOptions);
264
- }
265
-
266
- enableConsoleDirp() {
267
- monkeyPatchConsole();
268
- }
269
-
270
- #generateUuid() {
271
- return uuid(null, null, null);
272
- }
273
-
274
- static getLogger(options) {
275
- options = options || { };
276
- const logger = options.logger || (options.user ? options.user.logger : null) || ((app && app.locals) ? app.locals.logger : null);
277
- if (logger) return logger;
278
- const zeddemoreLogger = new ZeddemoreLogger();
279
- return zeddemoreLogger.createLogger(options);
280
- }
281
-
282
- #getRequestId = (req) => {
283
- if (!req) return null;
284
- return req[ this.requestIdAttribute ];
285
- }
286
-
287
- #initializeMorgan() {
288
- function buildContentLengthFormatToken(res, decimals = DEFAULT_CONTENT_LENGTH_DIGITS) {
289
- const contentLength = convertBytes(res.get('content-length'), { decimals });
290
- return contentLength ? ` - ${ contentLength }` : '';
291
- }
292
- function buildDecodedUrl(req) {
293
- const url = req.originalUrl || req.url;
294
- return decodeURI(url);
295
- }
296
- function buildResponseTimeFormatToken(req, res, digits = DEFAULT_RESPONSE_TIME_DIGITS) {
297
- const responseTime = getRequestResponseTime(req, res);
298
- return responseTime ? convertMilliseconds(responseTime, { digits }) : '-';
299
- }
300
- function buildStatusColoredToken(res) {
301
- const statusCode = areHeadersSent(res) ? res.statusCode : null;
302
- if (!statusCode) return '-';
303
- return chalkHttpStatuses(statusCode);
304
- }
305
- morgan.token(mft.CONTENT_LENGTH_FORMAT, (req, res, decimals) => { return buildContentLengthFormatToken(res, decimals); });
306
- morgan.token(mft.DECODED_URL, (req, res) => { return buildDecodedUrl(req); });
307
- morgan.token(mft.RESPONSE_TIME_FORMAT, (req, res, digits) => { return buildResponseTimeFormatToken(req, res, digits); });
308
- morgan.token(mft.STATUS_COLORED, (req, res) => { return buildStatusColoredToken(res); });
309
- morgan.format(mf.ZEDDEMORE, this.#buildMorganFormat(DEFAULT_MORGAN_FORMAT_TOKENS));
310
- }
311
-
312
- log = (logLevel) => {
313
- logLevel = logLevel || this.#logLevel;
314
- const logLevelName = massageLogLevel(logLevel);
315
- return this.logger[ logLevelName ];
316
- }
317
-
318
- #logServerInfo = (options, logLevel = wll.INFO) => {
319
- options = options || { };
320
- const showLogLevel = _.isBoolean(options.showLogLevel) ? options.showLogLevel : true;
321
- const logLevelLabel = chalkLogLevel(this.#logLevel, this.logLevelName.toUpperCase());
322
- const msgParts = [ `Server is ${ chalk.bold(chalk.yellowBright('⚡live⚡')) }` ];
323
- if (showLogLevel) msgParts.push(`with log level ${ logLevelLabel }${ this.#forceLogLevel ? ` (${ chalk.italic('forced') })` : '' }`);
324
- if (options.url) msgParts.push(`at ${ chalk.underline(options.url) }`);
325
- this.log(logLevel)(msgParts.join(' '));
326
- }
327
-
328
- #logServerListening = (options, logLevel = wll.INFO) => {
329
- const serverEnvironment = options.environment || process.env.NODE_ENV || 'development';
330
- const serverInstance = options.instance || (process.env.NODE_APP_INSTANCE && (process.env.NODE_APP_INSTANCE.length > 1)) ? process.env.NODE_APP_INSTANCE : null; // handles goofy PM2 NODE_APP_INSTANCE of '0'
331
- const serverName = options.name || this.defaultLabel;
332
- const serverPort = options.port || process.env.PORT || 3000;
333
- const msgParts = [ ];
334
- const serverParts = [ serverName ];
335
- if (serverEnvironment) serverParts.push(serverEnvironment);
336
- if (serverInstance) serverParts.push(serverInstance);
337
- msgParts.push(`[${ serverParts.join(':') }]`);
338
- msgParts.push(`Node.js Express server listening on port ${ chalk.bold(serverPort) }`);
339
- this.log(logLevel)(msgParts.join(' '));
340
- }
341
-
342
- #logServerPackagesInfo = (options, packages, logLevel = wll.INFO) => {
343
- function buildVersionLabel(_package) {
344
- if (!_package || !_package.name || !_package.version) return null;
345
- const packageName = _package.style ? chalkTarget(_package.name, _package.style) : chalkPackage(_package.name);
346
- return `${ packageName }@${ _package.version }`;
347
- }
348
- const versionParts = _.compact(_.sortBy(packages, (_package) => _package.name.toUpperCase()).map(buildVersionLabel));
349
- this.log(logLevel)(`Packages: ${ versionParts.join(' | ') }`);
350
- }
351
-
352
- #logServerRoutesAdded = (options, logLevel = wll.INFO) => {
353
- options = options || { };
354
- const showCategories = _.isBoolean(options.showCategories) ? options.showCategories : true;
355
- const routes = options.routes || this.apiRoutes || [ ];
356
- const routesLabel = (routes.length === 1) ? 'route' : 'routes';
357
- const addedLabel = chalk.green('added');
358
- const msgParts = [ `${ routes.length } ${ routesLabel } ${ addedLabel }` ];
359
- if (showCategories) {
360
- const categories = options.categories || this.apiRouteCategories || [];
361
- msgParts.push(`in: ${ categories.sort().join('/') }`);
362
- }
363
- this.log(logLevel)(msgParts.join(', '));
364
- }
365
-
366
- logServerStartup = (options, logLevel = wll.INFO) => {
367
- options = options || { };
368
- const showListening = _.isBoolean(options.showListening) ? options.showListening : true;
369
- const showPackages = _.isBoolean(options.showPackages) ? options.showPackages : true;
370
- const showRoutes = _.isBoolean(options.showRoutes) ? options.showRoutes : true;
371
- const showInfo = _.isBoolean(options.showInfo) ? options.showInfo : true;
372
- if (showListening) this.#logServerListening(options, logLevel);
373
- if (showPackages && options.packages) this.#logServerPackagesInfo(options, options.packages, logLevel);
374
- if (showRoutes) this.#logServerRoutesAdded(options, logLevel);
375
- if (showInfo) this.#logServerInfo(options, logLevel);
376
- }
377
-
378
- #matchPathToRoute = (path) => {
379
- if (!path) return null;
380
- let matchedRoute = null;
381
- for (const route of this.apiRoutes) {
382
- if (path.match(route.regexp)) {
383
- matchedRoute = route.path;
384
- break;
385
- }
386
- }
387
- return matchedRoute;
388
- }
389
-
390
- morganMiddleware = (options) => {
391
- options = options || { };
392
- const disableMorganLogging = _.isBoolean(options.disableMorganLogging) ? options.disableMorganLogging : this.disableMorganLogging;
393
- const morganFormat = options.morganFormat || this.#buildMorganFormat(DEFAULT_MORGAN_FORMAT_TOKENS);
394
- const userGetFn = (_.isFunction(options.userGetFn) ? options.userGetFn : null) || this.userGetFn;
395
- return (req, res, next) => {
396
- this.#initializeMorgan();
397
- return morgan(morganFormat, {
398
- skip: () => disableMorganLogging,
399
- stream: {
400
- write: (message) => {
401
- if (this.apiCallLoggingEnabled) this.#writeApiCallToDatabase(req, res, options);
402
- const logOptions = { };
403
- const user = userGetFn ? userGetFn(req, res) : null;
404
- if (user) logOptions.user = user;
405
- ZeddemoreLogger.getLogger(logOptions).http(this.#colorizeResponse(message.trim()));
406
- },
407
- },
408
- })(req, res, next);
409
- }
410
- }
411
-
412
- requestLoggerMiddleware = (req, res, next) => {
413
- const requestValues = parseRequest(req);
414
- const requestId = this.#generateUuid();
415
- req[ this.requestIdAttribute ] = requestId;
416
- res.header(rqh.REQUEST_ID, requestId);
417
- const ipAddress = requestValues.ipAddress;
418
- res.locals = res.locals || { };
419
- res.locals.user = res.locals.user || { };
420
- res.locals.user.logger = this.createRequestLogger(requestId, ipAddress);
421
- return next();
422
- }
423
-
424
- routeLoggingMiddleware = (req, res, next) => {
425
- if (!this.routeLoggingEnabled) return next();
426
- try {
427
- const routeValues = {
428
- route: req.path,
429
- method: req.method,
430
- lastCalled: new Date().toISOString(),
431
- };
432
- this.#writeRouteToDatabase(routeValues);
433
- } catch (e) {
434
- } finally {
435
- next();
436
- }
437
- }
438
-
439
- #userGetFn(req, res) {
440
- return ((res && res.locals) ? res.locals.user : null)
441
- || ((req && req.locals) ? req.locals.user : null)
442
- || (req ? req.user : null);
443
- }
444
-
445
- userLoggerMiddleware = (req, res, next) => {
446
- const requestId = this.#getRequestId(req);
447
- const user = this.userGetFn(req, res) || { };
448
- if (!requestId) return next();
449
- const username = user.login || user.username || null;
450
- let ipAddress = user.ipAddress || null;
451
- if (!ipAddress) {
452
- const requestValues = parseRequest(req);
453
- ipAddress = requestValues.ipAddress;
454
- }
455
- let userLogLevel = !_.isNil(user.logLevel) ? user.logLevel : this.defaultUserLogLevel;
456
- if (userLogLevel < 0) userLogLevel = this.#logLevel;
457
- const level = this.#forceLogLevel ? this.#logLevel : userLogLevel;
458
- res.locals = res.locals || { };
459
- res.locals.user = res.locals.user || user;
460
- res.locals.user.logger = this.createUserLogger(requestId, username, level, ipAddress);
461
- return next();
462
- }
463
-
464
- #writeApiCallToDatabase = async (req, res, options) => {
465
- options = options || { };
466
- if (!req) return;
467
- const user = this.userGetFn ? this.userGetFn(req, res) : null;
468
- const statusCode = options.statusCode || (res ? res.statusCode : null);
469
- if (isResponseSuccessful(statusCode) && this.suppressSuccessfulRequestApiCallLogging) return;
470
- if (!isRequestOfMethod(req, [ http.DELETE, http.PUT ]) && this.suppressNonMutatingRequestApiCallLogging) return;
471
- const matchedRoute = this.#matchPathToRoute(req.path);
472
- let metadataDefaults = Object.assign({ }, user);
473
- delete(metadataDefaults.id);
474
- delete(metadataDefaults.logger);
475
- const _metadata = _.defaults({ }, (options.metadata || { }), metadataDefaults);
476
- if (matchedRoute) {
477
- try {
478
- const appCallValues = {
479
- apiVersion: this.apiVersion,
480
- client: user ? user.clientId : null,
481
- clientVersion: req.header(rqh.APP_VERSION),
482
- httpStatusCode: statusCode,
483
- ipAddress: req.header(rqh.FORWARDED_FOR) || req.socket.remoteAddress,
484
- metadata: _metadata,
485
- method: req.method,
486
- route: matchedRoute,
487
- token: extractToken(req),
488
- userAgent: req.header(rqh.USER_AGENT),
489
- userId: user ? user.id : null,
490
- };
491
- await this.apiCallModel.create(appCallValues);
492
- } catch (e) {
493
- console.error(e);
494
- ZeddemoreLogger.getLogger({ user }).error('Api call logging failed, moving on');
495
- }
496
- }
497
- }
498
-
499
- #writeRouteToDatabase = async (routeValues) => {
500
- if (!this.routeLoggingEnabled || !routeValues) return;
501
- const matchedRoute = this.#matchPathToRoute(routeValues.route);
502
- if (matchedRoute) {
503
- try {
504
- const route = await this.routeModel.findOne({ where: { route: matchedRoute }, logging: false });
505
- if (route) {
506
- route.count++;
507
- route.lastCalledAt = new Date();
508
- route.save();
509
- } else {
510
- this.routeModel.create({
511
- count: 1,
512
- lastCalledAt: new Date(),
513
- method: routeValues.method,
514
- route: matchedRoute,
515
- });
516
- }
517
- } catch (e) {
518
- console.error(e);
519
- console.error('Route logging failed, moving on');
520
- }
521
- }
522
- }
523
-
524
- static writeAxiosErrorLog(axiosError, logOptions, options) {
525
- logOptions = logOptions || { };
526
- options = options || { };
527
- if (!axiosError || !axiosError.response) return;
528
- const _response = axiosError.response;
529
- if (!_response.request) return;
530
- const _request = _response.request;
531
- const logger = options.logger || ZeddemoreLogger.getLogger(options);
532
- if (!logger) return;
533
- const _method = _request.method || null;
534
- const method = _method ? chalkHttpVerbs(_method) : null;
535
- const _config = _response.config || null;
536
- const _headers = _response.headers || null;
537
- const _data = _response.data || null;
538
- const path = _config ? _config.url : '';
539
- const prefix = logOptions.prefix ? `[${ logOptions.prefix }]` : null;
540
- const status = chalkHttpStatuses(_response.status);
541
- const _duration = axiosError.duration || _response.duration;
542
- const duration = _duration ? convertMilliseconds(_duration, logger.responseTimeDigits) : '-';
543
- let _contentLength = _headers ? _headers[ rsh.CONTENT_LENGTH ] : null;
544
- if (!_contentLength) _contentLength = _data ? sizeof(_data) : null;
545
- const contentLength = _contentLength ? `- ${ convertBytes(_contentLength, logger.contentLengthDigits) }` : null;
546
- const data = _data ? JSON.stringify(_data) : null;
547
- const parts = [ prefix, method, path, status, duration, contentLength, data ];
548
- const message = _.compact(parts).join(' ');
549
- logger.error(message);
550
- }
551
-
552
- static writeAxiosResponseLog(axiosResponse, logOptions, options) {
553
- logOptions = logOptions || { };
554
- options = options || { };
555
- if (!axiosResponse || !axiosResponse.request) return;
556
- const _request = axiosResponse.request;
557
- const axiosConfig = logOptions.axios || { };
558
- const configData = (logOptions.data && _.isObject(axiosConfig.data)) ? JSON.stringify(axiosConfig.data) : null;
559
- const logLevel = massageLogLevel(logOptions.logLevel);
560
- const logger = options.logger || ZeddemoreLogger.getLogger(options);
561
- if (!logger) return;
562
- const _method = _request.method || null;
563
- const method = _method ? chalkHttpVerbs(_method) : null;
564
- const _headers = axiosResponse.headers || null;
565
- const _data = axiosResponse.data || null;
566
- const path = _request.path || '';
567
- const prefix = logOptions.prefix ? `[${ logOptions.prefix }]` : null;
568
- const responseData = (logOptions.response && _.isObject(_data)) ? JSON.stringify(_data) : null;
569
- const status = chalkHttpStatuses(axiosResponse.status);
570
- const _duration = axiosResponse.duration;
571
- const duration = _duration ? convertMilliseconds(_duration, logger.responseTimeDigits) : '-';
572
- let _contentLength = _headers ? _headers[ rsh.CONTENT_LENGTH ] : null;
573
- if (!_contentLength) _contentLength = _data ? sizeof(_data) : null;
574
- const contentLength = _contentLength ? `- ${ convertBytes(_contentLength, logger.contentLengthDigits) }` : null;
575
- const parts = [ prefix, method, path, configData, status, responseData, duration, contentLength ];
576
- const message = _.compact(parts).join(' ');
577
- logger[ logLevel ](message);
578
- }
579
-
580
- }
3
+ const { logLevelIdToWinstonLogLevelName } = require('./logging');
4
+ const ZeddemoreLogger = require('./ZeddemoreLogger');
581
5
 
582
6
  module.exports = {
7
+ enums: require('./enums'),
583
8
  log: ZeddemoreLogger.getLogger,
584
- winstonLogLevelIdToName,
9
+ logLevelIdToWinstonLogLevelName,
10
+ winstonLogLevelIdToName: logLevelIdToWinstonLogLevelName, // deprecated naming
585
11
  writeAxiosErrorLog: ZeddemoreLogger.writeAxiosErrorLog,
586
12
  writeAxiosLog: ZeddemoreLogger.writeAxiosResponseLog, // deprecated
587
13
  writeAxiosResponseLog: ZeddemoreLogger.writeAxiosResponseLog,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeddemore-logger",
3
- "version": "1.2.4",
3
+ "version": "2.0.0",
4
4
  "description": "Node.js Express logger using Morgan and Winston for thread and caller info tracking",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,8 +21,10 @@
21
21
  "main": "lib/zeddemore-logger.js",
22
22
  "dependencies": {
23
23
  "chalk": "^4.1.2",
24
+ "cli-progress": "^3.12.0",
24
25
  "lodash": "^4.17.21",
25
- "morgan": "^1.10.0",
26
+ "luxon": "^3.7.1",
27
+ "morgan": "^1.10.1",
26
28
  "object-sizeof": "^2.6.5",
27
29
  "uuid": "^10.0.0",
28
30
  "winston": "^3.17.0"