@viplance/nestjs-logger 0.4.7 → 0.4.8
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/dist/log.module.js +7 -2
- package/dist/log.module.js.map +1 -1
- package/dist/services/log.service.d.ts +1 -1
- package/dist/services/log.service.js +48 -6
- package/dist/services/log.service.js.map +1 -1
- package/dist/services/memory-db.service.d.ts +6 -0
- package/dist/services/memory-db.service.js +85 -1
- package/dist/services/memory-db.service.js.map +1 -1
- package/dist/services/ws.service.d.ts +2 -4
- package/dist/services/ws.service.js +61 -32
- package/dist/services/ws.service.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +3 -1
- package/public/scripts/common.js +139 -30
- package/public/scripts/details-popup.js +2 -2
- package/public/scripts/ws.js +31 -5
- package/public/styles/index.css +177 -2
- package/src/log.module.ts +8 -2
- package/src/services/log.service.ts +62 -5
- package/src/services/memory-db.service.ts +90 -3
- package/src/services/ws.service.ts +33 -36
package/public/scripts/common.js
CHANGED
|
@@ -11,6 +11,10 @@ const logTypes = Object.keys(selectedLogTypes).filter((key) => key !== `all`);
|
|
|
11
11
|
|
|
12
12
|
let logs = [];
|
|
13
13
|
let text = '';
|
|
14
|
+
let currentPage = 1;
|
|
15
|
+
let isLoading = false;
|
|
16
|
+
let hasMore = true;
|
|
17
|
+
const limit = 10;
|
|
14
18
|
|
|
15
19
|
connectWebSocket();
|
|
16
20
|
|
|
@@ -36,7 +40,9 @@ document.addEventListener(`click`, (e) => {
|
|
|
36
40
|
});
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
currentPage = 1;
|
|
44
|
+
hasMore = true;
|
|
45
|
+
getLogs(1);
|
|
40
46
|
|
|
41
47
|
return;
|
|
42
48
|
}
|
|
@@ -53,7 +59,9 @@ document.addEventListener(`click`, (e) => {
|
|
|
53
59
|
selectedLogTypes[`all`] = false;
|
|
54
60
|
unsetSelectorActive(document.querySelector(`li.all`));
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
currentPage = 1;
|
|
63
|
+
hasMore = true;
|
|
64
|
+
getLogs(1);
|
|
57
65
|
|
|
58
66
|
return;
|
|
59
67
|
}
|
|
@@ -141,24 +149,9 @@ function getLogHtmlElement(log) {
|
|
|
141
149
|
function renderLogs(logList = logs) {
|
|
142
150
|
let html = '';
|
|
143
151
|
|
|
144
|
-
logList
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
})
|
|
148
|
-
.filter((log) => {
|
|
149
|
-
if (text === '') return true;
|
|
150
|
-
|
|
151
|
-
return (
|
|
152
|
-
log.message.toLowerCase().includes(text) ||
|
|
153
|
-
log.trace?.toLowerCase().includes(text) ||
|
|
154
|
-
JSON.stringify(log.context || {})
|
|
155
|
-
.toLowerCase()
|
|
156
|
-
.includes(text)
|
|
157
|
-
);
|
|
158
|
-
})
|
|
159
|
-
.forEach((log) => {
|
|
160
|
-
html += getLogHtmlElement(log);
|
|
161
|
-
});
|
|
152
|
+
logList.forEach((log) => {
|
|
153
|
+
html += getLogHtmlElement(log);
|
|
154
|
+
});
|
|
162
155
|
|
|
163
156
|
document.getElementById('logs').innerHTML = html;
|
|
164
157
|
}
|
|
@@ -166,40 +159,79 @@ function renderLogs(logList = logs) {
|
|
|
166
159
|
async function checkElementsVisibility(logList = logs) {
|
|
167
160
|
if (logList.length === 0) {
|
|
168
161
|
document.getElementById('no-logs').style.display = 'block';
|
|
169
|
-
document.getElementById('search').style.display = 'none';
|
|
170
162
|
document.querySelector('.table-header').style.display = 'none';
|
|
171
|
-
document.querySelector('nav').style.display = '
|
|
163
|
+
document.querySelector('nav').style.display = 'flex';
|
|
172
164
|
} else {
|
|
173
165
|
document.getElementById('no-logs').style.display = 'none';
|
|
174
|
-
document.getElementById('search').style.display = 'inline-block';
|
|
175
166
|
document.querySelector('.table-header').style.display = 'flex';
|
|
176
167
|
document.querySelector('nav').style.display = 'flex';
|
|
177
168
|
}
|
|
178
169
|
}
|
|
179
170
|
|
|
180
|
-
async function getLogs() {
|
|
181
|
-
|
|
182
|
-
|
|
171
|
+
async function getLogs(page = 1) {
|
|
172
|
+
if (isLoading && page > 1) return;
|
|
173
|
+
|
|
174
|
+
if (page > 1 && !hasMore) return;
|
|
175
|
+
|
|
176
|
+
isLoading = true;
|
|
177
|
+
currentPage = page;
|
|
178
|
+
document.getElementById('loader').style.display = 'block';
|
|
179
|
+
|
|
180
|
+
const { origin, pathname, search: urlSearch } = window.location;
|
|
181
|
+
const searchParams = new URLSearchParams(urlSearch);
|
|
183
182
|
const key = searchParams.get('key');
|
|
184
183
|
|
|
185
|
-
|
|
184
|
+
const types = selectedLogTypes.all
|
|
185
|
+
? []
|
|
186
|
+
: Object.keys(selectedLogTypes).filter(
|
|
187
|
+
(key) => selectedLogTypes[key] && key !== 'all',
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
if (!!socket && socket.readyState === WebSocket.OPEN) {
|
|
186
191
|
socket.send(
|
|
187
192
|
JSON.stringify({
|
|
188
193
|
action: 'getLogs',
|
|
189
194
|
key,
|
|
195
|
+
page,
|
|
196
|
+
limit,
|
|
197
|
+
search: text,
|
|
198
|
+
types,
|
|
190
199
|
}),
|
|
191
200
|
);
|
|
192
201
|
} else {
|
|
193
|
-
const
|
|
202
|
+
const apiParams = new URLSearchParams(urlSearch);
|
|
203
|
+
apiParams.set('page', page);
|
|
204
|
+
apiParams.set('limit', limit);
|
|
205
|
+
|
|
206
|
+
if (text) {
|
|
207
|
+
apiParams.set('search', text);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (types.length > 0) {
|
|
211
|
+
apiParams.set('types', types.join(','));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const res = await fetch(`${origin}${pathname}api?${apiParams.toString()}`);
|
|
194
215
|
|
|
195
216
|
if (res.ok) {
|
|
196
|
-
|
|
217
|
+
const newLogs = await res.json();
|
|
197
218
|
|
|
198
|
-
|
|
219
|
+
if (page === 1) {
|
|
220
|
+
logs = newLogs;
|
|
221
|
+
} else {
|
|
222
|
+
logs = logs.concat(newLogs);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
hasMore = newLogs.length === limit;
|
|
226
|
+
isLoading = false;
|
|
227
|
+
document.getElementById('loader').style.display = 'none';
|
|
199
228
|
|
|
229
|
+
checkElementsVisibility();
|
|
200
230
|
renderLogs();
|
|
201
231
|
checkAndUpdatePopup();
|
|
202
232
|
} else {
|
|
233
|
+
isLoading = false;
|
|
234
|
+
document.getElementById('loader').style.display = 'none';
|
|
203
235
|
alert('An error occurred while fetching logs.');
|
|
204
236
|
}
|
|
205
237
|
}
|
|
@@ -244,8 +276,85 @@ async function deleteLog(_id) {
|
|
|
244
276
|
}
|
|
245
277
|
}
|
|
246
278
|
|
|
279
|
+
let searchTimeout;
|
|
247
280
|
function search(event) {
|
|
248
281
|
text = event.target.value.toLowerCase();
|
|
249
282
|
|
|
283
|
+
clearTimeout(searchTimeout);
|
|
284
|
+
searchTimeout = setTimeout(() => {
|
|
285
|
+
currentPage = 1;
|
|
286
|
+
hasMore = true;
|
|
287
|
+
getLogs(1);
|
|
288
|
+
}, 300);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Infinite scrolling
|
|
292
|
+
const observer = new IntersectionObserver(
|
|
293
|
+
(entries) => {
|
|
294
|
+
if (entries[0].isIntersecting && !isLoading && hasMore) {
|
|
295
|
+
getLogs(currentPage + 1);
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
{ threshold: 1.0 },
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
302
|
+
const scrollAnchor = document.getElementById('scroll-anchor');
|
|
303
|
+
if (scrollAnchor) {
|
|
304
|
+
observer.observe(scrollAnchor);
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
function matchesFilter(log) {
|
|
309
|
+
// Check types
|
|
310
|
+
if (!selectedLogTypes['all'] && !selectedLogTypes[log.type]) {
|
|
311
|
+
return false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Check search text
|
|
315
|
+
if (text !== '') {
|
|
316
|
+
const matches =
|
|
317
|
+
log.message.toLowerCase().includes(text) ||
|
|
318
|
+
log.trace?.toLowerCase().includes(text) ||
|
|
319
|
+
JSON.stringify(log.context || {})
|
|
320
|
+
.toLowerCase()
|
|
321
|
+
.includes(text);
|
|
322
|
+
|
|
323
|
+
if (!matches) return false;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function handleWsInsert(log) {
|
|
330
|
+
if (matchesFilter(log)) {
|
|
331
|
+
logs.unshift(log);
|
|
332
|
+
checkElementsVisibility();
|
|
333
|
+
renderLogs();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function handleWsUpdate(updatedLog) {
|
|
338
|
+
const idx = logs.findIndex((l) => l._id === updatedLog._id);
|
|
339
|
+
if (idx > -1) {
|
|
340
|
+
logs.splice(idx, 1);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (matchesFilter(updatedLog)) {
|
|
344
|
+
logs.unshift(updatedLog);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
checkElementsVisibility();
|
|
250
348
|
renderLogs();
|
|
349
|
+
checkAndUpdatePopup();
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function handleWsDelete(id) {
|
|
353
|
+
const idx = logs.findIndex((l) => l._id === id);
|
|
354
|
+
if (idx > -1) {
|
|
355
|
+
logs.splice(idx, 1);
|
|
356
|
+
checkElementsVisibility();
|
|
357
|
+
renderLogs();
|
|
358
|
+
checkAndUpdatePopup();
|
|
359
|
+
}
|
|
251
360
|
}
|
|
@@ -21,8 +21,8 @@ function showLogDetails(log) {
|
|
|
21
21
|
)}. First seen: ${getDate(log.createdAt)}`;
|
|
22
22
|
|
|
23
23
|
popup.innerHTML = `
|
|
24
|
-
<div id="drag-handle"
|
|
25
|
-
<div
|
|
24
|
+
<div id="drag-handle" title="Drag to move">
|
|
25
|
+
<div class="handle-indicator"></div>
|
|
26
26
|
</div>
|
|
27
27
|
<div class="content center">
|
|
28
28
|
<div class="container">
|
package/public/scripts/ws.js
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
// WebSocket connection
|
|
2
2
|
let socket;
|
|
3
|
+
let connected = false;
|
|
4
|
+
let connectionAttempts = 0;
|
|
3
5
|
let frozen = false;
|
|
4
6
|
|
|
5
7
|
async function connectWebSocket() {
|
|
8
|
+
connectionAttempts++;
|
|
9
|
+
|
|
10
|
+
if (connectionAttempts > 3) {
|
|
11
|
+
alert('Failed to connect to WebSocket. Check the `key` url parameter.');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
const { hostname, origin, pathname, search } = window.location;
|
|
7
16
|
|
|
8
17
|
const res = await fetch(`${origin}${pathname}settings${search}`);
|
|
@@ -39,11 +48,14 @@ async function connectWebSocket() {
|
|
|
39
48
|
};
|
|
40
49
|
|
|
41
50
|
socket.onopen = (event) => {
|
|
51
|
+
connected = true;
|
|
52
|
+
connectionAttempts = 0;
|
|
42
53
|
getLogs();
|
|
43
54
|
};
|
|
44
55
|
|
|
45
56
|
socket.onclose = (event) => {
|
|
46
|
-
|
|
57
|
+
connected = false;
|
|
58
|
+
console.error(event);
|
|
47
59
|
setTimeout(connectWebSocket, 5000);
|
|
48
60
|
};
|
|
49
61
|
|
|
@@ -53,24 +65,38 @@ async function connectWebSocket() {
|
|
|
53
65
|
if (data['action'] && !frozen) {
|
|
54
66
|
switch (data['action']) {
|
|
55
67
|
case 'list':
|
|
56
|
-
|
|
68
|
+
if (currentPage === 1) {
|
|
69
|
+
logs = data['data'];
|
|
70
|
+
} else {
|
|
71
|
+
logs = logs.concat(data['data']);
|
|
72
|
+
}
|
|
73
|
+
hasMore = data['data'].length === limit;
|
|
74
|
+
isLoading = false;
|
|
75
|
+
document.getElementById('loader').style.display = 'none';
|
|
57
76
|
checkElementsVisibility(logs);
|
|
58
77
|
renderLogs(logs);
|
|
59
78
|
checkAndUpdatePopup();
|
|
60
79
|
break;
|
|
61
80
|
case 'insert':
|
|
62
|
-
|
|
81
|
+
if (currentPage === 1) {
|
|
82
|
+
handleWsInsert(data['data']);
|
|
83
|
+
}
|
|
63
84
|
break;
|
|
64
85
|
case 'update':
|
|
65
|
-
|
|
86
|
+
handleWsUpdate(data['data']);
|
|
66
87
|
break;
|
|
67
88
|
case 'delete':
|
|
68
|
-
|
|
89
|
+
handleWsDelete(data['data']._id);
|
|
69
90
|
break;
|
|
70
91
|
}
|
|
71
92
|
}
|
|
72
93
|
};
|
|
94
|
+
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
if (!connected) connectWebSocket(); // fix for Safari browser
|
|
97
|
+
}, 300);
|
|
73
98
|
}
|
|
99
|
+
|
|
74
100
|
function sendMessage(message) {
|
|
75
101
|
socket.send(JSON.stringify(message));
|
|
76
102
|
}
|
package/public/styles/index.css
CHANGED
|
@@ -54,7 +54,7 @@ h3 {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
#logs {
|
|
57
|
-
margin-top:
|
|
57
|
+
margin-top: 7rem;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
#no-logs {
|
|
@@ -63,6 +63,18 @@ h3 {
|
|
|
63
63
|
text-align: center;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
+
#loader {
|
|
67
|
+
display: none;
|
|
68
|
+
text-align: center;
|
|
69
|
+
padding: 1rem;
|
|
70
|
+
color: var(--teal);
|
|
71
|
+
font-weight: bold;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#scroll-anchor {
|
|
75
|
+
height: 20px;
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
/* buttons */
|
|
67
79
|
button {
|
|
68
80
|
display: flex;
|
|
@@ -316,7 +328,27 @@ nav ul li:hover {
|
|
|
316
328
|
overflow-y: scroll;
|
|
317
329
|
z-index: 1;
|
|
318
330
|
opacity: 0.97;
|
|
319
|
-
box-shadow:
|
|
331
|
+
box-shadow:
|
|
332
|
+
0 4px 8px 0 rgba(0, 0, 0, 0.2),
|
|
333
|
+
0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
#drag-handle {
|
|
337
|
+
margin: -2rem -2rem 1rem -2rem;
|
|
338
|
+
height: 1.5rem;
|
|
339
|
+
background-color: #f1f1f1;
|
|
340
|
+
border-bottom: 1px solid #ddd;
|
|
341
|
+
cursor: grab;
|
|
342
|
+
display: flex;
|
|
343
|
+
align-items: center;
|
|
344
|
+
justify-content: center;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
#drag-handle .handle-indicator {
|
|
348
|
+
width: 50px;
|
|
349
|
+
height: 5px;
|
|
350
|
+
background-color: #ccc;
|
|
351
|
+
border-radius: 5px;
|
|
320
352
|
}
|
|
321
353
|
|
|
322
354
|
/* JSON viewer */
|
|
@@ -347,3 +379,146 @@ nav ul li:hover {
|
|
|
347
379
|
box-shadow: none;
|
|
348
380
|
}
|
|
349
381
|
}
|
|
382
|
+
|
|
383
|
+
@media (max-width: 768px) {
|
|
384
|
+
/* Allow header to flow naturally */
|
|
385
|
+
header {
|
|
386
|
+
position: relative !important;
|
|
387
|
+
padding-bottom: 1rem;
|
|
388
|
+
height: auto;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/* Reset logo from previous media query */
|
|
392
|
+
.logo {
|
|
393
|
+
width: 100%;
|
|
394
|
+
margin: 0 !important;
|
|
395
|
+
justify-content: center;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/* Show title again for branding */
|
|
399
|
+
.logo h2 {
|
|
400
|
+
display: block !important;
|
|
401
|
+
margin-left: 0.5rem;
|
|
402
|
+
font-size: 1.2rem;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/* Wrap controls */
|
|
406
|
+
.controls {
|
|
407
|
+
flex-wrap: wrap;
|
|
408
|
+
padding: 0 1rem;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/* Nav */
|
|
412
|
+
nav {
|
|
413
|
+
width: 100%;
|
|
414
|
+
order: 2;
|
|
415
|
+
overflow-x: auto;
|
|
416
|
+
margin-bottom: 1rem;
|
|
417
|
+
-webkit-overflow-scrolling: touch;
|
|
418
|
+
margin-top: 1rem;
|
|
419
|
+
height: 2rem;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
nav ul {
|
|
423
|
+
width: max-content;
|
|
424
|
+
padding: 0 0.5rem;
|
|
425
|
+
gap: 1.5rem;
|
|
426
|
+
justify-content: flex-start;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* Search */
|
|
430
|
+
#search {
|
|
431
|
+
order: 3;
|
|
432
|
+
width: 100%;
|
|
433
|
+
margin-bottom: 1rem;
|
|
434
|
+
box-sizing: border-box;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/* Buttons */
|
|
438
|
+
#refresh,
|
|
439
|
+
#freeze {
|
|
440
|
+
order: 4;
|
|
441
|
+
width: 48%;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
#refresh button,
|
|
445
|
+
#freeze button {
|
|
446
|
+
width: 100%;
|
|
447
|
+
justify-content: center;
|
|
448
|
+
padding: 10px;
|
|
449
|
+
margin-bottom: 1rem;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/* Logs Container */
|
|
453
|
+
#logs {
|
|
454
|
+
margin-top: 0;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/* Hide Table Header */
|
|
458
|
+
.table-header {
|
|
459
|
+
display: none;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/* Row Layout */
|
|
463
|
+
.row {
|
|
464
|
+
flex-wrap: wrap;
|
|
465
|
+
height: auto;
|
|
466
|
+
padding: 0.8rem 0;
|
|
467
|
+
border-bottom: 1px solid var(--light);
|
|
468
|
+
align-items: flex-start;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.row:hover {
|
|
472
|
+
border-left: 2px solid transparent;
|
|
473
|
+
background-color: transparent;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.row:active {
|
|
477
|
+
background-color: #f5f5f5;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/* Type */
|
|
481
|
+
.row > :first-child {
|
|
482
|
+
flex: 0 0 3.5rem;
|
|
483
|
+
font-size: 0.75rem;
|
|
484
|
+
text-transform: uppercase;
|
|
485
|
+
font-weight: bold;
|
|
486
|
+
padding-left: 0.5rem;
|
|
487
|
+
text-align: left;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/* Info */
|
|
491
|
+
.row > :nth-child(2) {
|
|
492
|
+
flex: 1 1 auto;
|
|
493
|
+
max-width: calc(100% - 6.5rem);
|
|
494
|
+
padding: 0 0.5rem;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
.log-info {
|
|
498
|
+
white-space: normal;
|
|
499
|
+
display: -webkit-box;
|
|
500
|
+
line-clamp: 2;
|
|
501
|
+
-webkit-line-clamp: 2;
|
|
502
|
+
-webkit-box-orient: vertical;
|
|
503
|
+
max-height: 2.8rem;
|
|
504
|
+
margin-bottom: 0.2rem;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/* Hide Context */
|
|
508
|
+
.row > :nth-child(3) {
|
|
509
|
+
display: none;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/* Count */
|
|
513
|
+
.row > :last-child {
|
|
514
|
+
flex: 0 0 2rem;
|
|
515
|
+
font-size: 0.8rem;
|
|
516
|
+
color: #aaa;
|
|
517
|
+
text-align: right;
|
|
518
|
+
padding-right: 0.5rem;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
#drag-handle {
|
|
522
|
+
display: none;
|
|
523
|
+
}
|
|
524
|
+
}
|
package/src/log.module.ts
CHANGED
|
@@ -64,11 +64,17 @@ export class LogModule {
|
|
|
64
64
|
}
|
|
65
65
|
);
|
|
66
66
|
|
|
67
|
-
// get
|
|
67
|
+
// get logs endpoint
|
|
68
68
|
httpAdapter.get(join(options.path, 'api'), async (req: any, res: any) => {
|
|
69
69
|
logAccessGuard.canActivate(req);
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
const params = querystring.parse(req.url.split('?')[1]);
|
|
72
|
+
const page = params.page ? parseInt(params.page.toString()) : 1;
|
|
73
|
+
const limit = params.limit ? parseInt(params.limit.toString()) : 50;
|
|
74
|
+
const search = params.search ? params.search.toString() : '';
|
|
75
|
+
const types = params.types ? params.types.toString().split(',') : [];
|
|
76
|
+
|
|
77
|
+
res.json(await logService.getAll(page, limit, search, types));
|
|
72
78
|
});
|
|
73
79
|
|
|
74
80
|
// delete log endpoint
|
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
DataSourceOptions,
|
|
12
12
|
EntityManager,
|
|
13
13
|
EntitySchema,
|
|
14
|
+
Like,
|
|
15
|
+
In,
|
|
14
16
|
} from 'typeorm';
|
|
15
17
|
import { createLogEntity } from '../entities/log.entity';
|
|
16
18
|
import { ExecutionContextHost } from '@nestjs/core/helpers/execution-context-host';
|
|
@@ -94,7 +96,12 @@ export class LogService implements LoggerService, OnApplicationShutdown {
|
|
|
94
96
|
case 'getLogs':
|
|
95
97
|
this.wsService.sendMessage({
|
|
96
98
|
action: 'list',
|
|
97
|
-
data: await this.getAll(
|
|
99
|
+
data: await this.getAll(
|
|
100
|
+
message.page,
|
|
101
|
+
message.limit,
|
|
102
|
+
message.search,
|
|
103
|
+
message.types
|
|
104
|
+
),
|
|
98
105
|
});
|
|
99
106
|
break;
|
|
100
107
|
case 'delete':
|
|
@@ -159,8 +166,16 @@ export class LogService implements LoggerService, OnApplicationShutdown {
|
|
|
159
166
|
});
|
|
160
167
|
}
|
|
161
168
|
|
|
162
|
-
async getAll(
|
|
163
|
-
|
|
169
|
+
async getAll(
|
|
170
|
+
page: number = 1,
|
|
171
|
+
limit: number = 50,
|
|
172
|
+
search: string = '',
|
|
173
|
+
types: string[] = []
|
|
174
|
+
): Promise<any[]> {
|
|
175
|
+
const skip = (page - 1) * limit;
|
|
176
|
+
const take = limit;
|
|
177
|
+
|
|
178
|
+
const findOptions: any = {
|
|
164
179
|
select: [
|
|
165
180
|
'_id',
|
|
166
181
|
'type',
|
|
@@ -173,7 +188,49 @@ export class LogService implements LoggerService, OnApplicationShutdown {
|
|
|
173
188
|
'breadcrumbs',
|
|
174
189
|
],
|
|
175
190
|
order: { updatedAt: 'DESC' },
|
|
176
|
-
|
|
191
|
+
take,
|
|
192
|
+
skip,
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
if (search) {
|
|
196
|
+
if (LogService.options?.database?.type === 'mongodb') {
|
|
197
|
+
const where: any = {
|
|
198
|
+
$or: [
|
|
199
|
+
{ message: { $regex: search, $options: 'i' } },
|
|
200
|
+
{ trace: { $regex: search, $options: 'i' } },
|
|
201
|
+
],
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
if (types.length > 0) {
|
|
205
|
+
where.type = { $in: types };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
findOptions.where = where;
|
|
209
|
+
} else {
|
|
210
|
+
findOptions.where = [
|
|
211
|
+
{ message: Like(`%${search}%`) },
|
|
212
|
+
{ trace: Like(`%${search}%`) },
|
|
213
|
+
];
|
|
214
|
+
|
|
215
|
+
if (types.length > 0) {
|
|
216
|
+
findOptions.where.forEach((option: any) => {
|
|
217
|
+
option.type = In(types);
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
} else if (types.length > 0) {
|
|
222
|
+
if (LogService.options?.database?.type === 'mongodb') {
|
|
223
|
+
findOptions.where = {
|
|
224
|
+
type: { $in: types },
|
|
225
|
+
};
|
|
226
|
+
} else {
|
|
227
|
+
findOptions.where = {
|
|
228
|
+
type: In(types),
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return this.getConnection().find(LogService.Log, findOptions);
|
|
177
234
|
}
|
|
178
235
|
|
|
179
236
|
async delete(_id: string) {
|
|
@@ -197,7 +254,7 @@ export class LogService implements LoggerService, OnApplicationShutdown {
|
|
|
197
254
|
// find the same log in DB
|
|
198
255
|
let log;
|
|
199
256
|
|
|
200
|
-
if (LogService.options
|
|
257
|
+
if (LogService.options && (LogService.options.join || LogService.options.join === undefined)) {
|
|
201
258
|
log = await connection.findOne(LogService.Log, {
|
|
202
259
|
where: {
|
|
203
260
|
type: data.type,
|