zeddemore-logger 1.0.7 → 1.1.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.
- package/lib/enums.js +53 -0
- package/lib/mappings/color_mappings.js +28 -27
- package/lib/mappings/http_mappings.js +18 -0
- package/lib/{http.js → request.js} +23 -3
- package/lib/response.js +36 -0
- package/lib/zeddemore-logger.js +109 -7
- package/package.json +1 -1
package/lib/enums.js
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
// Copyright (c) 2025 by Beardon Services, Inc.
|
|
2
2
|
|
|
3
|
+
const ansi256Colors = {
|
|
4
|
+
LOG_LEVEL_DEBUG: 34, // blue
|
|
5
|
+
LOG_LEVEL_ERROR: 31, // red
|
|
6
|
+
LOG_LEVEL_HTTP: 32, // green
|
|
7
|
+
LOG_LEVEL_INFO: 32, // green
|
|
8
|
+
LOG_LEVEL_SILLY: 35, // magenta
|
|
9
|
+
LOG_LEVEL_VERBOSE: 36, // cyan
|
|
10
|
+
LOG_LEVEL_WARNING: 33, // yellow
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const ansiColors = {
|
|
14
|
+
HTTP_CLIENT_ERROR: 33, // red
|
|
15
|
+
HTTP_INFORMATIONAL: 0,
|
|
16
|
+
HTTP_REDIRECTION: 36, // blue
|
|
17
|
+
HTTP_SERVER_ERROR: 31, // red
|
|
18
|
+
HTTP_SUCCESSFUL: 32, // green
|
|
19
|
+
};
|
|
20
|
+
|
|
3
21
|
const apiLogLevelCaptions = {
|
|
4
22
|
DEFAULT: 'Default',
|
|
5
23
|
ERROR: 'Error',
|
|
@@ -42,6 +60,34 @@ const databaseOperations = {
|
|
|
42
60
|
UPDATE: 'UPDATE',
|
|
43
61
|
};
|
|
44
62
|
|
|
63
|
+
const hexColors = {
|
|
64
|
+
BLACK: '#000000',
|
|
65
|
+
CONSOLE_WHITE: '#ECECEC',
|
|
66
|
+
DB_DELETE: '#F22613',
|
|
67
|
+
DB_INSERT: '#00B16A',
|
|
68
|
+
DB_SELECT: '#1E90FF',
|
|
69
|
+
DB_TRUNCATE: '#750505',
|
|
70
|
+
DB_UPDATE: '#F9690E',
|
|
71
|
+
HTTP_CONNECT: '#FFFFFF',
|
|
72
|
+
HTTP_DELETE: '#EF968A',
|
|
73
|
+
HTTP_GET: '#67D193',
|
|
74
|
+
HTTP_HEAD: '#68D696',
|
|
75
|
+
HTTP_OPTIONS: '#E55AA8',
|
|
76
|
+
HTTP_PATCH: '#C0A8E1',
|
|
77
|
+
HTTP_POST: '#F4DA7A',
|
|
78
|
+
HTTP_PUT: '#74AEF6',
|
|
79
|
+
HTTP_TRACE: '#FFFFFF',
|
|
80
|
+
OSU_ORANGE: '#FF6600',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const httpStatusCodeGroups = {
|
|
84
|
+
INFORMATIONAL: 1,
|
|
85
|
+
SUCCESSFUL: 2,
|
|
86
|
+
REDIRECTION: 3,
|
|
87
|
+
CLIENT_ERROR: 4,
|
|
88
|
+
SERVER_ERROR: 5,
|
|
89
|
+
};
|
|
90
|
+
|
|
45
91
|
const httpMethods = {
|
|
46
92
|
GET: 'GET',
|
|
47
93
|
HEAD: 'HEAD',
|
|
@@ -56,9 +102,12 @@ const httpMethods = {
|
|
|
56
102
|
|
|
57
103
|
const httpRequestHeaders = {
|
|
58
104
|
ALLOW: 'Allow',
|
|
105
|
+
APP_VERSION: 'App-Version',
|
|
59
106
|
AUTHORIZATION: 'Authorization',
|
|
60
107
|
BEARER_PREFIX: 'Bearer',
|
|
108
|
+
FORWARDED_FOR: 'X-Forwarded-For',
|
|
61
109
|
REQUEST_ID: 'X-Request-Id',
|
|
110
|
+
USER_AGENT: 'User-Agent',
|
|
62
111
|
};
|
|
63
112
|
|
|
64
113
|
const httpResponseHeaders = {
|
|
@@ -96,11 +145,15 @@ const winstonLogLevels = {
|
|
|
96
145
|
};
|
|
97
146
|
|
|
98
147
|
module.exports = {
|
|
148
|
+
ansi256Colors,
|
|
149
|
+
ansiColors,
|
|
99
150
|
apiLogLevelCaptions,
|
|
100
151
|
apiLogLevels,
|
|
101
152
|
chalkFormats,
|
|
102
153
|
chalkLayers,
|
|
103
154
|
databaseOperations,
|
|
155
|
+
hexColors,
|
|
156
|
+
httpStatusCodeGroups,
|
|
104
157
|
httpMethods,
|
|
105
158
|
httpRequestHeaders,
|
|
106
159
|
httpResponseHeaders,
|
|
@@ -3,44 +3,45 @@
|
|
|
3
3
|
const _ = require('lodash');
|
|
4
4
|
const enums = require('../enums');
|
|
5
5
|
|
|
6
|
-
const {
|
|
6
|
+
const { ansi256Colors: a256c, ansiColors: ac, databaseOperations: dbo, chalkFormats: cs, hexColors: hc,
|
|
7
|
+
httpMethods: http, winstonLogLevels: wll } = enums;
|
|
7
8
|
|
|
8
9
|
const databaseOperationColors = [
|
|
9
|
-
{ match: dbo.DELETE, style: { format: cs.HEX, fore:
|
|
10
|
-
{ match: dbo.INSERT, style: { format: cs.HEX, fore:
|
|
11
|
-
{ match: dbo.SELECT, style: { format: cs.HEX, fore:
|
|
12
|
-
{ match: dbo.TRUNCATE, style: { format: cs.HEX, fore:
|
|
13
|
-
{ match: dbo.UPDATE, style: { format: cs.HEX, fore:
|
|
10
|
+
{ match: dbo.DELETE, style: { format: cs.HEX, fore: hc.DB_DELETE, back: null } },
|
|
11
|
+
{ match: dbo.INSERT, style: { format: cs.HEX, fore: hc.DB_INSERT, back: null } },
|
|
12
|
+
{ match: dbo.SELECT, style: { format: cs.HEX, fore: hc.DB_SELECT, back: null } },
|
|
13
|
+
{ match: dbo.TRUNCATE, style: { format: cs.HEX, fore: hc.DB_TRUNCATE, back: null } },
|
|
14
|
+
{ match: dbo.UPDATE, style: { format: cs.HEX, fore: hc.DB_UPDATE, back: null } },
|
|
14
15
|
];
|
|
15
16
|
|
|
16
17
|
const httpStatusColors = [
|
|
17
|
-
{ range: _.range(500, 600), style: { format: cs.ANSI, fore:
|
|
18
|
-
{ range: _.range(400, 500), style: { format: cs.ANSI, fore:
|
|
19
|
-
{ range: _.range(300, 400), style: { format: cs.ANSI, fore:
|
|
20
|
-
{ range: _.range(200, 300), style: { format: cs.ANSI, fore:
|
|
21
|
-
{ range: _.range(100, 200), style: { format: cs.ANSI, fore:
|
|
18
|
+
{ range: _.range(500, 600), style: { format: cs.ANSI, fore: ac.HTTP_SERVER_ERROR, back: null } },
|
|
19
|
+
{ range: _.range(400, 500), style: { format: cs.ANSI, fore: ac.HTTP_CLIENT_ERROR, back: null } },
|
|
20
|
+
{ range: _.range(300, 400), style: { format: cs.ANSI, fore: ac.HTTP_REDIRECTION, back: null } },
|
|
21
|
+
{ range: _.range(200, 300), style: { format: cs.ANSI, fore: ac.HTTP_SUCCESSFUL, back: null } },
|
|
22
|
+
{ range: _.range(100, 200), style: { format: cs.ANSI, fore: ac.HTTP_INFORMATIONAL, back: null } },
|
|
22
23
|
];
|
|
23
24
|
|
|
24
25
|
const httpVerbColors = [
|
|
25
|
-
{ match: http.
|
|
26
|
-
{ match: http.
|
|
27
|
-
{ match: http.
|
|
28
|
-
{ match: http.
|
|
29
|
-
{ match: http.
|
|
30
|
-
{ match: http.
|
|
31
|
-
{ match: http.
|
|
32
|
-
{ match: http.
|
|
33
|
-
{ match: http.
|
|
26
|
+
{ match: http.CONNECT, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_CONNECT } },
|
|
27
|
+
{ match: http.DELETE, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_DELETE } },
|
|
28
|
+
{ match: http.GET, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_GET } },
|
|
29
|
+
{ match: http.HEAD, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_HEAD } },
|
|
30
|
+
{ match: http.OPTIONS, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_OPTIONS } },
|
|
31
|
+
{ match: http.PATCH, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_PATCH } },
|
|
32
|
+
{ match: http.POST, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_POST } },
|
|
33
|
+
{ match: http.PUT, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_PUT } },
|
|
34
|
+
{ match: http.TRACE, style: { format: cs.HEX, fore: hc.BLACK, back: hc.HTTP_TRACE } },
|
|
34
35
|
];
|
|
35
36
|
|
|
36
37
|
const logLevelColors = [
|
|
37
|
-
{ match: wll.ERROR, style: { format: cs.ANSI256, fore:
|
|
38
|
-
{ match: wll.WARNING, style: { format: cs.ANSI256, fore:
|
|
39
|
-
{ match: wll.INFO, style: { format: cs.ANSI256, fore:
|
|
40
|
-
{ match: wll.HTTP, style: { format: cs.ANSI256, fore:
|
|
41
|
-
{ match: wll.VERBOSE, style: { format: cs.ANSI256, fore:
|
|
42
|
-
{ match: wll.DEBUG, style: { format: cs.ANSI256, fore:
|
|
43
|
-
{ match: wll.SILLY, style: { format: cs.ANSI256, fore:
|
|
38
|
+
{ match: wll.ERROR, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_ERROR, back: null } },
|
|
39
|
+
{ match: wll.WARNING, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_WARNING, back: null } },
|
|
40
|
+
{ match: wll.INFO, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_INFO, back: null } },
|
|
41
|
+
{ match: wll.HTTP, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_HTTP, back: null } },
|
|
42
|
+
{ match: wll.VERBOSE, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_VERBOSE, back: null } },
|
|
43
|
+
{ match: wll.DEBUG, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_DEBUG, back: null } },
|
|
44
|
+
{ match: wll.SILLY, style: { format: cs.ANSI256, fore: a256c.LOG_LEVEL_SILLY, back: null } },
|
|
44
45
|
];
|
|
45
46
|
|
|
46
47
|
module.exports = {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Copyright (c) 2025 by Beardon Services, Inc.
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const enums = require('../enums');
|
|
5
|
+
|
|
6
|
+
const { httpStatusCodeGroups: hscg } = enums;
|
|
7
|
+
|
|
8
|
+
const httpStatusCodeGroupMap = [
|
|
9
|
+
{ group: hscg.INFORMATIONAL, range: _.range(100, 200) },
|
|
10
|
+
{ group: hscg.SUCCESSFUL, range: _.range(200, 300) },
|
|
11
|
+
{ group: hscg.REDIRECTION, range: _.range(300, 400) },
|
|
12
|
+
{ group: hscg.CLIENT_ERROR, range: _.range(400, 500) },
|
|
13
|
+
{ group: hscg.SERVER_ERROR, range: _.range(500, 600) },
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
module.exports = {
|
|
17
|
+
httpStatusCodeGroupMap,
|
|
18
|
+
};
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
// Copyright (c) 2025 by Beardon Services, Inc.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
const enums = require('./enums');
|
|
6
|
+
|
|
7
|
+
const { httpRequestHeaders: rqh } = enums;
|
|
8
|
+
|
|
9
|
+
function extractToken(req) {
|
|
10
|
+
let token;
|
|
11
|
+
const authHeader = req.header(rqh.AUTHORIZATION);
|
|
12
|
+
if (authHeader && authHeader.startsWith(`${ rqh.BEARER_PREFIX } `)) {
|
|
13
|
+
token = req.header(rqh.AUTHORIZATION).split(' ')[ 1 ];
|
|
14
|
+
} else if (req.query && req.query.token) {
|
|
15
|
+
token = req.query.token;
|
|
16
|
+
}
|
|
17
|
+
return token;
|
|
5
18
|
}
|
|
6
19
|
|
|
7
20
|
function getRequestResponseTime(req, res) {
|
|
@@ -9,6 +22,12 @@ function getRequestResponseTime(req, res) {
|
|
|
9
22
|
return (res._startAt[ 0 ] - req._startAt[ 0 ]) * 1e3 + (res._startAt[ 1 ] - req._startAt[ 1 ]) * 1e-6;
|
|
10
23
|
}
|
|
11
24
|
|
|
25
|
+
function isRequestOfMethod(req, method) {
|
|
26
|
+
const methods = Array.isArray(method) ? method : [ method ];
|
|
27
|
+
if (!req || !req.method || _.isEmpty(methods)) return false;
|
|
28
|
+
return methods.includes(req.method);
|
|
29
|
+
}
|
|
30
|
+
|
|
12
31
|
function parseRequest(req) {
|
|
13
32
|
if (!req) return { };
|
|
14
33
|
const body = req.body || { };
|
|
@@ -41,7 +60,8 @@ function parseRequestUserAgent(req) {
|
|
|
41
60
|
}
|
|
42
61
|
|
|
43
62
|
module.exports = {
|
|
44
|
-
|
|
63
|
+
extractToken,
|
|
45
64
|
getRequestResponseTime,
|
|
65
|
+
isRequestOfMethod,
|
|
46
66
|
parseRequest,
|
|
47
67
|
};
|
package/lib/response.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Copyright (c) 2025 by Beardon Services, Inc.
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
|
|
5
|
+
const enums = require('./enums');
|
|
6
|
+
const { httpStatusCodeGroupMap } = require('./mappings/http_mappings');
|
|
7
|
+
|
|
8
|
+
const { httpStatusCodeGroups: hscg } = enums;
|
|
9
|
+
|
|
10
|
+
function areHeadersSent(res) {
|
|
11
|
+
return typeof (res.headersSent !== 'boolean') ? Boolean(res._header) : res.headersSent;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isResponseStatusCodeInGroup(statusCode, group) {
|
|
15
|
+
if (!statusCode || !group) return false;
|
|
16
|
+
const httpStatusCodeGroupMapEntry = _.find(httpStatusCodeGroupMap, { group });
|
|
17
|
+
if (!httpStatusCodeGroupMapEntry) return false;
|
|
18
|
+
return httpStatusCodeGroupMapEntry.range.includes(+statusCode);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function isResponseStatusCodeRedirection(statusCode) {
|
|
22
|
+
return isResponseStatusCodeInGroup(statusCode, hscg.REDIRECTION);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isResponseStatusCodeSuccessful(statusCode) {
|
|
26
|
+
return isResponseStatusCodeInGroup(statusCode, hscg.SUCCESSFUL);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function isResponseSuccessful(statusCode) {
|
|
30
|
+
return isResponseStatusCodeSuccessful(statusCode) || isResponseStatusCodeRedirection(statusCode);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
areHeadersSent,
|
|
35
|
+
isResponseSuccessful,
|
|
36
|
+
};
|
package/lib/zeddemore-logger.js
CHANGED
|
@@ -7,15 +7,16 @@ const morgan = require('morgan');
|
|
|
7
7
|
const sizeof = require('object-sizeof');
|
|
8
8
|
const { v4: uuid } = require('uuid');
|
|
9
9
|
|
|
10
|
-
const { areHeadersSent,
|
|
10
|
+
const { areHeadersSent, isResponseSuccessful } = require('./response');
|
|
11
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
|
+
const { extractToken, getRequestResponseTime, isRequestOfMethod, parseRequest } = require('./request');
|
|
15
16
|
const { logLevelMap } = require('./mappings/log_mappings');
|
|
16
17
|
|
|
17
18
|
const { colorize, combine, label, metadata, printf, timestamp } = format;
|
|
18
|
-
const { morganFormats: mf, httpRequestHeaders: rqh, httpResponseHeaders: rsh, winstonLogLevelNames: wlln,
|
|
19
|
+
const { morganFormats: mf, httpMethods: http, httpRequestHeaders: rqh, httpResponseHeaders: rsh, winstonLogLevelNames: wlln,
|
|
19
20
|
winstonLogLevels: wll } = enums;
|
|
20
21
|
|
|
21
22
|
const COLOR_CONSOLE_WHITE_HEX = '#ECECEC';
|
|
@@ -41,10 +42,14 @@ class ZeddemoreLogger {
|
|
|
41
42
|
|
|
42
43
|
constructor(options) {
|
|
43
44
|
options = options || { };
|
|
44
|
-
this.
|
|
45
|
+
this.apiCallModel = options.apiCallModel || null;
|
|
46
|
+
this.apiRoutes = options.apiRoutes || [ ];
|
|
47
|
+
this.apiVersion = options.apiVersion || null;
|
|
45
48
|
this.defaultLabel = options.defaultLabel || 'zeddemore-logger';
|
|
49
|
+
this.disableApiCallLogging = options.hasOwnProperty('disableApiCallLogging') ? options.disableApiCallLogging : false;
|
|
50
|
+
this.disableRouteLogging = options.hasOwnProperty('disableRouteLogging') ? options.disableRouteLogging : false;
|
|
46
51
|
this.disableMorganLogging = options.hasOwnProperty('disableMorganLogging') ? options.disableMorganLogging : false;
|
|
47
|
-
this.displayCaller = options.hasOwnProperty('displayCaller') ? options.
|
|
52
|
+
this.displayCaller = options.hasOwnProperty('displayCaller') ? options.displayCaller : true;
|
|
48
53
|
this.displayIpAddress = options.hasOwnProperty('displayIpAddress') ? options.displayIpAddress : true;
|
|
49
54
|
this.displayRequestId = options.hasOwnProperty('displayRequestId') ? options.displayRequestId : true;
|
|
50
55
|
this.customCallerSettings = options.customCallerSettings || [ ];
|
|
@@ -52,11 +57,18 @@ class ZeddemoreLogger {
|
|
|
52
57
|
this.#forceLogLevel = options.hasOwnProperty('forceLogLevel') ? options.forceLogLevel : false;
|
|
53
58
|
this.#logLevel = options.hasOwnProperty('logLevel') ? options.logLevel : wll.INFO;
|
|
54
59
|
this.morganFormat = options.morganFormat || mf.DEV_ENHANCED;
|
|
60
|
+
this.routeModel = options.routeModel || null;
|
|
61
|
+
this.suppressNonMutatingRequestApiCallLogging = options.hasOwnProperty('suppressNonMutatingRequestApiCallLogging') ? options.suppressNonMutatingRequestApiCallLogging : false;
|
|
62
|
+
this.suppressSuccessfulRequestApiCallLogging = options.hasOwnProperty('suppressSuccessfulRequestApiCallLogging') ? options.suppressSuccessfulRequestApiCallLogging : false;
|
|
55
63
|
this.timestampFormat = options.timestampFormat || 'YYYY-MM-DD HH:mm:ss';
|
|
56
64
|
this.requestIdAttribute = options.requestIdAttribute || DEFAULT_REQUEST_ID_ATTRIBUTE;
|
|
57
65
|
this.userGetFn = options.userGetFn || this.#userGetFn;
|
|
58
66
|
}
|
|
59
67
|
|
|
68
|
+
get apiCallLoggingEnabled() {
|
|
69
|
+
return !this.disableApiCallLogging && !!this.apiCallModel;
|
|
70
|
+
}
|
|
71
|
+
|
|
60
72
|
get forceLogLevel() {
|
|
61
73
|
return this.#forceLogLevel;
|
|
62
74
|
}
|
|
@@ -69,6 +81,10 @@ class ZeddemoreLogger {
|
|
|
69
81
|
return winstonLogLevelIdToName(this.#logLevel);
|
|
70
82
|
}
|
|
71
83
|
|
|
84
|
+
get routeLoggingEnabled() {
|
|
85
|
+
return !this.disableRouteLogging && !!this.routeModel;
|
|
86
|
+
}
|
|
87
|
+
|
|
72
88
|
set forceLogLevel(doForce) {
|
|
73
89
|
this.#forceLogLevel = !!doForce;
|
|
74
90
|
}
|
|
@@ -215,9 +231,20 @@ class ZeddemoreLogger {
|
|
|
215
231
|
return zeddemoreLogger.createLogger(options);
|
|
216
232
|
}
|
|
217
233
|
|
|
234
|
+
#matchPathToRoute = (path) => {
|
|
235
|
+
if (!path) return null;
|
|
236
|
+
let matchedRoute = null;
|
|
237
|
+
for (const route of this.apiRoutes) {
|
|
238
|
+
if (path.match(route.regexp)) {
|
|
239
|
+
matchedRoute = route.path;
|
|
240
|
+
break;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return matchedRoute;
|
|
244
|
+
}
|
|
245
|
+
|
|
218
246
|
morganMiddleware = (options) => {
|
|
219
247
|
options = options || { };
|
|
220
|
-
const additionalWriteFn = (_.isFunction(options.additionalWriteFn) ? options.additionalWriteFn : null) || this.additionalWriteFn;
|
|
221
248
|
const disableMorganLogging = options.hasOwnProperty('disableMorganLogging') ? options.disableMorganLogging : this.disableMorganLogging;
|
|
222
249
|
const morganFormat = options.morganFormat || this.morganFormat;
|
|
223
250
|
const userGetFn = (_.isFunction(options.userGetFn) ? options.userGetFn : null) || this.userGetFn;
|
|
@@ -227,7 +254,7 @@ class ZeddemoreLogger {
|
|
|
227
254
|
skip: () => disableMorganLogging,
|
|
228
255
|
stream: {
|
|
229
256
|
write: (message) => {
|
|
230
|
-
if (
|
|
257
|
+
if (this.apiCallLoggingEnabled) this.#writeApiCallToDatabase(req, res, options);
|
|
231
258
|
const logOptions = { };
|
|
232
259
|
const user = userGetFn ? userGetFn(req, res) : null;
|
|
233
260
|
if (user) logOptions.user = user;
|
|
@@ -250,6 +277,21 @@ class ZeddemoreLogger {
|
|
|
250
277
|
return next();
|
|
251
278
|
}
|
|
252
279
|
|
|
280
|
+
routeLoggingMiddleware = (req, res, next) => {
|
|
281
|
+
if (!this.routeLoggingEnabled) return next();
|
|
282
|
+
try {
|
|
283
|
+
const routeValues = {
|
|
284
|
+
route: req.path,
|
|
285
|
+
method: req.method,
|
|
286
|
+
lastCalled: new Date().toISOString(),
|
|
287
|
+
};
|
|
288
|
+
this.#writeRouteToDatabase(routeValues);
|
|
289
|
+
} catch (e) {
|
|
290
|
+
} finally {
|
|
291
|
+
next();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
253
295
|
#userGetFn(req, res) {
|
|
254
296
|
return ((res && res.locals) ? res.locals.user : null)
|
|
255
297
|
|| ((req && req.locals) ? req.locals.user : null)
|
|
@@ -260,7 +302,7 @@ class ZeddemoreLogger {
|
|
|
260
302
|
const requestId = this.#getRequestId(req);
|
|
261
303
|
const user = this.userGetFn(req, res) || { };
|
|
262
304
|
if (!requestId) return next();
|
|
263
|
-
const username = user.login || null;
|
|
305
|
+
const username = user.login || user.username || null;
|
|
264
306
|
let ipAddress = user.ipAddress || null;
|
|
265
307
|
if (!ipAddress) {
|
|
266
308
|
const requestValues = parseRequest(req);
|
|
@@ -275,6 +317,66 @@ class ZeddemoreLogger {
|
|
|
275
317
|
return next();
|
|
276
318
|
}
|
|
277
319
|
|
|
320
|
+
#writeApiCallToDatabase = async (req, res, options) => {
|
|
321
|
+
options = options || { };
|
|
322
|
+
if (!req) return;
|
|
323
|
+
const user = this.userGetFn ? this.userGetFn(req, res) : null;
|
|
324
|
+
const statusCode = options.statusCode || (res ? res.statusCode : null);
|
|
325
|
+
if (isResponseSuccessful(statusCode) && this.suppressSuccessfulRequestApiCallLogging) return;
|
|
326
|
+
if (!isRequestOfMethod(req, [ http.DELETE, http.PUT ]) && this.suppressNonMutatingRequestApiCallLogging) return;
|
|
327
|
+
const matchedRoute = this.#matchPathToRoute(req.path);
|
|
328
|
+
let metadataDefaults = Object.assign({ }, user);
|
|
329
|
+
delete(metadataDefaults.id);
|
|
330
|
+
delete(metadataDefaults.logger);
|
|
331
|
+
const _metadata = _.defaults({ }, (options.metadata || { }), metadataDefaults);
|
|
332
|
+
if (matchedRoute) {
|
|
333
|
+
try {
|
|
334
|
+
const appCallValues = {
|
|
335
|
+
apiVersion: this.apiVersion,
|
|
336
|
+
client: user ? user.clientId : null,
|
|
337
|
+
clientVersion: req.header(rqh.APP_VERSION),
|
|
338
|
+
httpStatusCode: statusCode,
|
|
339
|
+
ipAddress: req.header(rqh.FORWARDED_FOR) || req.socket.remoteAddress,
|
|
340
|
+
metadata: _metadata,
|
|
341
|
+
method: req.method,
|
|
342
|
+
route: matchedRoute,
|
|
343
|
+
token: extractToken(req),
|
|
344
|
+
userAgent: req.header(rqh.USER_AGENT),
|
|
345
|
+
userId: user ? user.id : null,
|
|
346
|
+
};
|
|
347
|
+
await this.apiCallModel.create(appCallValues);
|
|
348
|
+
} catch (e) {
|
|
349
|
+
console.error(e);
|
|
350
|
+
ZeddemoreLogger.log({ user }).error('Api call logging failed, moving on');
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
#writeRouteToDatabase = async (routeValues) => {
|
|
356
|
+
if (!this.routeLoggingEnabled || !routeValues) return;
|
|
357
|
+
const matchedRoute = this.#matchPathToRoute(routeValues.route);
|
|
358
|
+
if (matchedRoute) {
|
|
359
|
+
try {
|
|
360
|
+
const route = await this.routeModel.findOne({ where: { route: matchedRoute }, logging: false });
|
|
361
|
+
if (route) {
|
|
362
|
+
route.count++;
|
|
363
|
+
route.lastCalledAt = new Date();
|
|
364
|
+
route.save();
|
|
365
|
+
} else {
|
|
366
|
+
this.routeModel.create({
|
|
367
|
+
count: 1,
|
|
368
|
+
lastCalledAt: new Date(),
|
|
369
|
+
method: routeValues.method,
|
|
370
|
+
route: matchedRoute,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
} catch (e) {
|
|
374
|
+
console.error(e);
|
|
375
|
+
console.error('Route logging failed, moving on');
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
278
380
|
static writeAxiosErrorLog(axiosError, logOptions, options) {
|
|
279
381
|
logOptions = logOptions || { };
|
|
280
382
|
options = options || { };
|