nestjs-profiler 1.0.25 → 1.0.27
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 +254 -147
- package/collectors/event-collector.d.ts +18 -0
- package/collectors/event-collector.js +254 -0
- package/collectors/event-collector.js.map +1 -0
- package/common/profiler-options.interface.d.ts +8 -0
- package/common/profiler.model.d.ts +25 -0
- package/controllers/profiler.controller.d.ts +17 -1
- package/controllers/profiler.controller.js +129 -17
- package/controllers/profiler.controller.js.map +1 -1
- package/middleware/profiler-auth.middleware.d.ts +10 -0
- package/middleware/profiler-auth.middleware.js +110 -0
- package/middleware/profiler-auth.middleware.js.map +1 -0
- package/package.json +2 -2
- package/profiler.module.js +103 -1
- package/profiler.module.js.map +1 -1
- package/services/cron-explorer.service.d.ts +48 -0
- package/services/cron-explorer.service.js +260 -0
- package/services/cron-explorer.service.js.map +1 -0
- package/services/entity-explorer.service.d.ts +1 -1
- package/services/entity-explorer.service.js +7 -7
- package/services/entity-explorer.service.js.map +1 -1
- package/services/health.service.js +23 -8
- package/services/health.service.js.map +1 -1
- package/services/profiler.service.d.ts +10 -1
- package/services/profiler.service.js +103 -35
- package/services/profiler.service.js.map +1 -1
- package/services/route-explorer.service.d.ts +23 -1
- package/services/route-explorer.service.js +136 -10
- package/services/route-explorer.service.js.map +1 -1
- package/services/template-builder.service.d.ts +1 -0
- package/services/template-builder.service.js +184 -83
- package/services/template-builder.service.js.map +1 -1
- package/services/view.service.d.ts +1 -1
- package/services/view.service.js +32 -23
- package/services/view.service.js.map +1 -1
- package/views/cron-jobs.html +635 -0
- package/views/events.html +763 -0
- package/views/layout.html +40 -9
- package/views/login.html +277 -0
- package/views/routes.html +405 -37
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
19
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
20
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
21
|
+
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;
|
|
22
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
23
|
+
};
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
42
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
43
|
+
};
|
|
44
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
45
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
46
|
+
};
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.EventCollector = void 0;
|
|
49
|
+
const common_1 = require("@nestjs/common");
|
|
50
|
+
const async_hooks_1 = require("async_hooks");
|
|
51
|
+
const crypto = __importStar(require("crypto"));
|
|
52
|
+
const profiler_service_1 = require("../services/profiler.service");
|
|
53
|
+
function resolveEE2Token() {
|
|
54
|
+
try {
|
|
55
|
+
const resolved = require.resolve('@nestjs/event-emitter', {
|
|
56
|
+
paths: [process.cwd()],
|
|
57
|
+
});
|
|
58
|
+
return require(resolved).EventEmitter2;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
try {
|
|
62
|
+
return require('@nestjs/event-emitter').EventEmitter2;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return Symbol('PROFILER_NO_EVENT_EMITTER');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const EE2_TOKEN = resolveEE2Token();
|
|
70
|
+
const eventALS = new async_hooks_1.AsyncLocalStorage();
|
|
71
|
+
let EventCollector = class EventCollector {
|
|
72
|
+
constructor(profilerService, eventEmitter) {
|
|
73
|
+
this.profilerService = profilerService;
|
|
74
|
+
this.eventEmitter = eventEmitter;
|
|
75
|
+
this.resolvedListenerNames = new Map();
|
|
76
|
+
this.listenerRegistrationCounters = new Map();
|
|
77
|
+
}
|
|
78
|
+
setListenerNames(map) {
|
|
79
|
+
this.resolvedListenerNames = map;
|
|
80
|
+
}
|
|
81
|
+
onModuleInit() {
|
|
82
|
+
if (this.eventEmitter) {
|
|
83
|
+
this.patchEmitter(this.eventEmitter);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
patchEmitter(emitter) {
|
|
87
|
+
if (emitter.__profilerPatched)
|
|
88
|
+
return;
|
|
89
|
+
emitter.__profilerPatched = true;
|
|
90
|
+
const self = this;
|
|
91
|
+
const makeWrappedListener = (fn, eventName, listenerIndex) => {
|
|
92
|
+
const eagerName = (fn.name || '')
|
|
93
|
+
.replace(/^bound /, '')
|
|
94
|
+
.replace(/^async /, '')
|
|
95
|
+
.trim();
|
|
96
|
+
return async function profilerListener(...args) {
|
|
97
|
+
const resolvedInfo = self.resolvedListenerNames.get(eventName)?.[listenerIndex];
|
|
98
|
+
const listenerName = resolvedInfo?.name || eagerName || `handler-${listenerIndex + 1}`;
|
|
99
|
+
const listenerFile = resolvedInfo?.file || '';
|
|
100
|
+
const trace = {
|
|
101
|
+
name: listenerName,
|
|
102
|
+
file: listenerFile,
|
|
103
|
+
startTime: Date.now(),
|
|
104
|
+
duration: 0,
|
|
105
|
+
status: 'success',
|
|
106
|
+
};
|
|
107
|
+
try {
|
|
108
|
+
const result = await fn(...args);
|
|
109
|
+
trace.duration = Date.now() - trace.startTime;
|
|
110
|
+
self.profilerService.addListenerTrace(eventALS.getStore()?.eventId, trace);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
trace.duration = Date.now() - trace.startTime;
|
|
115
|
+
trace.status = 'error';
|
|
116
|
+
trace.error = e?.message ?? String(e);
|
|
117
|
+
self.profilerService.addListenerTrace(eventALS.getStore()?.eventId, trace);
|
|
118
|
+
throw e;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
const origOn = emitter.on.bind(emitter);
|
|
123
|
+
const origOnce = emitter.once.bind(emitter);
|
|
124
|
+
const origPrepend = emitter.prependListener
|
|
125
|
+
? emitter.prependListener.bind(emitter)
|
|
126
|
+
: null;
|
|
127
|
+
emitter.on = function (event, fn, options) {
|
|
128
|
+
const idx = self.listenerRegistrationCounters.get(String(event)) ?? 0;
|
|
129
|
+
self.listenerRegistrationCounters.set(String(event), idx + 1);
|
|
130
|
+
return origOn(event, makeWrappedListener(fn, String(event), idx), options);
|
|
131
|
+
};
|
|
132
|
+
emitter.addListener = emitter.on;
|
|
133
|
+
emitter.once = function (event, fn, options) {
|
|
134
|
+
const idx = self.listenerRegistrationCounters.get(String(event)) ?? 0;
|
|
135
|
+
self.listenerRegistrationCounters.set(String(event), idx + 1);
|
|
136
|
+
return origOnce(event, makeWrappedListener(fn, String(event), idx), options);
|
|
137
|
+
};
|
|
138
|
+
if (origPrepend) {
|
|
139
|
+
emitter.prependListener = function (event, fn, options) {
|
|
140
|
+
const idx = self.listenerRegistrationCounters.get(String(event)) ?? 0;
|
|
141
|
+
self.listenerRegistrationCounters.set(String(event), idx + 1);
|
|
142
|
+
return origPrepend(event, makeWrappedListener(fn, String(event), idx), options);
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const origEmit = emitter.emit.bind(emitter);
|
|
146
|
+
emitter.emit = function (event, ...args) {
|
|
147
|
+
if (typeof event !== 'string')
|
|
148
|
+
return origEmit(event, ...args);
|
|
149
|
+
const profile = self.buildProfile(event, args, false);
|
|
150
|
+
return eventALS.run({ eventId: profile.id, depth: profile.depth }, () => {
|
|
151
|
+
try {
|
|
152
|
+
const result = origEmit(event, ...args);
|
|
153
|
+
self.profilerService.finalizeEvent(profile.id, 'success');
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
self.profilerService.finalizeEvent(profile.id, 'error', e?.message);
|
|
158
|
+
throw e;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
};
|
|
162
|
+
const origEmitAsync = emitter.emitAsync?.bind(emitter);
|
|
163
|
+
if (origEmitAsync) {
|
|
164
|
+
emitter.emitAsync = async function (event, ...args) {
|
|
165
|
+
if (typeof event !== 'string')
|
|
166
|
+
return origEmitAsync(event, ...args);
|
|
167
|
+
const profile = self.buildProfile(event, args, true);
|
|
168
|
+
return eventALS.run({ eventId: profile.id, depth: profile.depth }, async () => {
|
|
169
|
+
try {
|
|
170
|
+
const result = await origEmitAsync(event, ...args);
|
|
171
|
+
self.profilerService.finalizeEvent(profile.id, 'success');
|
|
172
|
+
return result;
|
|
173
|
+
}
|
|
174
|
+
catch (e) {
|
|
175
|
+
self.profilerService.finalizeEvent(profile.id, 'error', e?.message);
|
|
176
|
+
throw e;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
buildProfile(eventName, args, isAsync) {
|
|
183
|
+
const parent = eventALS.getStore();
|
|
184
|
+
const depth = parent ? parent.depth + 1 : 0;
|
|
185
|
+
const profile = {
|
|
186
|
+
id: crypto.randomUUID(),
|
|
187
|
+
eventName,
|
|
188
|
+
payloadPreview: this.serializePayload(args[0]),
|
|
189
|
+
emittedAt: Date.now(),
|
|
190
|
+
isAsync,
|
|
191
|
+
...this.getCallerLocation(),
|
|
192
|
+
listeners: [],
|
|
193
|
+
totalDuration: 0,
|
|
194
|
+
status: 'pending',
|
|
195
|
+
parentEventId: parent?.eventId,
|
|
196
|
+
requestId: this.profilerService.getCurrentRequestId(),
|
|
197
|
+
depth,
|
|
198
|
+
childEventIds: [],
|
|
199
|
+
};
|
|
200
|
+
if (parent?.eventId) {
|
|
201
|
+
this.profilerService.linkChildEvent(parent.eventId, profile.id);
|
|
202
|
+
}
|
|
203
|
+
this.profilerService.addEvent(profile);
|
|
204
|
+
return profile;
|
|
205
|
+
}
|
|
206
|
+
serializePayload(payload) {
|
|
207
|
+
try {
|
|
208
|
+
const str = JSON.stringify(payload);
|
|
209
|
+
if (!str)
|
|
210
|
+
return '';
|
|
211
|
+
return str.length > 200 ? str.slice(0, 200) + '…' : str;
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return '[unserializable]';
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
getCallerLocation() {
|
|
218
|
+
const lines = (new Error().stack ?? '').split('\n').slice(1);
|
|
219
|
+
const skip = [
|
|
220
|
+
'event-collector',
|
|
221
|
+
'EventCollector',
|
|
222
|
+
'profilerListener',
|
|
223
|
+
'AsyncLocalStorage',
|
|
224
|
+
'node:',
|
|
225
|
+
'eventemitter2',
|
|
226
|
+
'node_modules/@nestjs/event-emitter',
|
|
227
|
+
];
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
const trimmed = line.trim();
|
|
230
|
+
if (skip.some((s) => trimmed.includes(s)))
|
|
231
|
+
continue;
|
|
232
|
+
const m = trimmed.match(/^at (.+?)\s+\((.+?):(\d+):\d+\)/);
|
|
233
|
+
if (m) {
|
|
234
|
+
const name = m[1];
|
|
235
|
+
if (!name.startsWith('Object.') && name !== 'Function') {
|
|
236
|
+
return { emitterLocation: name, emitterFile: `${m[2]}:${m[3]}` };
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
const anon = trimmed.match(/^at (.+?):(\d+):\d+$/);
|
|
240
|
+
if (anon && !anon[1].startsWith('node:')) {
|
|
241
|
+
return { emitterLocation: anon[1], emitterFile: `${anon[1]}:${anon[2]}` };
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return { emitterLocation: 'unknown', emitterFile: '' };
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
exports.EventCollector = EventCollector;
|
|
248
|
+
exports.EventCollector = EventCollector = __decorate([
|
|
249
|
+
(0, common_1.Injectable)(),
|
|
250
|
+
__param(1, (0, common_1.Optional)()),
|
|
251
|
+
__param(1, (0, common_1.Inject)(EE2_TOKEN)),
|
|
252
|
+
__metadata("design:paramtypes", [profiler_service_1.ProfilerService, Object])
|
|
253
|
+
], EventCollector);
|
|
254
|
+
//# sourceMappingURL=event-collector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-collector.js","sourceRoot":"","sources":["../../../libs/nestjs-profiler/src/collectors/event-collector.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,13 @@ export interface ProfilerExplainOptions {
|
|
|
5
5
|
thresholdMs?: number;
|
|
6
6
|
}
|
|
7
7
|
export type ProfilerStorageType = 'memory' | ProfilerStorage;
|
|
8
|
+
export type ProfilerAuth = {
|
|
9
|
+
enabled: false;
|
|
10
|
+
} | {
|
|
11
|
+
enabled: true;
|
|
12
|
+
username: string;
|
|
13
|
+
password: string;
|
|
14
|
+
};
|
|
8
15
|
export interface ProfilerOptions {
|
|
9
16
|
enabled?: boolean;
|
|
10
17
|
storage?: ProfilerStorageType;
|
|
@@ -18,4 +25,5 @@ export interface ProfilerOptions {
|
|
|
18
25
|
collectMysql?: boolean;
|
|
19
26
|
collectHttp?: boolean;
|
|
20
27
|
explain?: ProfilerExplainOptions;
|
|
28
|
+
auth?: ProfilerAuth;
|
|
21
29
|
}
|
|
@@ -44,6 +44,31 @@ export interface HttpCallProfile {
|
|
|
44
44
|
error?: string;
|
|
45
45
|
protocol: 'http' | 'https';
|
|
46
46
|
}
|
|
47
|
+
export interface EventListenerTrace {
|
|
48
|
+
name: string;
|
|
49
|
+
duration: number;
|
|
50
|
+
startTime: number;
|
|
51
|
+
status: 'success' | 'error';
|
|
52
|
+
error?: string;
|
|
53
|
+
file?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface EventProfile {
|
|
56
|
+
id: string;
|
|
57
|
+
eventName: string;
|
|
58
|
+
payloadPreview: string;
|
|
59
|
+
emittedAt: number;
|
|
60
|
+
isAsync: boolean;
|
|
61
|
+
emitterLocation: string;
|
|
62
|
+
emitterFile: string;
|
|
63
|
+
listeners: EventListenerTrace[];
|
|
64
|
+
totalDuration: number;
|
|
65
|
+
status: 'pending' | 'success' | 'error';
|
|
66
|
+
error?: string;
|
|
67
|
+
parentEventId?: string;
|
|
68
|
+
requestId?: string;
|
|
69
|
+
depth: number;
|
|
70
|
+
childEventIds: string[];
|
|
71
|
+
}
|
|
47
72
|
export interface RequestProfile {
|
|
48
73
|
id: string;
|
|
49
74
|
method: string;
|
|
@@ -6,6 +6,8 @@ import { EntityExplorerService } from '../services/entity-explorer.service';
|
|
|
6
6
|
import { RouteExplorerService } from '../services/route-explorer.service';
|
|
7
7
|
import { HealthService } from '../services/health.service';
|
|
8
8
|
import { CodeQualityService } from '../services/code-quality.service';
|
|
9
|
+
import { CronExplorerService } from '../services/cron-explorer.service';
|
|
10
|
+
import { ProfilerOptions } from '../common/profiler-options.interface';
|
|
9
11
|
export declare class ProfilerController {
|
|
10
12
|
private readonly profilerService;
|
|
11
13
|
private readonly viewService;
|
|
@@ -14,7 +16,11 @@ export declare class ProfilerController {
|
|
|
14
16
|
private readonly routeExplorer;
|
|
15
17
|
private readonly healthService;
|
|
16
18
|
private readonly codeQualityService;
|
|
17
|
-
|
|
19
|
+
private readonly cronExplorer;
|
|
20
|
+
private readonly profilerOptions;
|
|
21
|
+
constructor(profilerService: ProfilerService, viewService: ViewService, templateBuilder: TemplateBuilderService, entityExplorer: EntityExplorerService, routeExplorer: RouteExplorerService, healthService: HealthService, codeQualityService: CodeQualityService, cronExplorer: CronExplorerService, profilerOptions: ProfilerOptions);
|
|
22
|
+
private get authEnabled();
|
|
23
|
+
private renderLayout;
|
|
18
24
|
dashboard(res: Response): Promise<void>;
|
|
19
25
|
requestsList(res: Response): Promise<void>;
|
|
20
26
|
listJson(): Promise<import("..").RequestProfile[]>;
|
|
@@ -27,6 +33,12 @@ export declare class ProfilerController {
|
|
|
27
33
|
message: string;
|
|
28
34
|
tip: string;
|
|
29
35
|
}>;
|
|
36
|
+
loginPage(res: Response, returnTo?: string): Promise<void>;
|
|
37
|
+
apiLogin(res: Response, body: {
|
|
38
|
+
username?: string;
|
|
39
|
+
password?: string;
|
|
40
|
+
}): Promise<void>;
|
|
41
|
+
logout(res: Response): Promise<void>;
|
|
30
42
|
detail(id: string, res: Response): Promise<void>;
|
|
31
43
|
detailJson(id: string): Promise<import("..").RequestProfile>;
|
|
32
44
|
summary(res: Response): Promise<void>;
|
|
@@ -40,6 +52,10 @@ export declare class ProfilerController {
|
|
|
40
52
|
healthAudit(force?: string): Promise<import("../services/health.service").HealthReport>;
|
|
41
53
|
codeQualityPage(res: Response): Promise<void>;
|
|
42
54
|
codeQualityAudit(force?: string): Promise<import("../services/code-quality.service").CodeQualityReport>;
|
|
55
|
+
eventsPage(res: Response): Promise<void>;
|
|
56
|
+
eventsApi(): Promise<import("..").EventProfile[]>;
|
|
57
|
+
cronJobsPage(res: Response): Promise<void>;
|
|
58
|
+
cronJobsApi(): Promise<import("../services/cron-explorer.service").CronReport>;
|
|
43
59
|
liveLogsPage(res: Response): Promise<void>;
|
|
44
60
|
liveLogsStream(res: Response): void;
|
|
45
61
|
serveAsset(file: string, res: Response): Promise<void>;
|
|
@@ -21,8 +21,10 @@ const entity_explorer_service_1 = require("../services/entity-explorer.service")
|
|
|
21
21
|
const route_explorer_service_1 = require("../services/route-explorer.service");
|
|
22
22
|
const health_service_1 = require("../services/health.service");
|
|
23
23
|
const code_quality_service_1 = require("../services/code-quality.service");
|
|
24
|
+
const cron_explorer_service_1 = require("../services/cron-explorer.service");
|
|
25
|
+
const crypto_1 = require("crypto");
|
|
24
26
|
let ProfilerController = class ProfilerController {
|
|
25
|
-
constructor(profilerService, viewService, templateBuilder, entityExplorer, routeExplorer, healthService, codeQualityService) {
|
|
27
|
+
constructor(profilerService, viewService, templateBuilder, entityExplorer, routeExplorer, healthService, codeQualityService, cronExplorer, profilerOptions) {
|
|
26
28
|
this.profilerService = profilerService;
|
|
27
29
|
this.viewService = viewService;
|
|
28
30
|
this.templateBuilder = templateBuilder;
|
|
@@ -30,6 +32,14 @@ let ProfilerController = class ProfilerController {
|
|
|
30
32
|
this.routeExplorer = routeExplorer;
|
|
31
33
|
this.healthService = healthService;
|
|
32
34
|
this.codeQualityService = codeQualityService;
|
|
35
|
+
this.cronExplorer = cronExplorer;
|
|
36
|
+
this.profilerOptions = profilerOptions;
|
|
37
|
+
}
|
|
38
|
+
get authEnabled() {
|
|
39
|
+
return this.profilerOptions?.auth?.enabled === true;
|
|
40
|
+
}
|
|
41
|
+
renderLayout(title, content, activeTab) {
|
|
42
|
+
return this.viewService.renderWithLayout(title, content, activeTab, this.authEnabled);
|
|
33
43
|
}
|
|
34
44
|
async dashboard(res) {
|
|
35
45
|
res.redirect('/__profiler/view/summary');
|
|
@@ -37,7 +47,7 @@ let ProfilerController = class ProfilerController {
|
|
|
37
47
|
async requestsList(res) {
|
|
38
48
|
const profiles = await this.profilerService.getDashboardData();
|
|
39
49
|
const content = this.templateBuilder.buildDashboard(profiles);
|
|
40
|
-
const html = this.
|
|
50
|
+
const html = this.renderLayout('Requests', content, 'requests');
|
|
41
51
|
res.header('Content-Type', 'text/html');
|
|
42
52
|
res.send(html);
|
|
43
53
|
}
|
|
@@ -63,21 +73,53 @@ let ProfilerController = class ProfilerController {
|
|
|
63
73
|
return {
|
|
64
74
|
status: 'error',
|
|
65
75
|
message: `Connection failed: ${e.message}`,
|
|
66
|
-
tip: 'Pass correct credentials in URL: ?user=YOUR_USER&password=YOUR_PASS&database=YOUR_DB'
|
|
76
|
+
tip: 'Pass correct credentials in URL: ?user=YOUR_USER&password=YOUR_PASS&database=YOUR_DB',
|
|
67
77
|
};
|
|
68
78
|
}
|
|
69
79
|
}
|
|
80
|
+
async loginPage(res, returnTo) {
|
|
81
|
+
const html = this.viewService.render('login', {
|
|
82
|
+
returnTo: returnTo || '/__profiler',
|
|
83
|
+
});
|
|
84
|
+
res.header('Content-Type', 'text/html');
|
|
85
|
+
res.send(html);
|
|
86
|
+
}
|
|
87
|
+
async apiLogin(res, body) {
|
|
88
|
+
const auth = this.profilerOptions?.auth;
|
|
89
|
+
if (!auth || auth.enabled === false) {
|
|
90
|
+
const expiresAt = Date.now() + 24 * 60 * 60 * 1000;
|
|
91
|
+
res.json({ token: 'no-auth', expiresAt });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const { username = '', password = '' } = body;
|
|
95
|
+
if (username === auth.username && password === auth.password) {
|
|
96
|
+
const expiresAt = Date.now() + 24 * 60 * 60 * 1000;
|
|
97
|
+
const token = (0, crypto_1.createHmac)('sha256', auth.password)
|
|
98
|
+
.update(`${auth.username}:${expiresAt}`)
|
|
99
|
+
.digest('hex');
|
|
100
|
+
res.json({ token, expiresAt, username: auth.username });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
res.status(common_1.HttpStatus.UNAUTHORIZED).json({ error: 'Invalid username or password.' });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async logout(res) {
|
|
107
|
+
const html = `<!DOCTYPE html><html><head><title>Signing out…</title>
|
|
108
|
+
<script>try{localStorage.removeItem('__profiler_auth');}catch(e){}window.location.replace('/__profiler/login');</script>
|
|
109
|
+
</head><body></body></html>`;
|
|
110
|
+
res.header('Content-Type', 'text/html').send(html);
|
|
111
|
+
}
|
|
70
112
|
async detail(id, res) {
|
|
71
113
|
const profile = await this.profilerService.getProfileDetail(id);
|
|
72
114
|
if (!profile) {
|
|
73
115
|
const content = this.templateBuilder.buildNotFound(id);
|
|
74
|
-
const html = this.
|
|
116
|
+
const html = this.renderLayout('Profile Not Found', content);
|
|
75
117
|
res.header('Content-Type', 'text/html');
|
|
76
118
|
res.status(common_1.HttpStatus.NOT_FOUND).send(html);
|
|
77
119
|
return;
|
|
78
120
|
}
|
|
79
121
|
const content = this.templateBuilder.buildDetail(profile);
|
|
80
|
-
const html = this.
|
|
122
|
+
const html = this.renderLayout(`Request ${profile.id}`, content);
|
|
81
123
|
res.header('Content-Type', 'text/html');
|
|
82
124
|
res.send(html);
|
|
83
125
|
}
|
|
@@ -90,54 +132,54 @@ let ProfilerController = class ProfilerController {
|
|
|
90
132
|
async summary(res) {
|
|
91
133
|
const stats = await this.profilerService.getSummaryStats();
|
|
92
134
|
const content = this.templateBuilder.buildSummaryPage(stats);
|
|
93
|
-
const html = this.
|
|
135
|
+
const html = this.renderLayout('Summary', content, 'summary');
|
|
94
136
|
res.header('Content-Type', 'text/html');
|
|
95
137
|
res.send(html);
|
|
96
138
|
}
|
|
97
139
|
async listQueries(res) {
|
|
98
140
|
const queries = await this.profilerService.getQueriesList();
|
|
99
141
|
const content = this.templateBuilder.buildQueriesList(queries);
|
|
100
|
-
const html = this.
|
|
142
|
+
const html = this.renderLayout('Database Queries', content, 'queries');
|
|
101
143
|
res.header('Content-Type', 'text/html');
|
|
102
144
|
res.send(html);
|
|
103
145
|
}
|
|
104
146
|
async listLogs(res, page = 1) {
|
|
105
147
|
const { logs, currentPage, totalPages, totalLogs } = await this.profilerService.getLogsList(page);
|
|
106
148
|
const content = this.templateBuilder.buildLogsList(logs, currentPage, totalPages, totalLogs);
|
|
107
|
-
const html = this.
|
|
149
|
+
const html = this.renderLayout('Application Logs', content, 'logs');
|
|
108
150
|
res.header('Content-Type', 'text/html');
|
|
109
151
|
res.send(html);
|
|
110
152
|
}
|
|
111
153
|
async listEntities(res) {
|
|
112
154
|
const entities = this.entityExplorer.getEntities();
|
|
113
155
|
const content = this.templateBuilder.buildEntitiesList(entities);
|
|
114
|
-
const html = this.
|
|
156
|
+
const html = this.renderLayout('Entity Explorer', content, 'entities');
|
|
115
157
|
res.header('Content-Type', 'text/html');
|
|
116
158
|
res.send(html);
|
|
117
159
|
}
|
|
118
160
|
async listRoutes(res) {
|
|
119
161
|
const routes = this.routeExplorer.getRoutes();
|
|
120
162
|
const content = this.templateBuilder.buildRoutesList(routes);
|
|
121
|
-
const html = this.
|
|
163
|
+
const html = this.renderLayout('Routes Explorer', content, 'routes');
|
|
122
164
|
res.header('Content-Type', 'text/html');
|
|
123
165
|
res.send(html);
|
|
124
166
|
}
|
|
125
167
|
async listCache(res) {
|
|
126
168
|
const cacheOps = await this.profilerService.getCacheList();
|
|
127
169
|
const content = this.templateBuilder.buildCacheList(cacheOps);
|
|
128
|
-
const html = this.
|
|
170
|
+
const html = this.renderLayout('Cache Operations', content, 'cache');
|
|
129
171
|
res.header('Content-Type', 'text/html');
|
|
130
172
|
res.send(html);
|
|
131
173
|
}
|
|
132
174
|
async listHttpCalls(res) {
|
|
133
175
|
const calls = await this.profilerService.getHttpCallsList();
|
|
134
176
|
const content = this.templateBuilder.buildHttpCallsList(calls);
|
|
135
|
-
const html = this.
|
|
177
|
+
const html = this.renderLayout('Outbound HTTP', content, 'http-calls');
|
|
136
178
|
res.header('Content-Type', 'text/html');
|
|
137
179
|
res.send(html);
|
|
138
180
|
}
|
|
139
181
|
async healthPage(res) {
|
|
140
|
-
const html = this.
|
|
182
|
+
const html = this.renderLayout('Health', this.templateBuilder.buildHealthPage(), 'health');
|
|
141
183
|
res.header('Content-Type', 'text/html');
|
|
142
184
|
res.send(html);
|
|
143
185
|
}
|
|
@@ -145,15 +187,33 @@ let ProfilerController = class ProfilerController {
|
|
|
145
187
|
return this.healthService.runHealthCheck(force === 'true');
|
|
146
188
|
}
|
|
147
189
|
async codeQualityPage(res) {
|
|
148
|
-
const html = this.
|
|
190
|
+
const html = this.renderLayout('Code Quality', this.templateBuilder.buildCodeQualityPage(), 'code-quality');
|
|
149
191
|
res.header('Content-Type', 'text/html');
|
|
150
192
|
res.send(html);
|
|
151
193
|
}
|
|
152
194
|
async codeQualityAudit(force) {
|
|
153
195
|
return this.codeQualityService.runCheck(force === 'true');
|
|
154
196
|
}
|
|
197
|
+
async eventsPage(res) {
|
|
198
|
+
const html = this.renderLayout('Event Tracking', this.templateBuilder.buildEventsPage(), 'events');
|
|
199
|
+
res.header('Content-Type', 'text/html');
|
|
200
|
+
res.send(html);
|
|
201
|
+
}
|
|
202
|
+
async eventsApi() {
|
|
203
|
+
return this.profilerService.getEventsList();
|
|
204
|
+
}
|
|
205
|
+
async cronJobsPage(res) {
|
|
206
|
+
const report = this.cronExplorer.getReport();
|
|
207
|
+
const cronDataJson = JSON.stringify(report);
|
|
208
|
+
const content = this.viewService.render('cron-jobs', { cronDataJson });
|
|
209
|
+
const html = this.renderLayout('Scheduled Jobs', content, 'cron-jobs');
|
|
210
|
+
res.header('Content-Type', 'text/html').send(html);
|
|
211
|
+
}
|
|
212
|
+
async cronJobsApi() {
|
|
213
|
+
return this.cronExplorer.getReport();
|
|
214
|
+
}
|
|
155
215
|
async liveLogsPage(res) {
|
|
156
|
-
const html = this.
|
|
216
|
+
const html = this.renderLayout('Live Logs', this.templateBuilder.buildLiveLogsPage(), 'live-logs');
|
|
157
217
|
res.header('Content-Type', 'text/html');
|
|
158
218
|
res.send(html);
|
|
159
219
|
}
|
|
@@ -165,7 +225,7 @@ let ProfilerController = class ProfilerController {
|
|
|
165
225
|
res.flushHeaders();
|
|
166
226
|
this.profilerService.logEmitter.setMaxListeners(this.profilerService.logEmitter.getMaxListeners() + 1);
|
|
167
227
|
res.write(`data: ${JSON.stringify({ level: 'system', message: 'Stream connected', timestamp: Date.now() })}\n\n`);
|
|
168
|
-
|
|
228
|
+
const batch = [];
|
|
169
229
|
let batchTimer = null;
|
|
170
230
|
const flush = () => {
|
|
171
231
|
batchTimer = null;
|
|
@@ -264,6 +324,29 @@ __decorate([
|
|
|
264
324
|
__metadata("design:paramtypes", []),
|
|
265
325
|
__metadata("design:returntype", Promise)
|
|
266
326
|
], ProfilerController.prototype, "debugQuery", null);
|
|
327
|
+
__decorate([
|
|
328
|
+
(0, common_1.Get)('login'),
|
|
329
|
+
__param(0, (0, common_1.Res)()),
|
|
330
|
+
__param(1, (0, common_1.Query)('returnTo')),
|
|
331
|
+
__metadata("design:type", Function),
|
|
332
|
+
__metadata("design:paramtypes", [Object, String]),
|
|
333
|
+
__metadata("design:returntype", Promise)
|
|
334
|
+
], ProfilerController.prototype, "loginPage", null);
|
|
335
|
+
__decorate([
|
|
336
|
+
(0, common_1.Post)('api/login'),
|
|
337
|
+
__param(0, (0, common_1.Res)()),
|
|
338
|
+
__param(1, (0, common_1.Body)()),
|
|
339
|
+
__metadata("design:type", Function),
|
|
340
|
+
__metadata("design:paramtypes", [Object, Object]),
|
|
341
|
+
__metadata("design:returntype", Promise)
|
|
342
|
+
], ProfilerController.prototype, "apiLogin", null);
|
|
343
|
+
__decorate([
|
|
344
|
+
(0, common_1.Get)('logout'),
|
|
345
|
+
__param(0, (0, common_1.Res)()),
|
|
346
|
+
__metadata("design:type", Function),
|
|
347
|
+
__metadata("design:paramtypes", [Object]),
|
|
348
|
+
__metadata("design:returntype", Promise)
|
|
349
|
+
], ProfilerController.prototype, "logout", null);
|
|
267
350
|
__decorate([
|
|
268
351
|
(0, common_1.Get)(':id'),
|
|
269
352
|
__param(0, (0, common_1.Param)('id')),
|
|
@@ -357,6 +440,32 @@ __decorate([
|
|
|
357
440
|
__metadata("design:paramtypes", [String]),
|
|
358
441
|
__metadata("design:returntype", Promise)
|
|
359
442
|
], ProfilerController.prototype, "codeQualityAudit", null);
|
|
443
|
+
__decorate([
|
|
444
|
+
(0, common_1.Get)('view/events'),
|
|
445
|
+
__param(0, (0, common_1.Res)()),
|
|
446
|
+
__metadata("design:type", Function),
|
|
447
|
+
__metadata("design:paramtypes", [Object]),
|
|
448
|
+
__metadata("design:returntype", Promise)
|
|
449
|
+
], ProfilerController.prototype, "eventsPage", null);
|
|
450
|
+
__decorate([
|
|
451
|
+
(0, common_1.Get)('api/events'),
|
|
452
|
+
__metadata("design:type", Function),
|
|
453
|
+
__metadata("design:paramtypes", []),
|
|
454
|
+
__metadata("design:returntype", Promise)
|
|
455
|
+
], ProfilerController.prototype, "eventsApi", null);
|
|
456
|
+
__decorate([
|
|
457
|
+
(0, common_1.Get)('view/cron-jobs'),
|
|
458
|
+
__param(0, (0, common_1.Res)()),
|
|
459
|
+
__metadata("design:type", Function),
|
|
460
|
+
__metadata("design:paramtypes", [Object]),
|
|
461
|
+
__metadata("design:returntype", Promise)
|
|
462
|
+
], ProfilerController.prototype, "cronJobsPage", null);
|
|
463
|
+
__decorate([
|
|
464
|
+
(0, common_1.Get)('api/cron-jobs'),
|
|
465
|
+
__metadata("design:type", Function),
|
|
466
|
+
__metadata("design:paramtypes", []),
|
|
467
|
+
__metadata("design:returntype", Promise)
|
|
468
|
+
], ProfilerController.prototype, "cronJobsApi", null);
|
|
360
469
|
__decorate([
|
|
361
470
|
(0, common_1.Get)('view/logs/live'),
|
|
362
471
|
__param(0, (0, common_1.Res)()),
|
|
@@ -389,12 +498,15 @@ __decorate([
|
|
|
389
498
|
], ProfilerController.prototype, "serveJs", null);
|
|
390
499
|
exports.ProfilerController = ProfilerController = __decorate([
|
|
391
500
|
(0, common_1.Controller)('__profiler'),
|
|
501
|
+
__param(8, (0, common_1.Optional)()),
|
|
502
|
+
__param(8, (0, common_1.Inject)('PROFILER_OPTIONS')),
|
|
392
503
|
__metadata("design:paramtypes", [profiler_service_1.ProfilerService,
|
|
393
504
|
view_service_1.ViewService,
|
|
394
505
|
template_builder_service_1.TemplateBuilderService,
|
|
395
506
|
entity_explorer_service_1.EntityExplorerService,
|
|
396
507
|
route_explorer_service_1.RouteExplorerService,
|
|
397
508
|
health_service_1.HealthService,
|
|
398
|
-
code_quality_service_1.CodeQualityService
|
|
509
|
+
code_quality_service_1.CodeQualityService,
|
|
510
|
+
cron_explorer_service_1.CronExplorerService, Object])
|
|
399
511
|
], ProfilerController);
|
|
400
512
|
//# sourceMappingURL=profiler.controller.js.map
|