zeddemore-logger 1.2.5 → 2.0.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.
- package/README.md +1 -1
- package/lib/ZeddemoreBase.js +283 -0
- package/lib/ZeddemoreLogger.js +814 -0
- package/lib/ZeddemoreLoggerController.js +77 -0
- package/lib/ZeddemoreProgressMultibar.js +776 -0
- package/lib/date.js +24 -1
- package/lib/defaults.js +37 -0
- package/lib/enums.js +15 -0
- package/lib/logging.js +76 -0
- package/lib/typedef.js +33 -0
- package/lib/uuid.js +11 -0
- package/lib/zeddemore-logger.js +5 -581
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
// Copyright (c) 2025 by Beardon Services, Inc.
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { DateTime } = require('luxon');
|
|
6
|
+
|
|
7
|
+
const { convertFechaDateFormatToLuxon } = require('./date');
|
|
8
|
+
const defaults = require('./defaults');
|
|
9
|
+
const { isValidLogLevel, logLevelToWinstonLogLevelName, logLevelIdToWinstonLogLevelName } = require('./logging');
|
|
10
|
+
const { stringToIdempotentHexColor } = require('./color');
|
|
11
|
+
require('./typedef');
|
|
12
|
+
|
|
13
|
+
class ZeddemoreBase {
|
|
14
|
+
|
|
15
|
+
#contentLengthDigits = defaults.contentLengthDigits;
|
|
16
|
+
#defaultLabel = null;
|
|
17
|
+
#displayCaller = true;
|
|
18
|
+
#displayIpAddress = true;
|
|
19
|
+
#displayRequestId = true;
|
|
20
|
+
#colorize = true;
|
|
21
|
+
#customCallerSettings = [ ];
|
|
22
|
+
#defaultUserLogLevel = defaults.userLogLevel;
|
|
23
|
+
#forceLogLevel = false;
|
|
24
|
+
/** @type {String} */
|
|
25
|
+
#logLevel = defaults.winstonLogLevelName;
|
|
26
|
+
#requestIdAttribute = defaults.requestIdAttribute;
|
|
27
|
+
#responseTimeDigits = defaults.responseTimeDigits;
|
|
28
|
+
#timestampFormat = defaults.timestampFormat;
|
|
29
|
+
#userGetFn = null;
|
|
30
|
+
|
|
31
|
+
constructor(options) {
|
|
32
|
+
options = options || { };
|
|
33
|
+
this.colorize = options.colorize;
|
|
34
|
+
this.contentLengthDigits = options.contentLengthDigits;
|
|
35
|
+
this.defaultLabel = options.defaultLabel || this.constructor.name;
|
|
36
|
+
this.displayCaller = options.displayCaller;
|
|
37
|
+
this.displayIpAddress = options.displayIpAddress;
|
|
38
|
+
this.displayRequestId = options.displayRequestId;
|
|
39
|
+
this.customCallerSettings = options.customCallerSettings;
|
|
40
|
+
this.defaultUserLogLevel = options.userLogLevel;
|
|
41
|
+
this.forceLogLevel = options.forceLogLevel;
|
|
42
|
+
this.logLevel = options.logLevel;
|
|
43
|
+
this.responseTimeDigits = options.responseTimeDigits;
|
|
44
|
+
this.timestampFormat = options.timestampFormat;
|
|
45
|
+
this.requestIdAttribute = options.requestIdAttribute;
|
|
46
|
+
this.userGetFn = options.userGetFn;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get colorize() {
|
|
50
|
+
return this.#colorize;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
set colorize(doColorize) {
|
|
54
|
+
if (_.isBoolean(doColorize)) this.#colorize = doColorize;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get contentLengthDigits() {
|
|
58
|
+
return this.#contentLengthDigits;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
set contentLengthDigits(digits) {
|
|
62
|
+
if (_.isInteger(digits) && (digits >= 0)) this.#contentLengthDigits = digits;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get defaultLabel() {
|
|
66
|
+
return this.#defaultLabel;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
set defaultLabel(label) {
|
|
70
|
+
if (_.isString(label) && !!label.length) this.#defaultLabel = label;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get displayCaller() {
|
|
74
|
+
return this.#displayCaller;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
set displayCaller(doDisplay) {
|
|
78
|
+
if (_.isBoolean(doDisplay)) this.#displayCaller = doDisplay;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get displayIpAddress() {
|
|
82
|
+
return this.#displayIpAddress;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
set displayIpAddress(doDisplay) {
|
|
86
|
+
if (_.isBoolean(doDisplay)) this.#displayIpAddress = doDisplay;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get displayRequestId() {
|
|
90
|
+
return this.#displayRequestId;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
set displayRequestId(doDisplay) {
|
|
94
|
+
if (_.isBoolean(doDisplay)) this.#displayRequestId = doDisplay;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get customCallerSettings() {
|
|
98
|
+
return this.#customCallerSettings;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
set customCallerSettings(settings) {
|
|
102
|
+
if (_.isArray(settings)) this.#customCallerSettings = settings;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
get defaultUserLogLevel() {
|
|
106
|
+
return this.#defaultUserLogLevel;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
set defaultUserLogLevel(level) {
|
|
110
|
+
if (isValidLogLevel(level)) this.#defaultUserLogLevel = logLevelToWinstonLogLevelName(level);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
get forceLogLevel() {
|
|
114
|
+
return this.#forceLogLevel;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
set forceLogLevel(doForce) {
|
|
118
|
+
if (_.isBoolean(doForce)) this.#forceLogLevel = doForce;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** @type {String} */
|
|
122
|
+
get logLevel() {
|
|
123
|
+
return this.#logLevel;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
set logLevel(level) {
|
|
127
|
+
if (isValidLogLevel(level)) this.#logLevel = logLevelToWinstonLogLevelName(level);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get logLevelName() {
|
|
131
|
+
return logLevelIdToWinstonLogLevelName(this.logLevel);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
get luxonTimestampFormat() {
|
|
135
|
+
return convertFechaDateFormatToLuxon(this.timestampFormat);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
get responseTimeDigits() {
|
|
139
|
+
return this.#responseTimeDigits;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
set responseTimeDigits(digits) {
|
|
143
|
+
if (_.isInteger(digits) && (digits >= 0)) this.#responseTimeDigits = digits;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
get requestIdAttribute() {
|
|
147
|
+
return this.#requestIdAttribute;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
set requestIdAttribute(attribute) {
|
|
151
|
+
if (_.isString(attribute) && !!attribute.length) this.#requestIdAttribute = attribute;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get timestamp() {
|
|
155
|
+
return DateTime.now().toFormat(this.luxonTimestampFormat);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get timestampFormat() {
|
|
159
|
+
return this.#timestampFormat;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
set timestampFormat(format) {
|
|
163
|
+
if (_.isString(format) && !!format.length) this.#timestampFormat = format;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
get userGetFn() {
|
|
167
|
+
if (this.#isValidUserGetFn(this.#userGetFn)) return this.#userGetFn;
|
|
168
|
+
return this.#defaultUserGetFn;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
set userGetFn(fn) {
|
|
172
|
+
if (_.isFunction(fn)) this.#userGetFn = fn;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
get winstonTimestampFormat() {
|
|
176
|
+
return this.timestampFormat;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Build log message prefix
|
|
181
|
+
* @param {String} [level]
|
|
182
|
+
* @param {Metadata} [metadata]
|
|
183
|
+
* @param {Boolean} [colorize]
|
|
184
|
+
* @returns {string}
|
|
185
|
+
*/
|
|
186
|
+
_buildLogMessagePrefix = (level, metadata, colorize = this.colorize) => {
|
|
187
|
+
metadata = this._structureMetadata(metadata);
|
|
188
|
+
const callerDisplay = metadata.caller || metadata.ip;
|
|
189
|
+
const idHexColor = colorize ? stringToIdempotentHexColor(metadata.id, true) : null;
|
|
190
|
+
const callerHexColor = colorize ? this.#callerToHexColor(callerDisplay) : null;
|
|
191
|
+
const parts = [ ];
|
|
192
|
+
if (!!metadata.timestamp) parts.push(metadata.timestamp);
|
|
193
|
+
if (!!metadata.label) parts.push(`[${ metadata.label }]`);
|
|
194
|
+
if (!!level) parts.push(`${ level }:`);
|
|
195
|
+
if (!!metadata.id && this.displayRequestId) {
|
|
196
|
+
if (colorize) {
|
|
197
|
+
parts.push(chalk.bold.hex(idHexColor)(metadata.fullId));
|
|
198
|
+
} else {
|
|
199
|
+
parts.push(metadata.fullId);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const callerParts = [ ];
|
|
203
|
+
if (!!metadata.caller && this.displayCaller) {
|
|
204
|
+
/**
|
|
205
|
+
* @type {Object}
|
|
206
|
+
* @property {String} caller
|
|
207
|
+
* @property {String} [logPrefix]
|
|
208
|
+
*/
|
|
209
|
+
const customCallerSettings = _.find(this.customCallerSettings, { caller: metadata.caller });
|
|
210
|
+
const logPrefix = customCallerSettings ? customCallerSettings.logPrefix : null;
|
|
211
|
+
callerParts.push(logPrefix ? logPrefix + metadata.caller : metadata.caller);
|
|
212
|
+
}
|
|
213
|
+
if (!!metadata.ip && this.displayIpAddress) callerParts.push(metadata.ip);
|
|
214
|
+
const fullCaller = callerParts.join('@');
|
|
215
|
+
if (!!fullCaller) {
|
|
216
|
+
if (colorize) {
|
|
217
|
+
parts.push(`<${ chalk.underline.hex(callerHexColor).bold(fullCaller) }>`);
|
|
218
|
+
} else {
|
|
219
|
+
parts.push(`<${ fullCaller }>`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!!metadata.prefix) parts.push(`[${ metadata.prefix }]`);
|
|
223
|
+
return parts.join(' ').trim();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#callerToHexColor = (caller) => {
|
|
227
|
+
if (!caller) return defaults.colorConsoleWhiteHex;
|
|
228
|
+
const customCallerSetting = _.find(this.customCallerSettings, { caller });
|
|
229
|
+
if (customCallerSetting && customCallerSetting.color && customCallerSetting.color.fore) return customCallerSetting.color.fore;
|
|
230
|
+
return stringToIdempotentHexColor(caller, true);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get the user object from the request or response
|
|
235
|
+
* @param {Object} req
|
|
236
|
+
* @param {Object} [req.locals]
|
|
237
|
+
* @param {Object} [req.locals.user]
|
|
238
|
+
* @param {Object} [req.user]
|
|
239
|
+
* @param {Object} res
|
|
240
|
+
* @param {Object} [res.locals]
|
|
241
|
+
* @param {Object} [res.locals.user]
|
|
242
|
+
* @returns {Object|null}
|
|
243
|
+
*/
|
|
244
|
+
#defaultUserGetFn(req, res) {
|
|
245
|
+
const reqLocalsUser = (_.isObject(req) && _.isObject(req.locals) && _.isObject(req.locals.user)) ? req.locals.user : null;
|
|
246
|
+
const reqUser = (_.isObject(req) && _.isObject(req.user)) ? req.user : null;
|
|
247
|
+
const resLocalsUser = (_.isObject(res) && _.isObject(res.locals) && _.isObject(res.locals.user)) ? res.locals.user : null;
|
|
248
|
+
return resLocalsUser || reqLocalsUser || reqUser || null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
_getRequestId = (req) => {
|
|
252
|
+
if (!req) return null;
|
|
253
|
+
return req[ this.requestIdAttribute ];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
#isValidUserGetFn(fn) {
|
|
257
|
+
return _.isFunction(fn) && (fn.length === 2);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
_structureMetadata = (metadata) => {
|
|
261
|
+
metadata = (_.isObject(metadata)) ? metadata : { };
|
|
262
|
+
const id = metadata.id ? metadata.id.substring(0, 8) : null;
|
|
263
|
+
const label = metadata.label || null;
|
|
264
|
+
const subId = metadata.subId || null;
|
|
265
|
+
const target = metadata.target || null;
|
|
266
|
+
return {
|
|
267
|
+
caller: metadata.caller || metadata.user || null,
|
|
268
|
+
fullId: `${ defaults.requestIdIcon }${ id }${ (subId ? `[${ subId }]` : '') }`,
|
|
269
|
+
id,
|
|
270
|
+
ip: metadata.ip || null,
|
|
271
|
+
label: target || label || this.defaultLabel,
|
|
272
|
+
originalLabel: label,
|
|
273
|
+
prefix: metadata.prefix || null,
|
|
274
|
+
raw: !!metadata.raw,
|
|
275
|
+
subId,
|
|
276
|
+
target,
|
|
277
|
+
timestamp: metadata.timestamp || this.timestamp,
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
module.exports = ZeddemoreBase;
|