zeddemore-logger 1.0.6 → 1.0.7

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/color.js CHANGED
@@ -1,43 +1,119 @@
1
- // Copyright (c) 2025 by Beardon Services, Inc.
1
+ // Copyright (c) 2024-2025 by Beardon Services, Inc.
2
2
 
3
3
  const _ = require('lodash');
4
4
  const chalk = require('chalk');
5
5
 
6
6
  const colorMappings = require('./mappings/color_mappings');
7
+ const enums = require('./enums');
7
8
 
8
- function chalkDatabaseOperation(operation, string = null) {
9
- if (!string) string = operation;
10
- return chalkViaColorMap(operation, string, colorMappings.databaseOperationColors, true);
9
+ const { chalkLayers: cl, chalkFormats: cs } = enums;
10
+
11
+ /**
12
+ * @param ansiColor {number}
13
+ * @param layer {string}
14
+ * @param string {string}
15
+ * @returns {string}
16
+ */
17
+ function chalkAnsi(ansiColor, layer = cl.FOREGROUND, string) {
18
+ if (!string) return '';
19
+ if (!ansiColor) return string;
20
+ switch (layer) {
21
+ case cl.BACKGROUND: return `\x1B[${ ansiColor }m${ string }\x1B[49m`;
22
+ case cl.FOREGROUND: return `\x1B[${ ansiColor }m${ string }\x1B[39m`;
23
+ default: return string;
24
+ }
25
+ }
26
+
27
+ /**
28
+ * @param ansiColor {number}
29
+ * @param layer {string}
30
+ * @param string {string}
31
+ * @returns {string}
32
+ */
33
+ function chalkAnsi256(ansiColor, layer = cl.FOREGROUND, string) {
34
+ if (!string) return '';
35
+ if (!ansiColor) return string;
36
+ switch (layer) {
37
+ case cl.BACKGROUND: return chalk.bgAnsi256(ansiColor)(string);
38
+ case cl.FOREGROUND: return chalk.ansi256(ansiColor)(string);
39
+ default: return string;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * @param hexColor {string}
45
+ * @param layer {string}
46
+ * @param string {string}
47
+ * @returns {string}
48
+ */
49
+ function chalkHex(hexColor, layer = cl.FOREGROUND, string) {
50
+ if (!string) return '';
51
+ if (!hexColor) return string;
52
+ hexColor = (hexColor[ 0 ] === '#') ? hexColor : `#${ hexColor }`;
53
+ switch (layer) {
54
+ case cl.BACKGROUND: return chalk.bgHex(hexColor)(string);
55
+ case cl.FOREGROUND: return chalk.hex(hexColor)(string);
56
+ default: return string;
57
+ }
11
58
  }
12
59
 
13
- function chalkHttpStatus(statusCode) {
14
- const colorMap = _.find(colorMappings.httpStatusColors, (httpStatusColor) => httpStatusColor.range.includes(statusCode));
15
- if (!colorMap) return statusCode;
16
- let chalkedMatch = statusCode;
17
- if (colorMap.ansi) chalkedMatch = `\x1B[${ colorMap.ansi }m${ statusCode }\x1B[39m`;
60
+ function chalkHttpStatuses(statusCode, string = null) {
61
+ if (!string) string = statusCode;
62
+ const colorMap = _.find(colorMappings.httpStatusColors, (httpStatusColor) => httpStatusColor.range.includes(string));
63
+ if (!colorMap || !colorMap.style) return string;
64
+ let chalkedMatch = string;
65
+ if (colorMap.style.fore) chalkedMatch = `\x1B[${ colorMap.style.fore }m${ string }\x1B[39m`;
18
66
  return chalkedMatch;
19
67
  }
20
68
 
21
- function chalkHttpVerb(verb, string = null) {
69
+ function chalkHttpVerbs(verb, string = null, replaceGlobal = false) {
22
70
  if (!string) string = verb;
23
- return chalkViaColorMap(verb, string, colorMappings.httpVerbColors, false);
71
+ return chalkViaColorMap(verb, string, colorMappings.httpVerbColors, replaceGlobal);
72
+ }
73
+
74
+ /**
75
+ * @param redColor {number}
76
+ * @param greenColor {number}
77
+ * @param blueColor {number}
78
+ * @param layer {string}
79
+ * @param string {string}
80
+ * @returns {string}
81
+ */
82
+ function chalkRgb(redColor, greenColor, blueColor, layer = cl.FOREGROUND, string) {
83
+ if (!string) return '';
84
+ if (!redColor || !greenColor || !blueColor) return string;
85
+ switch (layer) {
86
+ case cl.BACKGROUND: return chalk.bgRgb(redColor, greenColor, blueColor)(string);
87
+ case cl.FOREGROUND: return chalk.rgb(redColor, greenColor, blueColor)(string);
88
+ default: return string;
89
+ }
90
+ }
91
+
92
+ function chalkTarget(target, style) {
93
+ if (!style) return target;
94
+ const fore = style.fore;
95
+ const back = style.back;
96
+ switch (style.format) {
97
+ case cs.ANSI: return chalkAnsi(back, cl.BACKGROUND, chalkAnsi(fore, cl.FOREGROUND, target));
98
+ case cs.ANSI256: return chalkAnsi256(back, cl.BACKGROUND, chalkAnsi256(fore, cl.FOREGROUND, target));
99
+ case cs.HEX: return chalkHex(back, cl.BACKGROUND, chalkHex(fore, cl.FOREGROUND, target));
100
+ case cs.RGB: return chalkRgb(back.r, back.g, back.b, cl.BACKGROUND, chalkRgb(fore.r, fore.g, fore.b, cl.FOREGROUND, target));
101
+ default: return target;
102
+ }
24
103
  }
25
104
 
26
- function chalkViaColorMap(match, string, colorMap, useGlobal = true) {
105
+ function chalkViaColorMap(match, target, colorsMap, replaceGlobal = true) {
27
106
  function fixPattern(pattern) {
28
- return pattern.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1');
107
+ return _.isString(pattern) ? pattern.replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1') : pattern;
29
108
  }
30
- if (!match || !_.isString(match) || !string || !_.isString(string) || !_.isObject(colorMap)) return string;
109
+ if (!match || !_.isString(match) || !target || !_.isString(target) || !_.isObject(colorsMap)) return target;
31
110
  const cleanMatch = match.replace(/[^A-Z]/g, '');
32
- const mapping = _.find(colorMap, { match: cleanMatch });
33
- if (!mapping) return string;
34
- const flags = useGlobal ? 'g' : '';
111
+ const colorMap = _.find(colorsMap, { match: cleanMatch });
112
+ if (!colorMap || !colorMap.style) return target;
113
+ const flags = replaceGlobal ? 'g' : '';
35
114
  const re = new RegExp(fixPattern(match), flags);
36
- if (!string.match(re)) return string;
37
- let chalkedMatch = cleanMatch;
38
- if (mapping.fore) chalkedMatch = chalk.hex(mapping.fore)(chalkedMatch);
39
- if (mapping.back) chalkedMatch = chalk.bgHex(mapping.back)(chalkedMatch);
40
- return string.replace(re, chalkedMatch);
115
+ if (!target.match(re)) return target;
116
+ return target.replace(re, chalkTarget(cleanMatch, colorMap.style));
41
117
  }
42
118
 
43
119
  // adapted from https://stackoverflow.com/a/44134328
@@ -100,8 +176,7 @@ function stringToIdempotentHslValues(str, hslOptions) {
100
176
  }
101
177
 
102
178
  module.exports = {
103
- chalkDatabaseOperation,
104
- chalkHttpStatus,
105
- chalkHttpVerb,
179
+ chalkHttpStatuses,
180
+ chalkHttpVerbs,
106
181
  stringToIdempotentHexColor,
107
182
  };
package/lib/enums.js CHANGED
@@ -22,6 +22,18 @@ const apiLogLevels = {
22
22
  SILLY: 6,
23
23
  };
24
24
 
25
+ const chalkFormats = {
26
+ ANSI: 'ansi',
27
+ ANSI256: 'ansi256',
28
+ HEX: 'hex',
29
+ RGB: 'rgb',
30
+ };
31
+
32
+ const chalkLayers = {
33
+ BACKGROUND: 'bg',
34
+ FOREGROUND: 'fg',
35
+ };
36
+
25
37
  const databaseOperations = {
26
38
  DELETE: 'DELETE',
27
39
  INSERT: 'INSERT',
@@ -86,6 +98,8 @@ const winstonLogLevels = {
86
98
  module.exports = {
87
99
  apiLogLevelCaptions,
88
100
  apiLogLevels,
101
+ chalkFormats,
102
+ chalkLayers,
89
103
  databaseOperations,
90
104
  httpMethods,
91
105
  httpRequestHeaders,
@@ -1,40 +1,51 @@
1
- // Copyright (c) 2025 by Beardon Services, Inc.
1
+ // Copyright (c) 2024-2025 by Beardon Services, Inc.
2
2
 
3
3
  const _ = require('lodash');
4
4
  const enums = require('../enums');
5
5
 
6
- const { databaseOperations: dbo, httpMethods: http } = enums;
6
+ const { databaseOperations: dbo, chalkFormats: cs, httpMethods: http, winstonLogLevels: wll } = enums;
7
7
 
8
8
  const databaseOperationColors = [
9
- { match: dbo.DELETE, fore: '#F22613', back: null },
10
- { match: dbo.INSERT, fore: '#00B16A', back: null },
11
- { match: dbo.SELECT, fore: '#1E90FF', back: null },
12
- { match: dbo.TRUNCATE, fore: '#750505', back: null },
13
- { match: dbo.UPDATE, fore: '#F9690E', back: null },
9
+ { match: dbo.DELETE, style: { format: cs.HEX, fore: '#F22613', back: null } },
10
+ { match: dbo.INSERT, style: { format: cs.HEX, fore: '#00B16A', back: null } },
11
+ { match: dbo.SELECT, style: { format: cs.HEX, fore: '#1E90FF', back: null } },
12
+ { match: dbo.TRUNCATE, style: { format: cs.HEX, fore: '#750505', back: null } },
13
+ { match: dbo.UPDATE, style: { format: cs.HEX, fore: '#F9690E', back: null } },
14
14
  ];
15
15
 
16
16
  const httpStatusColors = [
17
- { range: _.range(500, 600), ansi: 31 },
18
- { range: _.range(400, 500), ansi: 33 },
19
- { range: _.range(300, 400), ansi: 36 },
20
- { range: _.range(200, 300), ansi: 32 },
21
- { range: _.range(100, 200), ansi: 0 },
17
+ { range: _.range(500, 600), style: { format: cs.ANSI, fore: 31, back: null } },
18
+ { range: _.range(400, 500), style: { format: cs.ANSI, fore: 33, back: null } },
19
+ { range: _.range(300, 400), style: { format: cs.ANSI, fore: 36, back: null } },
20
+ { range: _.range(200, 300), style: { format: cs.ANSI, fore: 32, back: null } },
21
+ { range: _.range(100, 200), style: { format: cs.ANSI, fore: 0, back: null } },
22
22
  ];
23
23
 
24
24
  const httpVerbColors = [
25
- { match: http.GET, fore: '#000000', back: '#67D193' },
26
- { match: http.HEAD, fore: '#000000', back: '#68D696' },
27
- { match: http.POST, fore: '#000000', back: '#F4DA7A' },
28
- { match: http.PUT, fore: '#000000', back: '#74AEF6' },
29
- { match: http.DELETE, fore: '#000000', back: '#EF968A' },
30
- { match: http.CONNECT, fore: '#000000', back: '#FFFFFF' },
31
- { match: http.OPTIONS, fore: '#000000', back: '#E55AA8' },
32
- { match: http.TRACE, fore: '#000000', back: '#FFFFFF' },
33
- { match: http.PATCH, fore: '#000000', back: '#C0A8E1' },
25
+ { match: http.GET, style: { format: cs.HEX, fore: '#000000', back: '#67D193' } },
26
+ { match: http.HEAD, style: { format: cs.HEX, fore: '#000000', back: '#68D696' } },
27
+ { match: http.POST, style: { format: cs.HEX, fore: '#000000', back: '#F4DA7A' } },
28
+ { match: http.PUT, style: { format: cs.HEX, fore: '#000000', back: '#74AEF6' } },
29
+ { match: http.DELETE, style: { format: cs.HEX, fore: '#000000', back: '#EF968A' } },
30
+ { match: http.CONNECT, style: { format: cs.HEX, fore: '#000000', back: '#FFFFFF' } },
31
+ { match: http.OPTIONS, style: { format: cs.HEX, fore: '#000000', back: '#E55AA8' } },
32
+ { match: http.TRACE, style: { format: cs.HEX, fore: '#000000', back: '#FFFFFF' } },
33
+ { match: http.PATCH, style: { format: cs.HEX, fore: '#000000', back: '#C0A8E1' } },
34
+ ];
35
+
36
+ const logLevelColors = [
37
+ { match: wll.ERROR, style: { format: cs.ANSI256, fore: 31, back: null } }, // red
38
+ { match: wll.WARNING, style: { format: cs.ANSI256, fore: 33, back: null } }, // yellow
39
+ { match: wll.INFO, style: { format: cs.ANSI256, fore: 32, back: null } }, // green
40
+ { match: wll.HTTP, style: { format: cs.ANSI256, fore: 32, back: null } },
41
+ { match: wll.VERBOSE, style: { format: cs.ANSI256, fore: 36, back: null } }, // cyan
42
+ { match: wll.DEBUG, style: { format: cs.ANSI256, fore: 34, back: null } }, // blue
43
+ { match: wll.SILLY, style: { format: cs.ANSI256, fore: 35, back: null } }, // magenta
34
44
  ];
35
45
 
36
46
  module.exports = {
37
47
  databaseOperationColors,
38
48
  httpStatusColors,
39
49
  httpVerbColors,
50
+ logLevelColors,
40
51
  };
@@ -8,14 +8,15 @@ const sizeof = require('object-sizeof');
8
8
  const { v4: uuid } = require('uuid');
9
9
 
10
10
  const { areHeadersSent, getRequestResponseTime, parseRequest } = require('./http');
11
- const { chalkHttpStatus, chalkHttpVerb, stringToIdempotentHexColor } = require('./color');
11
+ const { chalkHttpStatuses, chalkHttpVerbs, stringToIdempotentHexColor } = require('./color');
12
12
  const { convertBytes } = require('./math');
13
13
  const { convertMilliseconds } = require('./date');
14
14
  const enums = require('./enums');
15
15
  const { logLevelMap } = require('./mappings/log_mappings');
16
16
 
17
17
  const { colorize, combine, label, metadata, printf, timestamp } = format;
18
- const { morganFormats: mf, httpRequestHeaders: rqh, httpResponseHeaders: rsh, winstonLogLevelNames: wlln, winstonLogLevels: wll } = enums;
18
+ const { morganFormats: mf, httpRequestHeaders: rqh, httpResponseHeaders: rsh, winstonLogLevelNames: wlln,
19
+ winstonLogLevels: wll } = enums;
19
20
 
20
21
  const COLOR_CONSOLE_WHITE_HEX = '#ECECEC';
21
22
  const DEFAULT_REQUEST_ID_ATTRIBUTE = 'requestId';
@@ -35,6 +36,9 @@ function winstonLogLevelIdToName(levelId) {
35
36
 
36
37
  class ZeddemoreLogger {
37
38
 
39
+ #forceLogLevel = false;
40
+ #logLevel = wll.INFO;
41
+
38
42
  constructor(options) {
39
43
  options = options || { };
40
44
  this.additionalWriteFn = options.additionalWriteFn || null;
@@ -45,17 +49,36 @@ class ZeddemoreLogger {
45
49
  this.displayRequestId = options.hasOwnProperty('displayRequestId') ? options.displayRequestId : true;
46
50
  this.customCallerSettings = options.customCallerSettings || [ ];
47
51
  this.defaultUserLogLevel = options.defaultUserLogLevel || DEFAULT_USER_LOG_LEVEL;
48
- this.forceLogLevel = options.hasOwnProperty('forceLogLevel') ? options.forceLogLevel : false;
49
- this.logLevel = options.hasOwnProperty('logLevel') ? options.logLevel : wll.INFO;
52
+ this.#forceLogLevel = options.hasOwnProperty('forceLogLevel') ? options.forceLogLevel : false;
53
+ this.#logLevel = options.hasOwnProperty('logLevel') ? options.logLevel : wll.INFO;
50
54
  this.morganFormat = options.morganFormat || mf.DEV_ENHANCED;
51
55
  this.timestampFormat = options.timestampFormat || 'YYYY-MM-DD HH:mm:ss';
52
56
  this.requestIdAttribute = options.requestIdAttribute || DEFAULT_REQUEST_ID_ATTRIBUTE;
53
57
  this.userGetFn = options.userGetFn || this.#userGetFn;
54
58
  }
55
59
 
56
- #buildWinstonFormat = (options, additionalFormats = [ ]) =>{
60
+ get forceLogLevel() {
61
+ return this.#forceLogLevel;
62
+ }
63
+
64
+ get logLevel() {
65
+ return this.#logLevel;
66
+ }
67
+
68
+ get logLevelName() {
69
+ return winstonLogLevelIdToName(this.#logLevel);
70
+ }
71
+
72
+ set forceLogLevel(doForce) {
73
+ this.#forceLogLevel = !!doForce;
74
+ }
75
+
76
+ set logLevel(level) {
77
+ this.#logLevel = massageLogLevel(level);
78
+ }
79
+
80
+ #buildWinstonFormat = (options, additionalFormats = [ ]) => {
57
81
  options = options || { };
58
- const colorizedTemplate = this.#colorizedTemplate.bind(this);
59
82
  const formats = [
60
83
  format((info) => {
61
84
  info.id = info.id || options.id || null;
@@ -72,13 +95,13 @@ class ZeddemoreLogger {
72
95
  return combine(...additionalFormats.concat(formats));
73
96
  }
74
97
 
75
- #buildWinstonTransport = (logLevel = this.logLevel) => {
76
- logLevel = logLevel || this.logLevel;
98
+ #buildWinstonTransport = (logLevel = this.#logLevel) => {
99
+ logLevel = logLevel || this.#logLevel;
77
100
  const level = winstonLogLevelIdToName(logLevel);
78
101
  return new transports.Console({ level, name: WINSTON_CONSOLE_TRANSPORT_NAME });
79
102
  }
80
103
 
81
- #buildWinstonTransports = (logLevel = this.logLevel, additionalTransports = [ ]) => {
104
+ #buildWinstonTransports = (logLevel = this.#logLevel, additionalTransports = [ ]) => {
82
105
  return additionalTransports.concat([ this.#buildWinstonTransport(logLevel) ]);
83
106
  }
84
107
 
@@ -91,7 +114,7 @@ class ZeddemoreLogger {
91
114
 
92
115
  #colorizeResponse(message) {
93
116
  const verb = message.split(' ')[ 0 ];
94
- return chalkHttpVerb(verb, message);
117
+ return chalkHttpVerbs(verb, message);
95
118
  }
96
119
 
97
120
  #colorizedTemplate = (info) => {
@@ -177,7 +200,7 @@ class ZeddemoreLogger {
177
200
  function buildStatusColoredToken(res) {
178
201
  const statusCode = areHeadersSent(res) ? res.statusCode : null;
179
202
  if (!statusCode) return '-';
180
- return chalkHttpStatus(statusCode);
203
+ return chalkHttpStatuses(statusCode);
181
204
  }
182
205
  morgan.token('content-length-format', (req, res) => { return buildContentLengthFormatToken(res); });
183
206
  morgan.token('response-time-format', (req, res) => { return buildResponseTimeFormatToken(req, res); });
@@ -244,8 +267,8 @@ class ZeddemoreLogger {
244
267
  ipAddress = requestValues.ipAddress;
245
268
  }
246
269
  let userLogLevel = !_.isNil(user.logLevel) ? user.logLevel : this.defaultUserLogLevel;
247
- if (userLogLevel < 0) userLogLevel = this.logLevel;
248
- const level = this.forceLogLevel ? this.logLevel : userLogLevel;
270
+ if (userLogLevel < 0) userLogLevel = this.#logLevel;
271
+ const level = this.#forceLogLevel ? this.#logLevel : userLogLevel;
249
272
  res.locals = res.locals || { };
250
273
  res.locals.user = res.locals.user || user;
251
274
  res.locals.user.logger = this.createUserLogger(requestId, username, level, ipAddress);
@@ -262,13 +285,13 @@ class ZeddemoreLogger {
262
285
  const logger = options.logger || ZeddemoreLogger.log(options);
263
286
  if (!logger) return;
264
287
  const _method = _request.method || null;
265
- const method = _method ? chalkHttpVerb(_method) : null;
288
+ const method = _method ? chalkHttpVerbs(_method) : null;
266
289
  const _config = _response.config || null;
267
290
  const _headers = _response.headers || null;
268
291
  const _data = _response.data || null;
269
292
  const path = _config ? _config.url : '';
270
293
  const prefix = logOptions.prefix ? `[${ logOptions.prefix }]` : null;
271
- const status = chalkHttpStatus(_response.status);
294
+ const status = chalkHttpStatuses(_response.status);
272
295
  const _duration = axiosError.duration || _response.duration;
273
296
  const duration = _duration ? convertMilliseconds(_duration) : '-';
274
297
  let _contentLength = _headers ? _headers[ rsh.CONTENT_LENGTH ] : null;
@@ -291,13 +314,13 @@ class ZeddemoreLogger {
291
314
  const logger = options.logger || ZeddemoreLogger.log(options);
292
315
  if (!logger) return;
293
316
  const _method = _request.method || null;
294
- const method = _method ? chalkHttpVerb(_method) : null;
317
+ const method = _method ? chalkHttpVerbs(_method) : null;
295
318
  const _headers = axiosResponse.headers || null;
296
319
  const _data = axiosResponse.data || null;
297
320
  const path = _request.path || '';
298
321
  const prefix = logOptions.prefix ? `[${ logOptions.prefix }]` : null;
299
322
  const responseData = (logOptions.response && _.isObject(_data)) ? JSON.stringify(_data) : null;
300
- const status = chalkHttpStatus(axiosResponse.status);
323
+ const status = chalkHttpStatuses(axiosResponse.status);
301
324
  const _duration = axiosResponse.duration;
302
325
  const duration = _duration ? convertMilliseconds(_duration) : '-';
303
326
  let _contentLength = _headers ? _headers[ rsh.CONTENT_LENGTH ] : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeddemore-logger",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "Node.js Express logger using Morgan and Winston for thread and caller info tracking",
5
5
  "repository": {
6
6
  "type": "git",