infront-logger 1.1.5 → 1.1.6
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 +9 -0
- package/dist/browser.d.ts +12 -0
- package/dist/browser.es.js +4176 -0
- package/dist/browser.umd.js +4180 -0
- package/package.json +14 -4
- package/dist/index.es.js +0 -608
- package/dist/index.umd.js +0 -612
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "infront-logger",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
".": {
|
|
13
13
|
"import": "./dist/index.es.js",
|
|
14
14
|
"require": "./dist/index.umd.js"
|
|
15
|
+
},
|
|
16
|
+
"./browser": {
|
|
17
|
+
"import": "./dist/browser.es.js",
|
|
18
|
+
"require": "./dist/browser.umd.js"
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
21
|
"keywords": [],
|
|
@@ -20,10 +24,12 @@
|
|
|
20
24
|
"devDependencies": {
|
|
21
25
|
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
|
22
26
|
"@esbuild-plugins/node-modules-polyfill": "^0.2.2",
|
|
27
|
+
"concurrently": "^8.2.2",
|
|
23
28
|
"rollup-plugin-copy": "^3.5.0",
|
|
24
29
|
"vite": "^5.0.12"
|
|
25
30
|
},
|
|
26
31
|
"dependencies": {
|
|
32
|
+
"@datadog/browser-logs": "~5.23.3",
|
|
27
33
|
"winston": "^3.11.0",
|
|
28
34
|
"winston-daily-rotate-file": "^4.7.1",
|
|
29
35
|
"infront-utils": "^1.0.1"
|
|
@@ -31,8 +37,12 @@
|
|
|
31
37
|
"scripts": {
|
|
32
38
|
"test": "echo \"Error: no test specified\" && exit 1",
|
|
33
39
|
"dev": "vite",
|
|
34
|
-
"build": "vite build",
|
|
35
|
-
"build:watch": "vite build --watch",
|
|
36
|
-
"
|
|
40
|
+
"build:node": "vite build",
|
|
41
|
+
"build:node:watch": "vite build --watch",
|
|
42
|
+
"build:browser:watch": "vite build --config vite.config.browser.js --watch",
|
|
43
|
+
"build:watch": "concurrently \"npm run build:node:watch\" \"npm run build:browser:watch\"",
|
|
44
|
+
"preview": "vite preview",
|
|
45
|
+
"build:browser": " vite build --config vite.config.browser.js",
|
|
46
|
+
"build": "concurrently \"npm run build:node\" \"npm run build:browser\""
|
|
37
47
|
}
|
|
38
48
|
}
|
package/dist/index.es.js
DELETED
|
@@ -1,608 +0,0 @@
|
|
|
1
|
-
require("winston-daily-rotate-file");
|
|
2
|
-
const { format: format$1, createLogger, transports, addColors } = require("winston");
|
|
3
|
-
require("util");
|
|
4
|
-
const colors = {
|
|
5
|
-
error: "red",
|
|
6
|
-
warn: "yellow",
|
|
7
|
-
info: "green",
|
|
8
|
-
http: "magenta",
|
|
9
|
-
debug: "white"
|
|
10
|
-
};
|
|
11
|
-
addColors(colors);
|
|
12
|
-
const OPTIONS$1 = {
|
|
13
|
-
dirname: "logs",
|
|
14
|
-
levels: {
|
|
15
|
-
error: 0,
|
|
16
|
-
warn: 1,
|
|
17
|
-
info: 2,
|
|
18
|
-
http: 3,
|
|
19
|
-
debug: 4
|
|
20
|
-
},
|
|
21
|
-
level: "info",
|
|
22
|
-
zippedArchive: false,
|
|
23
|
-
dateFormat: "YYYY-MM-DD HH:mm:ss:ms",
|
|
24
|
-
maxFiles: 2,
|
|
25
|
-
maxFileSize: "30m",
|
|
26
|
-
filename: "logs.log",
|
|
27
|
-
errorFilename: "error.log",
|
|
28
|
-
console: true,
|
|
29
|
-
file: true,
|
|
30
|
-
exclude: [],
|
|
31
|
-
createSymlink: true,
|
|
32
|
-
symlinkName: "logs.log",
|
|
33
|
-
consoleJSON: false
|
|
34
|
-
};
|
|
35
|
-
function fileFormatter(options) {
|
|
36
|
-
return format$1.combine(
|
|
37
|
-
format$1.errors({ stack: true }),
|
|
38
|
-
// {
|
|
39
|
-
// transform: (info) => {
|
|
40
|
-
// const args = [info.message, ...(info[Symbol.for('splat')] || [])];
|
|
41
|
-
// info.message = args.filter(Boolean).map(arg => {
|
|
42
|
-
// if(arg instanceof Error){
|
|
43
|
-
// return errorToJSON(arg);
|
|
44
|
-
// }
|
|
45
|
-
// return arg;
|
|
46
|
-
// });
|
|
47
|
-
//
|
|
48
|
-
// const msg = args.map(arg => {
|
|
49
|
-
// if (typeof arg == 'object')
|
|
50
|
-
// return inspect(arg, {compact: false, depth: Infinity});
|
|
51
|
-
// return arg;
|
|
52
|
-
// }).join(' ');
|
|
53
|
-
//
|
|
54
|
-
// info[Symbol.for('message')] = `${info[Symbol.for('level')]}: ${msg}${info.stack ? ' ' + info.stack : ''}`;
|
|
55
|
-
//
|
|
56
|
-
// if(options.exclude.some(string => msg.includes(string))) return null;
|
|
57
|
-
//
|
|
58
|
-
// return info;
|
|
59
|
-
// }
|
|
60
|
-
// },
|
|
61
|
-
format$1.timestamp({ format: options.dateFormat }),
|
|
62
|
-
format$1.json()
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
function consoleFormatter(options) {
|
|
66
|
-
let formatters = [
|
|
67
|
-
format$1.errors({ stack: true }),
|
|
68
|
-
format$1.printf((info) => {
|
|
69
|
-
if ((info == null ? void 0 : info.level) === "error" && info.stack) {
|
|
70
|
-
return `${info.stack}`;
|
|
71
|
-
} else {
|
|
72
|
-
return info.message;
|
|
73
|
-
}
|
|
74
|
-
}),
|
|
75
|
-
// options.consoleJSON? format.json() : {transform : (info)=>info},
|
|
76
|
-
options.consoleJSON ? format$1.json() : format$1.splat()
|
|
77
|
-
];
|
|
78
|
-
if (!options.consoleJSON) {
|
|
79
|
-
formatters.push(format$1.colorize({ all: true }));
|
|
80
|
-
}
|
|
81
|
-
return format$1.combine(...formatters);
|
|
82
|
-
}
|
|
83
|
-
function getFormatter(type, options) {
|
|
84
|
-
switch (type) {
|
|
85
|
-
case "file":
|
|
86
|
-
return fileFormatter(options);
|
|
87
|
-
case "access":
|
|
88
|
-
break;
|
|
89
|
-
case "console":
|
|
90
|
-
return consoleFormatter(options);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function createTransport(options) {
|
|
94
|
-
let formatter = getFormatter(options.format, options);
|
|
95
|
-
if (formatter) {
|
|
96
|
-
options.format = formatter;
|
|
97
|
-
} else {
|
|
98
|
-
delete options.format;
|
|
99
|
-
}
|
|
100
|
-
return new transports.DailyRotateFile(options);
|
|
101
|
-
}
|
|
102
|
-
class Logger {
|
|
103
|
-
constructor(options = {}) {
|
|
104
|
-
this.options = { ...OPTIONS$1, ...options };
|
|
105
|
-
if (!this.options.filename.includes("."))
|
|
106
|
-
this.options.filename += ".log";
|
|
107
|
-
if (!this.options.errorFilename.includes("."))
|
|
108
|
-
this.options.errorFilename += ".log";
|
|
109
|
-
let trans = [];
|
|
110
|
-
let exceptionHandlers = [new transports.Console({
|
|
111
|
-
format: getFormatter("console", this.options)
|
|
112
|
-
})];
|
|
113
|
-
if (this.options.file) {
|
|
114
|
-
trans.push(createTransport({
|
|
115
|
-
...this.options,
|
|
116
|
-
format: "file",
|
|
117
|
-
filename: this.options.filename,
|
|
118
|
-
symlinkName: this.options.filename
|
|
119
|
-
}));
|
|
120
|
-
trans.push(createTransport({
|
|
121
|
-
...this.options,
|
|
122
|
-
format: "file",
|
|
123
|
-
filename: this.options.errorFilename,
|
|
124
|
-
symlinkName: this.options.errorFilename,
|
|
125
|
-
level: "error"
|
|
126
|
-
}));
|
|
127
|
-
exceptionHandlers.push(
|
|
128
|
-
new transports.File({ filename: `${this.options.dirname}/${this.options.errorFilename}` })
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
if (this.options.console) {
|
|
132
|
-
trans.push(new transports.Console({
|
|
133
|
-
format: getFormatter("console", this.options)
|
|
134
|
-
}));
|
|
135
|
-
}
|
|
136
|
-
this.logger = createLogger({
|
|
137
|
-
level: this.options.level,
|
|
138
|
-
levels: this.options.levels,
|
|
139
|
-
exitOnError: false,
|
|
140
|
-
// format,
|
|
141
|
-
transports: trans
|
|
142
|
-
// exceptionHandlers
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
const redact$2 = (data, ...sensitiveKeysList) => {
|
|
147
|
-
var _a, _b;
|
|
148
|
-
if (typeof data === "object" && data !== null && !((_b = (_a = data == null ? void 0 : data.constructor) == null ? void 0 : _a.name) == null ? void 0 : _b.startsWith("model"))) {
|
|
149
|
-
if (Array.isArray(data)) {
|
|
150
|
-
return data.map((item) => redact$2(item, ...sensitiveKeysList));
|
|
151
|
-
}
|
|
152
|
-
const redactedData = {};
|
|
153
|
-
for (const key in data) {
|
|
154
|
-
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
|
155
|
-
if (sensitiveKeysList.includes(key)) {
|
|
156
|
-
redactedData[key] = "*****";
|
|
157
|
-
} else {
|
|
158
|
-
redactedData[key] = redact$2(data[key], ...sensitiveKeysList);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return redactedData;
|
|
163
|
-
} else {
|
|
164
|
-
return data;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
const trim$2 = (data, length) => {
|
|
168
|
-
try {
|
|
169
|
-
let str = JSON.stringify(data);
|
|
170
|
-
if (str.length > length) {
|
|
171
|
-
return str.substring(0, length) + "... [TRIMMED]";
|
|
172
|
-
}
|
|
173
|
-
return data;
|
|
174
|
-
} catch (err) {
|
|
175
|
-
return "";
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
const http = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
179
|
-
__proto__: null,
|
|
180
|
-
redact: redact$2,
|
|
181
|
-
trim: trim$2
|
|
182
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
183
|
-
function toFixedNumber(num, digits, base) {
|
|
184
|
-
const pow = Math.pow(base ?? 10, digits);
|
|
185
|
-
return Math.round(num * pow) / pow;
|
|
186
|
-
}
|
|
187
|
-
function bytesToMB$1(b) {
|
|
188
|
-
return toFixedNumber(b / 1024 / 1024, 2, 10);
|
|
189
|
-
}
|
|
190
|
-
function formatBytes$2(bytes, decimals = 2) {
|
|
191
|
-
if (!+bytes)
|
|
192
|
-
return "0 Bytes";
|
|
193
|
-
const k = 1024;
|
|
194
|
-
const dm = decimals < 0 ? 0 : decimals;
|
|
195
|
-
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
|
196
|
-
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
197
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))}${sizes[i]}`;
|
|
198
|
-
}
|
|
199
|
-
const format = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
200
|
-
__proto__: null,
|
|
201
|
-
bytesToMB: bytesToMB$1,
|
|
202
|
-
formatBytes: formatBytes$2,
|
|
203
|
-
toFixedNumber
|
|
204
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
205
|
-
const pick = (obj, ...keys) => Object.fromEntries(
|
|
206
|
-
keys.filter((key) => key in obj).map((key) => [key, obj[key]])
|
|
207
|
-
);
|
|
208
|
-
const omit$2 = (obj, ...keys) => {
|
|
209
|
-
const result = { ...obj };
|
|
210
|
-
keys.forEach(function(prop) {
|
|
211
|
-
delete result[prop];
|
|
212
|
-
});
|
|
213
|
-
return result;
|
|
214
|
-
};
|
|
215
|
-
const object = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
216
|
-
__proto__: null,
|
|
217
|
-
omit: omit$2,
|
|
218
|
-
pick
|
|
219
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
220
|
-
const v8 = require("v8");
|
|
221
|
-
const { bytesToMB } = format;
|
|
222
|
-
function stats() {
|
|
223
|
-
try {
|
|
224
|
-
let h = v8.getHeapStatistics();
|
|
225
|
-
return {
|
|
226
|
-
"total_heap_size": bytesToMB(h.total_heap_size),
|
|
227
|
-
"total_heap_size_executable": bytesToMB(h.total_heap_size_executable),
|
|
228
|
-
"total_physical_size": bytesToMB(h.total_physical_size),
|
|
229
|
-
"total_available_size": bytesToMB(h.total_available_size),
|
|
230
|
-
"used_heap_size": bytesToMB(h.used_heap_size),
|
|
231
|
-
"heap_size_limit": bytesToMB(h.heap_size_limit),
|
|
232
|
-
"malloced_memory": bytesToMB(h.malloced_memory),
|
|
233
|
-
"peak_malloced_memory": bytesToMB(h.peak_malloced_memory),
|
|
234
|
-
"does_zap_garbage": h.does_zap_garbage,
|
|
235
|
-
"number_of_native_contexts": h.number_of_native_contexts,
|
|
236
|
-
"number_of_detached_contexts": h.number_of_detached_contexts
|
|
237
|
-
};
|
|
238
|
-
} catch (err) {
|
|
239
|
-
return {};
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
class BaseLogger {
|
|
243
|
-
constructor(component, options) {
|
|
244
|
-
this.options = options;
|
|
245
|
-
this.logger = new Logger(options).logger.child({ component });
|
|
246
|
-
this.ctx = {};
|
|
247
|
-
this.startTime = Date.now();
|
|
248
|
-
this.absaluteStartTime = Date.now();
|
|
249
|
-
}
|
|
250
|
-
session(id) {
|
|
251
|
-
this.ctx.sessionID = id;
|
|
252
|
-
return this;
|
|
253
|
-
}
|
|
254
|
-
log() {
|
|
255
|
-
this.logger.info(...arguments, this.ctx);
|
|
256
|
-
this._stopMemProfile();
|
|
257
|
-
}
|
|
258
|
-
info() {
|
|
259
|
-
this.logger.info(...arguments, this.ctx);
|
|
260
|
-
this._stopMemProfile();
|
|
261
|
-
}
|
|
262
|
-
error() {
|
|
263
|
-
this.logger.error(...arguments, this.ctx);
|
|
264
|
-
this._stopMemProfile();
|
|
265
|
-
}
|
|
266
|
-
profile(action, options = {}) {
|
|
267
|
-
this.ctx.profiler = this.ctx.profiler || {};
|
|
268
|
-
if (action) {
|
|
269
|
-
let startTime = this.ctx.profiler[action] ? Date.now() - this.ctx.profiler[action] : this.startTime;
|
|
270
|
-
this.ctx.profiler[action] = Date.now() - startTime;
|
|
271
|
-
}
|
|
272
|
-
this.ctx.profiler.totalTime = Date.now() - this.absaluteStartTime;
|
|
273
|
-
if (!options.continue)
|
|
274
|
-
this.startTime = Date.now();
|
|
275
|
-
return this;
|
|
276
|
-
}
|
|
277
|
-
_stopMemProfile() {
|
|
278
|
-
if (this.memProfileInterval)
|
|
279
|
-
clearInterval(this.memProfileInterval);
|
|
280
|
-
}
|
|
281
|
-
profileMem(options = {}) {
|
|
282
|
-
this.ctx.maxMemory = this.ctx.maxMemory || 0;
|
|
283
|
-
this.ctx.memoryStats = this.ctx.memoryStats || [];
|
|
284
|
-
this.ctx.memoryUsage = this.ctx.memoryUsage || [];
|
|
285
|
-
this.ctx.memoryStatsIntervalMS = options.interval || 1e3;
|
|
286
|
-
this._stopMemProfile();
|
|
287
|
-
this.memProfileInterval = setInterval(() => {
|
|
288
|
-
let mem = stats();
|
|
289
|
-
this.ctx.memoryStats.push(mem);
|
|
290
|
-
this.ctx.memoryUsage.push(mem.used_heap_size);
|
|
291
|
-
if (mem.used_heap_size > this.ctx.maxMemory) {
|
|
292
|
-
this.ctx.maxMemory = mem.used_heap_size;
|
|
293
|
-
}
|
|
294
|
-
}, this.ctx.memoryStatsIntervalMS);
|
|
295
|
-
return this;
|
|
296
|
-
}
|
|
297
|
-
context(key, value) {
|
|
298
|
-
if (typeof key === "string") {
|
|
299
|
-
this.ctx[key] = value;
|
|
300
|
-
} else if (typeof key === "object") {
|
|
301
|
-
Object.assign(this.ctx, key);
|
|
302
|
-
}
|
|
303
|
-
return this;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
const { redact: redact$1, trim: trim$1 } = http;
|
|
307
|
-
const { formatBytes: formatBytes$1 } = format;
|
|
308
|
-
const { omit: omit$1 } = object;
|
|
309
|
-
const MAX_BODY_LENGTH$1 = 128;
|
|
310
|
-
class HTTPLogger extends BaseLogger {
|
|
311
|
-
constructor(startTime, options = {}) {
|
|
312
|
-
super("http", options);
|
|
313
|
-
this.startTime = startTime || Date.now();
|
|
314
|
-
}
|
|
315
|
-
request(req) {
|
|
316
|
-
this.session(req.sessionID);
|
|
317
|
-
this.req = req;
|
|
318
|
-
return this;
|
|
319
|
-
}
|
|
320
|
-
response(res) {
|
|
321
|
-
this.res = res;
|
|
322
|
-
return this;
|
|
323
|
-
}
|
|
324
|
-
body(data) {
|
|
325
|
-
this.data = data;
|
|
326
|
-
return this;
|
|
327
|
-
}
|
|
328
|
-
_prepare() {
|
|
329
|
-
var _a, _b;
|
|
330
|
-
let req = this.req;
|
|
331
|
-
let res = this.res;
|
|
332
|
-
let body = this.data;
|
|
333
|
-
this.ctx.request = {
|
|
334
|
-
headers: redact$1(req.headers, "cookie"),
|
|
335
|
-
host: req.headers.host,
|
|
336
|
-
baseUrl: req.baseUrl,
|
|
337
|
-
url: req.originalUrl || req.url,
|
|
338
|
-
method: req.method,
|
|
339
|
-
body: redact$1(req.body, "password"),
|
|
340
|
-
params: req == null ? void 0 : req.params,
|
|
341
|
-
query: redact$1(req == null ? void 0 : req.query, "password"),
|
|
342
|
-
clientIP: ((_a = req == null ? void 0 : req.headers["x-forwarded-for"]) == null ? void 0 : _a.split(",")[0]) ?? (req == null ? void 0 : req.socket.remoteAddress)
|
|
343
|
-
};
|
|
344
|
-
this.ctx.response = {
|
|
345
|
-
headers: omit$1(res.getHeaders(), "set-cookie", "x-powered-by"),
|
|
346
|
-
statusCode: res.statusCode,
|
|
347
|
-
body: trim$1(body, MAX_BODY_LENGTH$1)
|
|
348
|
-
};
|
|
349
|
-
this.ctx.responseTimeMs = Date.now() - this.startTime;
|
|
350
|
-
this.ctx.responseSizeBytes = this.data ? JSON.stringify(this.data).length : 0;
|
|
351
|
-
this.ctx.user = (_b = req == null ? void 0 : req.user) == null ? void 0 : _b.id;
|
|
352
|
-
}
|
|
353
|
-
_message(msg) {
|
|
354
|
-
var _a;
|
|
355
|
-
let remoteAddress = this.req.ip || this.req._remoteAddress || this.req.connection && this.req.connection.remoteAddress || void 0;
|
|
356
|
-
let ip = this.ctx.request.clientIP;
|
|
357
|
-
let method = this.ctx.request.method;
|
|
358
|
-
let url = this.ctx.request.url;
|
|
359
|
-
let statusCode = this.ctx.response.statusCode;
|
|
360
|
-
let responseTimeMs = this.ctx.responseTimeMs + "ms";
|
|
361
|
-
let responseSize = formatBytes$1((_a = JSON.stringify(this.data)) == null ? void 0 : _a.length);
|
|
362
|
-
return `${method} ${url} ${statusCode} ${responseTimeMs} ${responseSize} ${ip} ${remoteAddress} ${msg || ""}`;
|
|
363
|
-
}
|
|
364
|
-
success(req, res, body) {
|
|
365
|
-
if (req)
|
|
366
|
-
this.request(req);
|
|
367
|
-
if (res)
|
|
368
|
-
this.response(res);
|
|
369
|
-
if (body)
|
|
370
|
-
this.body(body);
|
|
371
|
-
this._prepare();
|
|
372
|
-
super.info(this._message());
|
|
373
|
-
}
|
|
374
|
-
error(err) {
|
|
375
|
-
this._prepare();
|
|
376
|
-
super.error(this._message(err));
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
const ops = [
|
|
380
|
-
"find",
|
|
381
|
-
"findOne",
|
|
382
|
-
"findById",
|
|
383
|
-
"findOneAndUpdate",
|
|
384
|
-
"updateOne",
|
|
385
|
-
"updateMany",
|
|
386
|
-
"countDocuments",
|
|
387
|
-
"estimatedDocumentCount",
|
|
388
|
-
"findOneAndRemove",
|
|
389
|
-
"findOneAndDelete",
|
|
390
|
-
"deleteOne",
|
|
391
|
-
"deleteMany",
|
|
392
|
-
"aggregate",
|
|
393
|
-
"save"
|
|
394
|
-
];
|
|
395
|
-
const explained = [
|
|
396
|
-
"find",
|
|
397
|
-
"findOne"
|
|
398
|
-
];
|
|
399
|
-
const OPTIONS = {
|
|
400
|
-
maxResBytes: 100 * 1024,
|
|
401
|
-
logRes: true,
|
|
402
|
-
explain: false
|
|
403
|
-
};
|
|
404
|
-
class MongooseLogger extends BaseLogger {
|
|
405
|
-
constructor(options = {}) {
|
|
406
|
-
super("database", { ...OPTIONS, ...options });
|
|
407
|
-
}
|
|
408
|
-
operation(o) {
|
|
409
|
-
this.ctx.operation = o;
|
|
410
|
-
return this;
|
|
411
|
-
}
|
|
412
|
-
collection(c) {
|
|
413
|
-
this.ctx.collection = c;
|
|
414
|
-
return this;
|
|
415
|
-
}
|
|
416
|
-
query(q) {
|
|
417
|
-
this.ctx.query = q;
|
|
418
|
-
return this;
|
|
419
|
-
}
|
|
420
|
-
update(u) {
|
|
421
|
-
this.ctx.update = u;
|
|
422
|
-
return this;
|
|
423
|
-
}
|
|
424
|
-
pipeline(p) {
|
|
425
|
-
this.ctx.pipeline = p;
|
|
426
|
-
return this;
|
|
427
|
-
}
|
|
428
|
-
async explain(query) {
|
|
429
|
-
if (this.options.explain && !query.options.explain) {
|
|
430
|
-
let { command, executionStats, queryPlanner } = await query.clone().explain();
|
|
431
|
-
this.ctx.explain = { command, executionStats, queryPlanner };
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
result(res) {
|
|
435
|
-
try {
|
|
436
|
-
this.ctx.resultSizeBytes = JSON.stringify(res).length;
|
|
437
|
-
this.ctx.resultLength = Array.isArray(res) ? res.length : res ? 1 : 0;
|
|
438
|
-
} catch (err) {
|
|
439
|
-
}
|
|
440
|
-
if (!this.options.logRes)
|
|
441
|
-
return this;
|
|
442
|
-
if (Array.isArray(res)) {
|
|
443
|
-
this.ctx.documentCount = res.length;
|
|
444
|
-
} else if (this.ctx.resultSizeBytes < this.options.maxResBytes) {
|
|
445
|
-
this.ctx.result = res;
|
|
446
|
-
} else {
|
|
447
|
-
this.ctx.result = `Result too long (more then ${this.options.maxResBytes} bytes)`;
|
|
448
|
-
}
|
|
449
|
-
return this;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
async function postHook(target, res) {
|
|
453
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
454
|
-
if ((_a = target == null ? void 0 : target.options) == null ? void 0 : _a.explain)
|
|
455
|
-
return;
|
|
456
|
-
const op = target.constructor.name === "Aggregate" ? "aggregate" : target.op || target.$op;
|
|
457
|
-
const collection = ((_b = target == null ? void 0 : target._collection) == null ? void 0 : _b.collectionName) || ((_c = target == null ? void 0 : target.collection) == null ? void 0 : _c.name) || ((_e = (_d = target == null ? void 0 : target._model) == null ? void 0 : _d.collection) == null ? void 0 : _e.collectionName);
|
|
458
|
-
if (!op || !collection) {
|
|
459
|
-
try {
|
|
460
|
-
let { logger, ...t } = target;
|
|
461
|
-
target == null ? void 0 : target.logger.profile().result(res).context("target", t).info(`DB query with bad target}`);
|
|
462
|
-
} catch (err) {
|
|
463
|
-
console.error(err);
|
|
464
|
-
}
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
(_f = target == null ? void 0 : target.logger) == null ? void 0 : _f.operation(op).collection(collection).query(target._conditions).update(target._update).pipeline(target._pipeline).profile().result(res);
|
|
468
|
-
if (explained.includes(op)) {
|
|
469
|
-
await (target == null ? void 0 : target.logger.explain(target));
|
|
470
|
-
}
|
|
471
|
-
(_g = target == null ? void 0 : target.logger) == null ? void 0 : _g.info(`DB query: ${op} - ${collection}`);
|
|
472
|
-
}
|
|
473
|
-
function plugin(options = {}) {
|
|
474
|
-
return (schema) => {
|
|
475
|
-
ops.forEach((op) => {
|
|
476
|
-
schema.pre(op, function(next) {
|
|
477
|
-
this.logger = new MongooseLogger(options);
|
|
478
|
-
next();
|
|
479
|
-
});
|
|
480
|
-
schema.post(op, function(res) {
|
|
481
|
-
postHook(this, res);
|
|
482
|
-
});
|
|
483
|
-
});
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
const { redact, trim } = http;
|
|
487
|
-
const { formatBytes } = format;
|
|
488
|
-
const { omit } = object;
|
|
489
|
-
const MAX_BODY_LENGTH = 128;
|
|
490
|
-
class FastifyLogger extends BaseLogger {
|
|
491
|
-
constructor(startTime, options = {}) {
|
|
492
|
-
super(options["component"] || "fastify-api", options);
|
|
493
|
-
this.startTime = startTime || Date.now();
|
|
494
|
-
}
|
|
495
|
-
getRequestSessionId(req) {
|
|
496
|
-
return req.id;
|
|
497
|
-
}
|
|
498
|
-
getResponseHeaders(res) {
|
|
499
|
-
return res.headers;
|
|
500
|
-
}
|
|
501
|
-
getRequestUserId(req) {
|
|
502
|
-
var _a;
|
|
503
|
-
return (_a = req["user"]) == null ? void 0 : _a.id;
|
|
504
|
-
}
|
|
505
|
-
getResponseStatusCode(res) {
|
|
506
|
-
return res.statusCode;
|
|
507
|
-
}
|
|
508
|
-
getRequestQuery(req) {
|
|
509
|
-
return req.query;
|
|
510
|
-
}
|
|
511
|
-
getRequestParams(req) {
|
|
512
|
-
return req.params;
|
|
513
|
-
}
|
|
514
|
-
getRequestBody(req) {
|
|
515
|
-
return req.body;
|
|
516
|
-
}
|
|
517
|
-
getRequestMethod(req) {
|
|
518
|
-
return req.method;
|
|
519
|
-
}
|
|
520
|
-
getRequestUrl(req) {
|
|
521
|
-
return req.url;
|
|
522
|
-
}
|
|
523
|
-
getRequestOriginalUrl(req) {
|
|
524
|
-
return req.originalUrl;
|
|
525
|
-
}
|
|
526
|
-
getRequestBaseUrl(req) {
|
|
527
|
-
const url = new URL(req.url, "http://" + req.headers.host);
|
|
528
|
-
return url.origin;
|
|
529
|
-
}
|
|
530
|
-
getRequestHeaders(req) {
|
|
531
|
-
return req.headers || {};
|
|
532
|
-
}
|
|
533
|
-
request(req) {
|
|
534
|
-
this.session(this.getRequestSessionId(req));
|
|
535
|
-
this.req = req;
|
|
536
|
-
return this;
|
|
537
|
-
}
|
|
538
|
-
response(res) {
|
|
539
|
-
this.res = res;
|
|
540
|
-
return this;
|
|
541
|
-
}
|
|
542
|
-
body(data) {
|
|
543
|
-
this.data = data;
|
|
544
|
-
return this;
|
|
545
|
-
}
|
|
546
|
-
_prepare() {
|
|
547
|
-
const req = this.req;
|
|
548
|
-
const res = this.res;
|
|
549
|
-
const body = this.data;
|
|
550
|
-
this.ctx.request = {
|
|
551
|
-
headers: redact(this.getRequestHeaders(req), "cookie"),
|
|
552
|
-
host: this.getRequestHeaders(req).host,
|
|
553
|
-
baseUrl: this.getRequestBaseUrl(req),
|
|
554
|
-
url: this.getRequestOriginalUrl(req) || this.getRequestUrl(req),
|
|
555
|
-
method: this.getRequestMethod(req),
|
|
556
|
-
body: redact(this.getRequestBody(req), "password"),
|
|
557
|
-
params: this.getRequestParams(req),
|
|
558
|
-
query: redact(this.getRequestQuery(req), "password"),
|
|
559
|
-
clientIP: this.getClientIp(req)
|
|
560
|
-
};
|
|
561
|
-
this.ctx.response = {
|
|
562
|
-
headers: omit(this.getResponseHeaders(res), "set-cookie", "x-powered-by"),
|
|
563
|
-
statusCode: this.getResponseStatusCode(res),
|
|
564
|
-
body: trim(body, MAX_BODY_LENGTH)
|
|
565
|
-
};
|
|
566
|
-
this.ctx.responseTimeMs = Date.now() - this.startTime;
|
|
567
|
-
this.ctx.responseSizeBytes = this.data ? JSON.stringify(this.data).length : 0;
|
|
568
|
-
this.ctx.user = this.getRequestUserId(req);
|
|
569
|
-
}
|
|
570
|
-
_message(msg) {
|
|
571
|
-
var _a;
|
|
572
|
-
const remoteAddress = this.getRemoteAddress();
|
|
573
|
-
const ip = this.ctx.request.clientIP;
|
|
574
|
-
const method = this.ctx.request.method;
|
|
575
|
-
const url = this.ctx.request.url;
|
|
576
|
-
const statusCode = this.ctx.response.statusCode;
|
|
577
|
-
const responseTimeMs = this.ctx.responseTimeMs + "ms";
|
|
578
|
-
const responseSize = formatBytes((_a = JSON.stringify(this.data)) == null ? void 0 : _a.length);
|
|
579
|
-
return `${method} ${url} ${statusCode} ${responseTimeMs} ${responseSize} ${ip} ${remoteAddress} ${msg || ""}`;
|
|
580
|
-
}
|
|
581
|
-
getClientIp(req) {
|
|
582
|
-
var _a, _b;
|
|
583
|
-
return ((_a = this.getRequestHeaders(req)["x-forwarded-for"]) == null ? void 0 : _a.split(",")[0]) ?? ((_b = req == null ? void 0 : req.socket) == null ? void 0 : _b.remoteAddress);
|
|
584
|
-
}
|
|
585
|
-
getRemoteAddress() {
|
|
586
|
-
return this.req.ip || this.req._remoteAddress || void 0;
|
|
587
|
-
}
|
|
588
|
-
success(req, res, body) {
|
|
589
|
-
if (req)
|
|
590
|
-
this.request(req);
|
|
591
|
-
if (res)
|
|
592
|
-
this.response(res);
|
|
593
|
-
if (body)
|
|
594
|
-
this.body(body);
|
|
595
|
-
this._prepare();
|
|
596
|
-
super.info(this._message());
|
|
597
|
-
}
|
|
598
|
-
error(err) {
|
|
599
|
-
this._prepare();
|
|
600
|
-
super.error(this._message(err));
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
export {
|
|
604
|
-
BaseLogger,
|
|
605
|
-
FastifyLogger,
|
|
606
|
-
HTTPLogger as HttpLogger,
|
|
607
|
-
plugin as MongooseLoggerPlugin
|
|
608
|
-
};
|