@ngn-net/nestjs-telescope 0.3.2 → 0.3.4
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/enums/entry-type.enum.d.ts +2 -1
- package/dist/enums/entry-type.enum.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/telescope.module.js +13 -0
- package/dist/ui/index.html +76 -1
- package/dist/ui/manifest.json +2 -2
- package/dist/watchers/rabbitmq.watcher.d.ts +11 -0
- package/dist/watchers/rabbitmq.watcher.js +231 -0
- package/package.json +5 -1
- package/ui/index.html +76 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -29,3 +29,4 @@ __exportStar(require("./watchers/model.watcher"), exports);
|
|
|
29
29
|
__exportStar(require("./watchers/notification.watcher"), exports);
|
|
30
30
|
__exportStar(require("./watchers/gate.watcher"), exports);
|
|
31
31
|
__exportStar(require("./watchers/http-client.watcher"), exports);
|
|
32
|
+
__exportStar(require("./watchers/rabbitmq.watcher"), exports);
|
package/dist/telescope.module.js
CHANGED
|
@@ -42,6 +42,7 @@ const command_watcher_1 = require("./watchers/command.watcher");
|
|
|
42
42
|
const model_watcher_1 = require("./watchers/model.watcher");
|
|
43
43
|
const notification_watcher_1 = require("./watchers/notification.watcher");
|
|
44
44
|
const gate_watcher_1 = require("./watchers/gate.watcher");
|
|
45
|
+
const rabbitmq_watcher_1 = require("./watchers/rabbitmq.watcher");
|
|
45
46
|
const constants_1 = require("./constants");
|
|
46
47
|
const entry_type_enum_1 = require("./enums/entry-type.enum");
|
|
47
48
|
let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
@@ -295,6 +296,13 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
295
296
|
}
|
|
296
297
|
}
|
|
297
298
|
catch (e) { }
|
|
299
|
+
try {
|
|
300
|
+
require('@golevelup/nestjs-rabbitmq');
|
|
301
|
+
if (!options.enabledEntryTypes || options.enabledEntryTypes.includes(entry_type_enum_1.EntryType.RABBITMQ)) {
|
|
302
|
+
providers.push(rabbitmq_watcher_1.RabbitMQWatcher);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
catch (e) { }
|
|
298
306
|
}
|
|
299
307
|
static registerWatchersAndModulesAsync(providers, imports) {
|
|
300
308
|
providers.push({ provide: core_1.APP_INTERCEPTOR, useClass: http_request_watcher_1.HttpRequestWatcher });
|
|
@@ -344,6 +352,11 @@ let TelescopeModule = TelescopeModule_1 = class TelescopeModule {
|
|
|
344
352
|
providers.push(mail_watcher_1.MailWatcher);
|
|
345
353
|
}
|
|
346
354
|
catch (e) { }
|
|
355
|
+
try {
|
|
356
|
+
require('@golevelup/nestjs-rabbitmq');
|
|
357
|
+
providers.push(rabbitmq_watcher_1.RabbitMQWatcher);
|
|
358
|
+
}
|
|
359
|
+
catch (e) { }
|
|
347
360
|
}
|
|
348
361
|
};
|
|
349
362
|
exports.TelescopeModule = TelescopeModule;
|
package/dist/ui/index.html
CHANGED
|
@@ -502,6 +502,7 @@
|
|
|
502
502
|
.badge-model { background-color: rgba(16, 185, 129, 0.12); color: var(--accent-green); }
|
|
503
503
|
.badge-notification { background-color: rgba(245, 158, 11, 0.12); color: var(--accent-amber); }
|
|
504
504
|
.badge-dump { background-color: rgba(139, 92, 246, 0.12); color: var(--accent-purple); }
|
|
505
|
+
.badge-rabbitmq { background-color: rgba(245, 158, 11, 0.12); color: var(--accent-amber); }
|
|
505
506
|
|
|
506
507
|
.badge-get { background-color: rgba(16, 185, 129, 0.15); color: var(--accent-green); }
|
|
507
508
|
.badge-post { background-color: rgba(59, 130, 246, 0.15); color: var(--accent-blue); }
|
|
@@ -869,6 +870,7 @@
|
|
|
869
870
|
{ id: 'command', label: 'Commands', icon: '💻' },
|
|
870
871
|
{ id: 'model', label: 'Models', icon: '📦' },
|
|
871
872
|
{ id: 'notification', label: 'Notifications', icon: '🔔' },
|
|
873
|
+
{ id: 'rabbitmq', label: 'RabbitMQ', icon: '🐰' },
|
|
872
874
|
{ id: 'dump', label: 'Dumps', icon: '🗑️' },
|
|
873
875
|
];
|
|
874
876
|
|
|
@@ -1419,6 +1421,7 @@
|
|
|
1419
1421
|
item.type === 'http_client' ? (`${item.content.method || 'GET'} ${item.content.url}`) :
|
|
1420
1422
|
item.type === 'cache' ? (`Cache ${item.content.action?.toUpperCase()}: ${item.content.key}`) :
|
|
1421
1423
|
item.type === 'redis' ? (`Redis: ${item.content.command}`) :
|
|
1424
|
+
item.type === 'rabbitmq' ? (`${item.content.direction === 'outgoing' ? '→' : '←'} ${item.content.exchange} → ${item.content.routingKey}`) :
|
|
1422
1425
|
JSON.stringify(item.content)}
|
|
1423
1426
|
</span>
|
|
1424
1427
|
{item.type === 'query' && item.content.duration !== undefined && (
|
|
@@ -1452,7 +1455,7 @@
|
|
|
1452
1455
|
|
|
1453
1456
|
// Determine font family for subtitle
|
|
1454
1457
|
function varMono(type) {
|
|
1455
|
-
return (type === 'query' || type === 'redis' || type === 'request' || type === 'http_client' || type === 'command') ? 'var(--font-mono)' : 'var(--font-sans)';
|
|
1458
|
+
return (type === 'query' || type === 'redis' || type === 'request' || type === 'http_client' || type === 'command' || type === 'rabbitmq') ? 'var(--font-mono)' : 'var(--font-sans)';
|
|
1456
1459
|
}
|
|
1457
1460
|
|
|
1458
1461
|
// Helper functions for displaying table items
|
|
@@ -1591,6 +1594,19 @@
|
|
|
1591
1594
|
subtitle: typeof content.message === 'string' ? content.message : JSON.stringify(content.message),
|
|
1592
1595
|
status: <span className="badge badge-status-ok">dumped</span>
|
|
1593
1596
|
};
|
|
1597
|
+
case 'rabbitmq':
|
|
1598
|
+
const dir = content.direction || 'unknown';
|
|
1599
|
+
const dirIcon = dir === 'outgoing' ? '→' : '←';
|
|
1600
|
+
const dirColor = dir === 'outgoing' ? 'var(--accent-blue)' : 'var(--accent-green)';
|
|
1601
|
+
return {
|
|
1602
|
+
title: `${dirIcon} ${content.exchange || ''}`,
|
|
1603
|
+
subtitle: `${content.routingKey || ''} (${content.handler || content.queue || ''})`,
|
|
1604
|
+
status: content.status === 'failed' ? (
|
|
1605
|
+
<span className="badge badge-status-err">failed</span>
|
|
1606
|
+
) : (
|
|
1607
|
+
<span className="badge badge-rabbitmq" style={{ color: dirColor }}>{dir}</span>
|
|
1608
|
+
)
|
|
1609
|
+
};
|
|
1594
1610
|
default:
|
|
1595
1611
|
return {
|
|
1596
1612
|
title: 'Telescope Entry',
|
|
@@ -1974,6 +1990,65 @@
|
|
|
1974
1990
|
</div>
|
|
1975
1991
|
</React.Fragment>
|
|
1976
1992
|
);
|
|
1993
|
+
case 'rabbitmq':
|
|
1994
|
+
return (
|
|
1995
|
+
<React.Fragment>
|
|
1996
|
+
<div className="key-val-row">
|
|
1997
|
+
<div className="key-val-label">Direction</div>
|
|
1998
|
+
<div className="key-val-value" style={{ fontWeight: '600', color: '#fff', textTransform: 'uppercase' }}>{content.direction}</div>
|
|
1999
|
+
</div>
|
|
2000
|
+
<div className="key-val-row">
|
|
2001
|
+
<div className="key-val-label">Exchange</div>
|
|
2002
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)', color: '#818cf8' }}>{content.exchange}</div>
|
|
2003
|
+
</div>
|
|
2004
|
+
<div className="key-val-row">
|
|
2005
|
+
<div className="key-val-label">Routing Key</div>
|
|
2006
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)' }}>{content.routingKey}</div>
|
|
2007
|
+
</div>
|
|
2008
|
+
{content.queue && (
|
|
2009
|
+
<div className="key-val-row">
|
|
2010
|
+
<div className="key-val-label">Queue</div>
|
|
2011
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)' }}>{content.queue}</div>
|
|
2012
|
+
</div>
|
|
2013
|
+
)}
|
|
2014
|
+
{content.handler && (
|
|
2015
|
+
<div className="key-val-row">
|
|
2016
|
+
<div className="key-val-label">Handler</div>
|
|
2017
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)' }}>{content.handler}</div>
|
|
2018
|
+
</div>
|
|
2019
|
+
)}
|
|
2020
|
+
{content.duration !== undefined && (
|
|
2021
|
+
<div className="key-val-row">
|
|
2022
|
+
<div className="key-val-label">Duration</div>
|
|
2023
|
+
<div className="key-val-value">{content.duration} ms</div>
|
|
2024
|
+
</div>
|
|
2025
|
+
)}
|
|
2026
|
+
{content.status && (
|
|
2027
|
+
<div className="key-val-row">
|
|
2028
|
+
<div className="key-val-label">Status</div>
|
|
2029
|
+
<div className="key-val-value">
|
|
2030
|
+
{content.status === 'failed' ? (
|
|
2031
|
+
<span className="badge badge-status-err">failed</span>
|
|
2032
|
+
) : (
|
|
2033
|
+
<span className="badge badge-status-ok">{content.status}</span>
|
|
2034
|
+
)}
|
|
2035
|
+
</div>
|
|
2036
|
+
</div>
|
|
2037
|
+
)}
|
|
2038
|
+
{content.error && (
|
|
2039
|
+
<div className="key-val-row">
|
|
2040
|
+
<div className="key-val-label">Error</div>
|
|
2041
|
+
<div className="key-val-value" style={{ color: 'var(--accent-red)' }}>{content.error}</div>
|
|
2042
|
+
</div>
|
|
2043
|
+
)}
|
|
2044
|
+
{content.message && (
|
|
2045
|
+
<div className="key-val-row" style={{ flexDirection: 'column', display: 'flex', gap: '8px' }}>
|
|
2046
|
+
<div className="key-val-label">Message Payload</div>
|
|
2047
|
+
<pre className="json-code">{JSON.stringify(content.message, null, 2)}</pre>
|
|
2048
|
+
</div>
|
|
2049
|
+
)}
|
|
2050
|
+
</React.Fragment>
|
|
2051
|
+
);
|
|
1977
2052
|
default:
|
|
1978
2053
|
return (
|
|
1979
2054
|
<div className="key-val-row">
|
package/dist/ui/manifest.json
CHANGED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { OnModuleInit } from '@nestjs/common';
|
|
2
|
+
import { TelescopeService } from '../telescope.service';
|
|
3
|
+
export declare class RabbitMQWatcher implements OnModuleInit {
|
|
4
|
+
private readonly telescope;
|
|
5
|
+
private readonly logger;
|
|
6
|
+
constructor(telescope: TelescopeService);
|
|
7
|
+
onModuleInit(): void;
|
|
8
|
+
private patchAmqpConnection;
|
|
9
|
+
private patchRabbitSubscribe;
|
|
10
|
+
private sanitizeMessage;
|
|
11
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
var RabbitMQWatcher_1;
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.RabbitMQWatcher = void 0;
|
|
14
|
+
const common_1 = require("@nestjs/common");
|
|
15
|
+
const telescope_service_1 = require("../telescope.service");
|
|
16
|
+
const entry_type_enum_1 = require("../enums/entry-type.enum");
|
|
17
|
+
let RabbitMQWatcher = RabbitMQWatcher_1 = class RabbitMQWatcher {
|
|
18
|
+
telescope;
|
|
19
|
+
logger = new common_1.Logger(RabbitMQWatcher_1.name);
|
|
20
|
+
constructor(telescope) {
|
|
21
|
+
this.telescope = telescope;
|
|
22
|
+
}
|
|
23
|
+
onModuleInit() {
|
|
24
|
+
this.patchAmqpConnection();
|
|
25
|
+
this.patchRabbitSubscribe();
|
|
26
|
+
}
|
|
27
|
+
patchAmqpConnection() {
|
|
28
|
+
try {
|
|
29
|
+
const { AmqpConnection } = require('@golevelup/nestjs-rabbitmq');
|
|
30
|
+
if (!AmqpConnection || !AmqpConnection.prototype)
|
|
31
|
+
return;
|
|
32
|
+
const originalPublish = AmqpConnection.prototype.publish;
|
|
33
|
+
if (!originalPublish)
|
|
34
|
+
return;
|
|
35
|
+
const self = this;
|
|
36
|
+
AmqpConnection.prototype.publish = async function (exchange, routingKey, msg, ...args) {
|
|
37
|
+
const startTime = Date.now();
|
|
38
|
+
const result = await originalPublish.call(this, exchange, routingKey, msg, ...args);
|
|
39
|
+
const duration = Date.now() - startTime;
|
|
40
|
+
const sanitizedMsg = self.sanitizeMessage(msg);
|
|
41
|
+
self.telescope.record({
|
|
42
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
43
|
+
content: {
|
|
44
|
+
direction: 'outgoing',
|
|
45
|
+
exchange,
|
|
46
|
+
routingKey,
|
|
47
|
+
message: sanitizedMsg,
|
|
48
|
+
duration,
|
|
49
|
+
status: 'sent',
|
|
50
|
+
},
|
|
51
|
+
}).catch(() => { });
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch { }
|
|
56
|
+
}
|
|
57
|
+
patchRabbitSubscribe() {
|
|
58
|
+
try {
|
|
59
|
+
const rabbitmq = require('@golevelup/nestjs-rabbitmq');
|
|
60
|
+
if (!rabbitmq)
|
|
61
|
+
return;
|
|
62
|
+
const self = this;
|
|
63
|
+
const RabbitSubscribeHandler = rabbitmq.RabbitSubscribe;
|
|
64
|
+
if (RabbitSubscribeHandler) {
|
|
65
|
+
const originalHandler = RabbitSubscribeHandler;
|
|
66
|
+
rabbitmq.RabbitSubscribe = function (options) {
|
|
67
|
+
const decorator = originalHandler(options);
|
|
68
|
+
return function (target, propertyKey, descriptor) {
|
|
69
|
+
const originalMethod = descriptor.value;
|
|
70
|
+
const exchange = options?.exchange || '';
|
|
71
|
+
const routingKey = options?.routingKey || '';
|
|
72
|
+
const queue = options?.queue || '';
|
|
73
|
+
descriptor.value = async function (...args) {
|
|
74
|
+
const startTime = Date.now();
|
|
75
|
+
const incomingMsg = args[0];
|
|
76
|
+
self.telescope.record({
|
|
77
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
78
|
+
content: {
|
|
79
|
+
direction: 'incoming',
|
|
80
|
+
exchange,
|
|
81
|
+
routingKey,
|
|
82
|
+
queue,
|
|
83
|
+
message: self.sanitizeMessage(incomingMsg),
|
|
84
|
+
handler: `${target.constructor?.name || 'Unknown'}.${propertyKey}`,
|
|
85
|
+
timestamp: new Date().toISOString(),
|
|
86
|
+
},
|
|
87
|
+
}).catch(() => { });
|
|
88
|
+
try {
|
|
89
|
+
const result = await originalMethod.apply(this, args);
|
|
90
|
+
const duration = Date.now() - startTime;
|
|
91
|
+
self.telescope.record({
|
|
92
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
93
|
+
content: {
|
|
94
|
+
direction: 'incoming_response',
|
|
95
|
+
exchange,
|
|
96
|
+
routingKey,
|
|
97
|
+
queue,
|
|
98
|
+
handler: `${target.constructor?.name || 'Unknown'}.${propertyKey}`,
|
|
99
|
+
duration,
|
|
100
|
+
status: 'completed',
|
|
101
|
+
},
|
|
102
|
+
}).catch(() => { });
|
|
103
|
+
return result;
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
const duration = Date.now() - startTime;
|
|
107
|
+
self.telescope.record({
|
|
108
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
109
|
+
content: {
|
|
110
|
+
direction: 'incoming_response',
|
|
111
|
+
exchange,
|
|
112
|
+
routingKey,
|
|
113
|
+
queue,
|
|
114
|
+
handler: `${target.constructor?.name || 'Unknown'}.${propertyKey}`,
|
|
115
|
+
duration,
|
|
116
|
+
status: 'failed',
|
|
117
|
+
error: err.message || String(err),
|
|
118
|
+
},
|
|
119
|
+
}).catch(() => { });
|
|
120
|
+
throw err;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
return descriptor;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const RabbitRPCHandler = rabbitmq.RabbitRPC;
|
|
128
|
+
if (RabbitRPCHandler) {
|
|
129
|
+
const originalRPCHandler = RabbitRPCHandler;
|
|
130
|
+
rabbitmq.RabbitRPC = function (options) {
|
|
131
|
+
const decorator = originalRPCHandler(options);
|
|
132
|
+
return function (target, propertyKey, descriptor) {
|
|
133
|
+
const originalMethod = descriptor.value;
|
|
134
|
+
const exchange = options?.exchange || '';
|
|
135
|
+
const routingKey = options?.routingKey || '';
|
|
136
|
+
const queue = options?.queue || '';
|
|
137
|
+
descriptor.value = async function (...args) {
|
|
138
|
+
const startTime = Date.now();
|
|
139
|
+
const incomingMsg = args[0];
|
|
140
|
+
self.telescope.record({
|
|
141
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
142
|
+
content: {
|
|
143
|
+
direction: 'incoming_rpc',
|
|
144
|
+
exchange,
|
|
145
|
+
routingKey,
|
|
146
|
+
queue,
|
|
147
|
+
message: self.sanitizeMessage(incomingMsg),
|
|
148
|
+
handler: `${target.constructor?.name || 'Unknown'}.${propertyKey}`,
|
|
149
|
+
timestamp: new Date().toISOString(),
|
|
150
|
+
},
|
|
151
|
+
}).catch(() => { });
|
|
152
|
+
try {
|
|
153
|
+
const result = await originalMethod.apply(this, args);
|
|
154
|
+
const duration = Date.now() - startTime;
|
|
155
|
+
self.telescope.record({
|
|
156
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
157
|
+
content: {
|
|
158
|
+
direction: 'incoming_rpc_response',
|
|
159
|
+
exchange,
|
|
160
|
+
routingKey,
|
|
161
|
+
queue,
|
|
162
|
+
handler: `${target.constructor?.name || 'Unknown'}.${propertyKey}`,
|
|
163
|
+
duration,
|
|
164
|
+
status: 'completed',
|
|
165
|
+
},
|
|
166
|
+
}).catch(() => { });
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const duration = Date.now() - startTime;
|
|
171
|
+
self.telescope.record({
|
|
172
|
+
type: entry_type_enum_1.EntryType.RABBITMQ,
|
|
173
|
+
content: {
|
|
174
|
+
direction: 'incoming_rpc_response',
|
|
175
|
+
exchange,
|
|
176
|
+
routingKey,
|
|
177
|
+
queue,
|
|
178
|
+
handler: `${target.constructor?.name || 'Unknown'}.${propertyKey}`,
|
|
179
|
+
duration,
|
|
180
|
+
status: 'failed',
|
|
181
|
+
error: err.message || String(err),
|
|
182
|
+
},
|
|
183
|
+
}).catch(() => { });
|
|
184
|
+
throw err;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
return descriptor;
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
catch { }
|
|
193
|
+
}
|
|
194
|
+
sanitizeMessage(msg) {
|
|
195
|
+
if (!msg)
|
|
196
|
+
return null;
|
|
197
|
+
if (typeof msg === 'string') {
|
|
198
|
+
try {
|
|
199
|
+
const parsed = JSON.parse(msg);
|
|
200
|
+
return this.sanitizeMessage(parsed);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return msg.length > 1000 ? msg.substring(0, 1000) + '...[truncated]' : msg;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (Buffer.isBuffer(msg)) {
|
|
207
|
+
return '[Buffer]';
|
|
208
|
+
}
|
|
209
|
+
if (typeof msg === 'object') {
|
|
210
|
+
const sanitized = {};
|
|
211
|
+
for (const [key, value] of Object.entries(msg)) {
|
|
212
|
+
if (key.toLowerCase().includes('password') || key.toLowerCase().includes('secret') || key.toLowerCase().includes('token')) {
|
|
213
|
+
sanitized[key] = '[REDACTED]';
|
|
214
|
+
}
|
|
215
|
+
else if (typeof value === 'string' && value.length > 500) {
|
|
216
|
+
sanitized[key] = value.substring(0, 500) + '...[truncated]';
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
sanitized[key] = value;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return sanitized;
|
|
223
|
+
}
|
|
224
|
+
return msg;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
exports.RabbitMQWatcher = RabbitMQWatcher;
|
|
228
|
+
exports.RabbitMQWatcher = RabbitMQWatcher = RabbitMQWatcher_1 = __decorate([
|
|
229
|
+
(0, common_1.Injectable)(),
|
|
230
|
+
__metadata("design:paramtypes", [telescope_service_1.TelescopeService])
|
|
231
|
+
], RabbitMQWatcher);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ngn-net/nestjs-telescope",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"reflect-metadata": "^0.2"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
+
"@golevelup/nestjs-rabbitmq": "^9",
|
|
33
34
|
"@nestjs/bullmq": "^11",
|
|
34
35
|
"@nestjs/cache-manager": "^3",
|
|
35
36
|
"@nestjs/common": "^11",
|
|
@@ -45,6 +46,9 @@
|
|
|
45
46
|
"typeorm": "^0.3"
|
|
46
47
|
},
|
|
47
48
|
"peerDependenciesMeta": {
|
|
49
|
+
"@golevelup/nestjs-rabbitmq": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
48
52
|
"@nestjs/bullmq": {
|
|
49
53
|
"optional": true
|
|
50
54
|
},
|
package/ui/index.html
CHANGED
|
@@ -502,6 +502,7 @@
|
|
|
502
502
|
.badge-model { background-color: rgba(16, 185, 129, 0.12); color: var(--accent-green); }
|
|
503
503
|
.badge-notification { background-color: rgba(245, 158, 11, 0.12); color: var(--accent-amber); }
|
|
504
504
|
.badge-dump { background-color: rgba(139, 92, 246, 0.12); color: var(--accent-purple); }
|
|
505
|
+
.badge-rabbitmq { background-color: rgba(245, 158, 11, 0.12); color: var(--accent-amber); }
|
|
505
506
|
|
|
506
507
|
.badge-get { background-color: rgba(16, 185, 129, 0.15); color: var(--accent-green); }
|
|
507
508
|
.badge-post { background-color: rgba(59, 130, 246, 0.15); color: var(--accent-blue); }
|
|
@@ -869,6 +870,7 @@
|
|
|
869
870
|
{ id: 'command', label: 'Commands', icon: '💻' },
|
|
870
871
|
{ id: 'model', label: 'Models', icon: '📦' },
|
|
871
872
|
{ id: 'notification', label: 'Notifications', icon: '🔔' },
|
|
873
|
+
{ id: 'rabbitmq', label: 'RabbitMQ', icon: '🐰' },
|
|
872
874
|
{ id: 'dump', label: 'Dumps', icon: '🗑️' },
|
|
873
875
|
];
|
|
874
876
|
|
|
@@ -1419,6 +1421,7 @@
|
|
|
1419
1421
|
item.type === 'http_client' ? (`${item.content.method || 'GET'} ${item.content.url}`) :
|
|
1420
1422
|
item.type === 'cache' ? (`Cache ${item.content.action?.toUpperCase()}: ${item.content.key}`) :
|
|
1421
1423
|
item.type === 'redis' ? (`Redis: ${item.content.command}`) :
|
|
1424
|
+
item.type === 'rabbitmq' ? (`${item.content.direction === 'outgoing' ? '→' : '←'} ${item.content.exchange} → ${item.content.routingKey}`) :
|
|
1422
1425
|
JSON.stringify(item.content)}
|
|
1423
1426
|
</span>
|
|
1424
1427
|
{item.type === 'query' && item.content.duration !== undefined && (
|
|
@@ -1452,7 +1455,7 @@
|
|
|
1452
1455
|
|
|
1453
1456
|
// Determine font family for subtitle
|
|
1454
1457
|
function varMono(type) {
|
|
1455
|
-
return (type === 'query' || type === 'redis' || type === 'request' || type === 'http_client' || type === 'command') ? 'var(--font-mono)' : 'var(--font-sans)';
|
|
1458
|
+
return (type === 'query' || type === 'redis' || type === 'request' || type === 'http_client' || type === 'command' || type === 'rabbitmq') ? 'var(--font-mono)' : 'var(--font-sans)';
|
|
1456
1459
|
}
|
|
1457
1460
|
|
|
1458
1461
|
// Helper functions for displaying table items
|
|
@@ -1591,6 +1594,19 @@
|
|
|
1591
1594
|
subtitle: typeof content.message === 'string' ? content.message : JSON.stringify(content.message),
|
|
1592
1595
|
status: <span className="badge badge-status-ok">dumped</span>
|
|
1593
1596
|
};
|
|
1597
|
+
case 'rabbitmq':
|
|
1598
|
+
const dir = content.direction || 'unknown';
|
|
1599
|
+
const dirIcon = dir === 'outgoing' ? '→' : '←';
|
|
1600
|
+
const dirColor = dir === 'outgoing' ? 'var(--accent-blue)' : 'var(--accent-green)';
|
|
1601
|
+
return {
|
|
1602
|
+
title: `${dirIcon} ${content.exchange || ''}`,
|
|
1603
|
+
subtitle: `${content.routingKey || ''} (${content.handler || content.queue || ''})`,
|
|
1604
|
+
status: content.status === 'failed' ? (
|
|
1605
|
+
<span className="badge badge-status-err">failed</span>
|
|
1606
|
+
) : (
|
|
1607
|
+
<span className="badge badge-rabbitmq" style={{ color: dirColor }}>{dir}</span>
|
|
1608
|
+
)
|
|
1609
|
+
};
|
|
1594
1610
|
default:
|
|
1595
1611
|
return {
|
|
1596
1612
|
title: 'Telescope Entry',
|
|
@@ -1974,6 +1990,65 @@
|
|
|
1974
1990
|
</div>
|
|
1975
1991
|
</React.Fragment>
|
|
1976
1992
|
);
|
|
1993
|
+
case 'rabbitmq':
|
|
1994
|
+
return (
|
|
1995
|
+
<React.Fragment>
|
|
1996
|
+
<div className="key-val-row">
|
|
1997
|
+
<div className="key-val-label">Direction</div>
|
|
1998
|
+
<div className="key-val-value" style={{ fontWeight: '600', color: '#fff', textTransform: 'uppercase' }}>{content.direction}</div>
|
|
1999
|
+
</div>
|
|
2000
|
+
<div className="key-val-row">
|
|
2001
|
+
<div className="key-val-label">Exchange</div>
|
|
2002
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)', color: '#818cf8' }}>{content.exchange}</div>
|
|
2003
|
+
</div>
|
|
2004
|
+
<div className="key-val-row">
|
|
2005
|
+
<div className="key-val-label">Routing Key</div>
|
|
2006
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)' }}>{content.routingKey}</div>
|
|
2007
|
+
</div>
|
|
2008
|
+
{content.queue && (
|
|
2009
|
+
<div className="key-val-row">
|
|
2010
|
+
<div className="key-val-label">Queue</div>
|
|
2011
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)' }}>{content.queue}</div>
|
|
2012
|
+
</div>
|
|
2013
|
+
)}
|
|
2014
|
+
{content.handler && (
|
|
2015
|
+
<div className="key-val-row">
|
|
2016
|
+
<div className="key-val-label">Handler</div>
|
|
2017
|
+
<div className="key-val-value" style={{ fontFamily: 'var(--font-mono)' }}>{content.handler}</div>
|
|
2018
|
+
</div>
|
|
2019
|
+
)}
|
|
2020
|
+
{content.duration !== undefined && (
|
|
2021
|
+
<div className="key-val-row">
|
|
2022
|
+
<div className="key-val-label">Duration</div>
|
|
2023
|
+
<div className="key-val-value">{content.duration} ms</div>
|
|
2024
|
+
</div>
|
|
2025
|
+
)}
|
|
2026
|
+
{content.status && (
|
|
2027
|
+
<div className="key-val-row">
|
|
2028
|
+
<div className="key-val-label">Status</div>
|
|
2029
|
+
<div className="key-val-value">
|
|
2030
|
+
{content.status === 'failed' ? (
|
|
2031
|
+
<span className="badge badge-status-err">failed</span>
|
|
2032
|
+
) : (
|
|
2033
|
+
<span className="badge badge-status-ok">{content.status}</span>
|
|
2034
|
+
)}
|
|
2035
|
+
</div>
|
|
2036
|
+
</div>
|
|
2037
|
+
)}
|
|
2038
|
+
{content.error && (
|
|
2039
|
+
<div className="key-val-row">
|
|
2040
|
+
<div className="key-val-label">Error</div>
|
|
2041
|
+
<div className="key-val-value" style={{ color: 'var(--accent-red)' }}>{content.error}</div>
|
|
2042
|
+
</div>
|
|
2043
|
+
)}
|
|
2044
|
+
{content.message && (
|
|
2045
|
+
<div className="key-val-row" style={{ flexDirection: 'column', display: 'flex', gap: '8px' }}>
|
|
2046
|
+
<div className="key-val-label">Message Payload</div>
|
|
2047
|
+
<pre className="json-code">{JSON.stringify(content.message, null, 2)}</pre>
|
|
2048
|
+
</div>
|
|
2049
|
+
)}
|
|
2050
|
+
</React.Fragment>
|
|
2051
|
+
);
|
|
1977
2052
|
default:
|
|
1978
2053
|
return (
|
|
1979
2054
|
<div className="key-val-row">
|