chrome-cdp-cli 2.1.0 → 2.1.2
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 +380 -955
- package/dist/cli/EnhancedCLIInterface.js +48 -38
- package/dist/cli/OutputFormatter.js +77 -75
- package/dist/cli/OutputManager.js +20 -20
- package/dist/client/index.js +0 -1
- package/dist/handlers/EvaluateScriptHandler.js +74 -270
- package/package.json +1 -1
- package/dist/client/ProxyClient.js +0 -278
- package/dist/handlers/RestartProxyHandler.js +0 -97
- package/dist/proxy/ProxyManager.js +0 -270
- package/dist/proxy/index.js +0 -60
- package/dist/proxy/server/CDPEventMonitor.js +0 -263
- package/dist/proxy/server/CDPProxyServer.js +0 -441
- package/dist/proxy/server/CommandExecutionService.js +0 -297
- package/dist/proxy/server/ConnectionPool.js +0 -437
- package/dist/proxy/server/FileSystemSecurity.js +0 -358
- package/dist/proxy/server/HealthMonitor.js +0 -242
- package/dist/proxy/server/MessageStore.js +0 -291
- package/dist/proxy/server/PerformanceMonitor.js +0 -277
- package/dist/proxy/server/ProxyAPIServer.js +0 -1125
- package/dist/proxy/server/SecurityManager.js +0 -337
- package/dist/proxy/server/WSProxy.js +0 -468
- package/dist/proxy/types/ProxyTypes.js +0 -2
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.MessageStore = void 0;
|
|
4
|
-
const logger_1 = require("../../utils/logger");
|
|
5
|
-
class MessageStore {
|
|
6
|
-
constructor(maxConsoleMessages = 1000, maxNetworkRequests = 500) {
|
|
7
|
-
this.consoleMessages = new Map();
|
|
8
|
-
this.networkRequests = new Map();
|
|
9
|
-
this.maxConsoleMessages = maxConsoleMessages;
|
|
10
|
-
this.maxNetworkRequests = maxNetworkRequests;
|
|
11
|
-
this.logger = new logger_1.Logger();
|
|
12
|
-
}
|
|
13
|
-
addConsoleMessage(connectionId, message) {
|
|
14
|
-
if (!this.consoleMessages.has(connectionId)) {
|
|
15
|
-
this.consoleMessages.set(connectionId, []);
|
|
16
|
-
}
|
|
17
|
-
const messages = this.consoleMessages.get(connectionId);
|
|
18
|
-
messages.push(message);
|
|
19
|
-
if (messages.length > this.maxConsoleMessages) {
|
|
20
|
-
const removed = messages.splice(0, messages.length - this.maxConsoleMessages);
|
|
21
|
-
this.logger.debug(`Removed ${removed.length} old console messages for connection ${connectionId}`);
|
|
22
|
-
}
|
|
23
|
-
this.logger.debug(`Added console message (${message.type}) for connection ${connectionId}: ${message.text.substring(0, 100)}`);
|
|
24
|
-
}
|
|
25
|
-
getConsoleMessages(connectionId, filter) {
|
|
26
|
-
const messages = this.consoleMessages.get(connectionId) || [];
|
|
27
|
-
if (!filter) {
|
|
28
|
-
return [...messages];
|
|
29
|
-
}
|
|
30
|
-
let filteredMessages = [...messages];
|
|
31
|
-
if (filter.types && filter.types.length > 0) {
|
|
32
|
-
filteredMessages = filteredMessages.filter(msg => filter.types.includes(msg.type));
|
|
33
|
-
}
|
|
34
|
-
if (filter.textPattern) {
|
|
35
|
-
const pattern = new RegExp(filter.textPattern, 'i');
|
|
36
|
-
filteredMessages = filteredMessages.filter(msg => pattern.test(msg.text));
|
|
37
|
-
}
|
|
38
|
-
if (filter.source) {
|
|
39
|
-
filteredMessages = filteredMessages.filter(msg => msg.source === filter.source);
|
|
40
|
-
}
|
|
41
|
-
if (filter.startTime) {
|
|
42
|
-
filteredMessages = filteredMessages.filter(msg => msg.timestamp >= filter.startTime);
|
|
43
|
-
}
|
|
44
|
-
if (filter.endTime) {
|
|
45
|
-
filteredMessages = filteredMessages.filter(msg => msg.timestamp <= filter.endTime);
|
|
46
|
-
}
|
|
47
|
-
if (filter.maxMessages && filter.maxMessages > 0) {
|
|
48
|
-
filteredMessages = filteredMessages.slice(-filter.maxMessages);
|
|
49
|
-
}
|
|
50
|
-
return filteredMessages;
|
|
51
|
-
}
|
|
52
|
-
getLatestConsoleMessage(connectionId, filter) {
|
|
53
|
-
const messages = this.getConsoleMessages(connectionId, filter);
|
|
54
|
-
return messages.length > 0 ? messages[messages.length - 1] : null;
|
|
55
|
-
}
|
|
56
|
-
clearConsoleMessages(connectionId) {
|
|
57
|
-
this.consoleMessages.delete(connectionId);
|
|
58
|
-
this.logger.debug(`Cleared console messages for connection ${connectionId}`);
|
|
59
|
-
}
|
|
60
|
-
getConsoleMessageCount(connectionId, filter) {
|
|
61
|
-
return this.getConsoleMessages(connectionId, filter).length;
|
|
62
|
-
}
|
|
63
|
-
addNetworkRequest(connectionId, request) {
|
|
64
|
-
if (!this.networkRequests.has(connectionId)) {
|
|
65
|
-
this.networkRequests.set(connectionId, []);
|
|
66
|
-
}
|
|
67
|
-
const requests = this.networkRequests.get(connectionId);
|
|
68
|
-
requests.push(request);
|
|
69
|
-
if (requests.length > this.maxNetworkRequests) {
|
|
70
|
-
const removed = requests.splice(0, requests.length - this.maxNetworkRequests);
|
|
71
|
-
this.logger.debug(`Removed ${removed.length} old network requests for connection ${connectionId}`);
|
|
72
|
-
}
|
|
73
|
-
this.logger.debug(`Added network request for connection ${connectionId}: ${request.method} ${request.url}`);
|
|
74
|
-
}
|
|
75
|
-
updateNetworkRequest(connectionId, requestId, update) {
|
|
76
|
-
const requests = this.networkRequests.get(connectionId);
|
|
77
|
-
if (!requests) {
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const request = requests.find(r => r.requestId === requestId);
|
|
81
|
-
if (request) {
|
|
82
|
-
Object.assign(request, update);
|
|
83
|
-
this.logger.debug(`Updated network request ${requestId} for connection ${connectionId}`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
getNetworkRequests(connectionId, filter) {
|
|
87
|
-
const requests = this.networkRequests.get(connectionId) || [];
|
|
88
|
-
if (!filter) {
|
|
89
|
-
return [...requests];
|
|
90
|
-
}
|
|
91
|
-
let filteredRequests = [...requests];
|
|
92
|
-
if (filter.methods && filter.methods.length > 0) {
|
|
93
|
-
filteredRequests = filteredRequests.filter(req => filter.methods.includes(req.method.toUpperCase()));
|
|
94
|
-
}
|
|
95
|
-
if (filter.statusCodes && filter.statusCodes.length > 0) {
|
|
96
|
-
filteredRequests = filteredRequests.filter(req => req.status && filter.statusCodes.includes(req.status));
|
|
97
|
-
}
|
|
98
|
-
if (filter.urlPattern) {
|
|
99
|
-
const pattern = new RegExp(filter.urlPattern, 'i');
|
|
100
|
-
filteredRequests = filteredRequests.filter(req => pattern.test(req.url));
|
|
101
|
-
}
|
|
102
|
-
if (filter.startTime) {
|
|
103
|
-
filteredRequests = filteredRequests.filter(req => req.timestamp >= filter.startTime);
|
|
104
|
-
}
|
|
105
|
-
if (filter.endTime) {
|
|
106
|
-
filteredRequests = filteredRequests.filter(req => req.timestamp <= filter.endTime);
|
|
107
|
-
}
|
|
108
|
-
if (!filter.includeResponseBody) {
|
|
109
|
-
filteredRequests = filteredRequests.map(req => ({
|
|
110
|
-
...req,
|
|
111
|
-
responseBody: undefined
|
|
112
|
-
}));
|
|
113
|
-
}
|
|
114
|
-
if (filter.maxRequests && filter.maxRequests > 0) {
|
|
115
|
-
filteredRequests = filteredRequests.slice(-filter.maxRequests);
|
|
116
|
-
}
|
|
117
|
-
return filteredRequests;
|
|
118
|
-
}
|
|
119
|
-
getLatestNetworkRequest(connectionId, filter) {
|
|
120
|
-
const requests = this.getNetworkRequests(connectionId, filter);
|
|
121
|
-
return requests.length > 0 ? requests[requests.length - 1] : null;
|
|
122
|
-
}
|
|
123
|
-
clearNetworkRequests(connectionId) {
|
|
124
|
-
this.networkRequests.delete(connectionId);
|
|
125
|
-
this.logger.debug(`Cleared network requests for connection ${connectionId}`);
|
|
126
|
-
}
|
|
127
|
-
getNetworkRequestCount(connectionId, filter) {
|
|
128
|
-
return this.getNetworkRequests(connectionId, filter).length;
|
|
129
|
-
}
|
|
130
|
-
cleanupConnection(connectionId) {
|
|
131
|
-
this.clearConsoleMessages(connectionId);
|
|
132
|
-
this.clearNetworkRequests(connectionId);
|
|
133
|
-
this.logger.info(`Cleaned up all data for connection ${connectionId}`);
|
|
134
|
-
}
|
|
135
|
-
clearAll() {
|
|
136
|
-
this.consoleMessages.clear();
|
|
137
|
-
this.networkRequests.clear();
|
|
138
|
-
this.logger.info('Cleared all stored messages and requests');
|
|
139
|
-
}
|
|
140
|
-
enforceMemoryLimits() {
|
|
141
|
-
let totalConsoleMessages = 0;
|
|
142
|
-
let totalNetworkRequests = 0;
|
|
143
|
-
for (const messages of this.consoleMessages.values()) {
|
|
144
|
-
totalConsoleMessages += messages.length;
|
|
145
|
-
}
|
|
146
|
-
for (const requests of this.networkRequests.values()) {
|
|
147
|
-
totalNetworkRequests += requests.length;
|
|
148
|
-
}
|
|
149
|
-
this.logger.debug(`Memory usage: ${totalConsoleMessages} console messages, ${totalNetworkRequests} network requests`);
|
|
150
|
-
if (totalConsoleMessages > this.maxConsoleMessages * 2) {
|
|
151
|
-
this.cleanupOldestConsoleMessages();
|
|
152
|
-
}
|
|
153
|
-
if (totalNetworkRequests > this.maxNetworkRequests * 2) {
|
|
154
|
-
this.cleanupOldestNetworkRequests();
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
getStorageStats() {
|
|
158
|
-
const stats = {
|
|
159
|
-
connections: 0,
|
|
160
|
-
totalConsoleMessages: 0,
|
|
161
|
-
totalNetworkRequests: 0,
|
|
162
|
-
consoleMessagesByConnection: {},
|
|
163
|
-
networkRequestsByConnection: {}
|
|
164
|
-
};
|
|
165
|
-
const connectionIds = new Set([
|
|
166
|
-
...this.consoleMessages.keys(),
|
|
167
|
-
...this.networkRequests.keys()
|
|
168
|
-
]);
|
|
169
|
-
stats.connections = connectionIds.size;
|
|
170
|
-
for (const connectionId of connectionIds) {
|
|
171
|
-
const consoleCount = this.consoleMessages.get(connectionId)?.length || 0;
|
|
172
|
-
const networkCount = this.networkRequests.get(connectionId)?.length || 0;
|
|
173
|
-
stats.consoleMessagesByConnection[connectionId] = consoleCount;
|
|
174
|
-
stats.networkRequestsByConnection[connectionId] = networkCount;
|
|
175
|
-
stats.totalConsoleMessages += consoleCount;
|
|
176
|
-
stats.totalNetworkRequests += networkCount;
|
|
177
|
-
}
|
|
178
|
-
return stats;
|
|
179
|
-
}
|
|
180
|
-
processConsoleAPIEvent(connectionId, params) {
|
|
181
|
-
try {
|
|
182
|
-
const message = {
|
|
183
|
-
connectionId,
|
|
184
|
-
type: this.mapConsoleType(params.type),
|
|
185
|
-
text: this.formatConsoleArgs(params.args || []),
|
|
186
|
-
args: (params.args || []).map((arg) => arg.value || arg.description || ''),
|
|
187
|
-
timestamp: params.timestamp || Date.now(),
|
|
188
|
-
stackTrace: params.stackTrace ? this.convertStackTrace(params.stackTrace.callFrames) : undefined,
|
|
189
|
-
source: 'Runtime.consoleAPICalled'
|
|
190
|
-
};
|
|
191
|
-
this.addConsoleMessage(connectionId, message);
|
|
192
|
-
}
|
|
193
|
-
catch (error) {
|
|
194
|
-
this.logger.error('Error processing console API event:', error);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
processLogEntryEvent(connectionId, params) {
|
|
198
|
-
try {
|
|
199
|
-
const entry = params.entry;
|
|
200
|
-
const message = {
|
|
201
|
-
connectionId,
|
|
202
|
-
type: this.mapLogLevel(entry.level),
|
|
203
|
-
text: entry.text || '',
|
|
204
|
-
args: [entry.text || ''],
|
|
205
|
-
timestamp: entry.timestamp || Date.now(),
|
|
206
|
-
stackTrace: entry.url && entry.lineNumber ? [{
|
|
207
|
-
functionName: '<unknown>',
|
|
208
|
-
url: entry.url,
|
|
209
|
-
lineNumber: entry.lineNumber,
|
|
210
|
-
columnNumber: 0
|
|
211
|
-
}] : undefined,
|
|
212
|
-
source: 'Log.entryAdded'
|
|
213
|
-
};
|
|
214
|
-
this.addConsoleMessage(connectionId, message);
|
|
215
|
-
}
|
|
216
|
-
catch (error) {
|
|
217
|
-
this.logger.error('Error processing log entry event:', error);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
mapConsoleType(cdpType) {
|
|
221
|
-
switch (cdpType) {
|
|
222
|
-
case 'log': return 'log';
|
|
223
|
-
case 'info': return 'info';
|
|
224
|
-
case 'warning': return 'warn';
|
|
225
|
-
case 'error': return 'error';
|
|
226
|
-
case 'debug': return 'debug';
|
|
227
|
-
default: return 'log';
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
mapLogLevel(logLevel) {
|
|
231
|
-
switch (logLevel.toLowerCase()) {
|
|
232
|
-
case 'verbose':
|
|
233
|
-
case 'info': return 'info';
|
|
234
|
-
case 'warning': return 'warn';
|
|
235
|
-
case 'error': return 'error';
|
|
236
|
-
default: return 'log';
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
formatConsoleArgs(args) {
|
|
240
|
-
return args.map(arg => {
|
|
241
|
-
if (arg.value !== undefined) {
|
|
242
|
-
if (typeof arg.value === 'string') {
|
|
243
|
-
return arg.value;
|
|
244
|
-
}
|
|
245
|
-
return JSON.stringify(arg.value);
|
|
246
|
-
}
|
|
247
|
-
return arg.description || '';
|
|
248
|
-
}).join(' ');
|
|
249
|
-
}
|
|
250
|
-
convertStackTrace(callFrames) {
|
|
251
|
-
return callFrames.map(frame => ({
|
|
252
|
-
functionName: frame.functionName || '<anonymous>',
|
|
253
|
-
url: frame.url,
|
|
254
|
-
lineNumber: frame.lineNumber,
|
|
255
|
-
columnNumber: frame.columnNumber
|
|
256
|
-
}));
|
|
257
|
-
}
|
|
258
|
-
cleanupOldestConsoleMessages() {
|
|
259
|
-
let maxMessages = 0;
|
|
260
|
-
let connectionToCleanup = '';
|
|
261
|
-
for (const [connectionId, messages] of this.consoleMessages) {
|
|
262
|
-
if (messages.length > maxMessages) {
|
|
263
|
-
maxMessages = messages.length;
|
|
264
|
-
connectionToCleanup = connectionId;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
if (connectionToCleanup) {
|
|
268
|
-
const messages = this.consoleMessages.get(connectionToCleanup);
|
|
269
|
-
const toRemove = Math.floor(messages.length * 0.2);
|
|
270
|
-
messages.splice(0, toRemove);
|
|
271
|
-
this.logger.info(`Cleaned up ${toRemove} old console messages from connection ${connectionToCleanup}`);
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
cleanupOldestNetworkRequests() {
|
|
275
|
-
let maxRequests = 0;
|
|
276
|
-
let connectionToCleanup = '';
|
|
277
|
-
for (const [connectionId, requests] of this.networkRequests) {
|
|
278
|
-
if (requests.length > maxRequests) {
|
|
279
|
-
maxRequests = requests.length;
|
|
280
|
-
connectionToCleanup = connectionId;
|
|
281
|
-
}
|
|
282
|
-
}
|
|
283
|
-
if (connectionToCleanup) {
|
|
284
|
-
const requests = this.networkRequests.get(connectionToCleanup);
|
|
285
|
-
const toRemove = Math.floor(requests.length * 0.2);
|
|
286
|
-
requests.splice(0, toRemove);
|
|
287
|
-
this.logger.info(`Cleaned up ${toRemove} old network requests from connection ${connectionToCleanup}`);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
exports.MessageStore = MessageStore;
|
|
@@ -1,277 +0,0 @@
|
|
|
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 __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PerformanceMonitor = void 0;
|
|
37
|
-
const logger_1 = require("../../utils/logger");
|
|
38
|
-
const os = __importStar(require("os"));
|
|
39
|
-
class PerformanceMonitor {
|
|
40
|
-
constructor(connectionPool, messageStore, thresholds) {
|
|
41
|
-
this.metricsHistory = [];
|
|
42
|
-
this.maxHistorySize = 100;
|
|
43
|
-
this.lastAlertTimes = new Map();
|
|
44
|
-
this.alertCooldownMs = 300000;
|
|
45
|
-
this.logger = (0, logger_1.createLogger)({ component: 'PerformanceMonitor' });
|
|
46
|
-
this.connectionPool = connectionPool;
|
|
47
|
-
this.messageStore = messageStore;
|
|
48
|
-
this.startTime = Date.now();
|
|
49
|
-
this.thresholds = {
|
|
50
|
-
memoryUtilizationWarning: 80,
|
|
51
|
-
memoryUtilizationCritical: 95,
|
|
52
|
-
heapUtilizationWarning: 80,
|
|
53
|
-
heapUtilizationCritical: 95,
|
|
54
|
-
connectionCountWarning: 50,
|
|
55
|
-
connectionCountCritical: 100,
|
|
56
|
-
messageCountWarning: 10000,
|
|
57
|
-
messageCountCritical: 50000,
|
|
58
|
-
...thresholds
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
start(intervalMs = 60000) {
|
|
62
|
-
if (this.monitoringInterval) {
|
|
63
|
-
this.logger.warn('Performance monitoring is already running');
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
this.logger.info('Starting performance monitoring', {
|
|
67
|
-
intervalMs,
|
|
68
|
-
thresholds: this.thresholds
|
|
69
|
-
});
|
|
70
|
-
this.collectMetrics();
|
|
71
|
-
this.monitoringInterval = setInterval(() => {
|
|
72
|
-
this.collectMetrics();
|
|
73
|
-
}, intervalMs);
|
|
74
|
-
}
|
|
75
|
-
stop() {
|
|
76
|
-
if (this.monitoringInterval) {
|
|
77
|
-
clearInterval(this.monitoringInterval);
|
|
78
|
-
this.monitoringInterval = undefined;
|
|
79
|
-
this.logger.info('Performance monitoring stopped');
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
collectMetrics() {
|
|
83
|
-
const now = Date.now();
|
|
84
|
-
const memoryUsage = process.memoryUsage();
|
|
85
|
-
const connections = this.connectionPool.getAllConnections();
|
|
86
|
-
const storageStats = this.messageStore.getStorageStats();
|
|
87
|
-
const loadAvg = os.loadavg();
|
|
88
|
-
const freeMemory = os.freemem();
|
|
89
|
-
const totalMemory = os.totalmem();
|
|
90
|
-
const memoryUtilization = ((totalMemory - freeMemory) / totalMemory) * 100;
|
|
91
|
-
const heapUtilization = (memoryUsage.heapUsed / memoryUsage.heapTotal) * 100;
|
|
92
|
-
const healthyConnections = connections.filter(c => c.isHealthy).length;
|
|
93
|
-
const totalClientConnections = connections.reduce((sum, c) => sum + c.clientCount, 0);
|
|
94
|
-
const averageClientCount = connections.length > 0 ? totalClientConnections / connections.length : 0;
|
|
95
|
-
const averageMessagesPerConnection = connections.length > 0
|
|
96
|
-
? storageStats.totalConsoleMessages / connections.length
|
|
97
|
-
: 0;
|
|
98
|
-
const averageRequestsPerConnection = connections.length > 0
|
|
99
|
-
? storageStats.totalNetworkRequests / connections.length
|
|
100
|
-
: 0;
|
|
101
|
-
const metrics = {
|
|
102
|
-
timestamp: now,
|
|
103
|
-
uptime: now - this.startTime,
|
|
104
|
-
memory: {
|
|
105
|
-
heapUsed: memoryUsage.heapUsed,
|
|
106
|
-
heapTotal: memoryUsage.heapTotal,
|
|
107
|
-
external: memoryUsage.external,
|
|
108
|
-
rss: memoryUsage.rss,
|
|
109
|
-
heapUtilization
|
|
110
|
-
},
|
|
111
|
-
system: {
|
|
112
|
-
loadAverage: loadAvg,
|
|
113
|
-
freeMemory,
|
|
114
|
-
totalMemory,
|
|
115
|
-
memoryUtilization,
|
|
116
|
-
cpuCount: os.cpus().length
|
|
117
|
-
},
|
|
118
|
-
connections: {
|
|
119
|
-
total: connections.length,
|
|
120
|
-
healthy: healthyConnections,
|
|
121
|
-
unhealthy: connections.length - healthyConnections,
|
|
122
|
-
averageClientCount,
|
|
123
|
-
totalClientConnections
|
|
124
|
-
},
|
|
125
|
-
messages: {
|
|
126
|
-
totalConsoleMessages: storageStats.totalConsoleMessages,
|
|
127
|
-
totalNetworkRequests: storageStats.totalNetworkRequests,
|
|
128
|
-
averageMessagesPerConnection,
|
|
129
|
-
averageRequestsPerConnection
|
|
130
|
-
},
|
|
131
|
-
performance: {}
|
|
132
|
-
};
|
|
133
|
-
this.metricsHistory.push(metrics);
|
|
134
|
-
if (this.metricsHistory.length > this.maxHistorySize) {
|
|
135
|
-
this.metricsHistory.shift();
|
|
136
|
-
}
|
|
137
|
-
this.logger.logPerformanceMetrics('PerformanceMonitor', {
|
|
138
|
-
uptime: metrics.uptime,
|
|
139
|
-
memoryUtilization: metrics.system.memoryUtilization,
|
|
140
|
-
heapUtilization: metrics.memory.heapUtilization,
|
|
141
|
-
connectionCount: metrics.connections.total,
|
|
142
|
-
messageCount: metrics.messages.totalConsoleMessages,
|
|
143
|
-
requestCount: metrics.messages.totalNetworkRequests,
|
|
144
|
-
loadAverage: metrics.system.loadAverage[0]
|
|
145
|
-
});
|
|
146
|
-
this.checkThresholds(metrics);
|
|
147
|
-
return metrics;
|
|
148
|
-
}
|
|
149
|
-
checkThresholds(metrics) {
|
|
150
|
-
if (metrics.system.memoryUtilization >= this.thresholds.memoryUtilizationCritical) {
|
|
151
|
-
this.sendAlert('memory-critical', 'Critical system memory utilization', {
|
|
152
|
-
utilization: metrics.system.memoryUtilization,
|
|
153
|
-
threshold: this.thresholds.memoryUtilizationCritical,
|
|
154
|
-
freeMemory: metrics.system.freeMemory,
|
|
155
|
-
totalMemory: metrics.system.totalMemory
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
else if (metrics.system.memoryUtilization >= this.thresholds.memoryUtilizationWarning) {
|
|
159
|
-
this.sendAlert('memory-warning', 'High system memory utilization', {
|
|
160
|
-
utilization: metrics.system.memoryUtilization,
|
|
161
|
-
threshold: this.thresholds.memoryUtilizationWarning,
|
|
162
|
-
freeMemory: metrics.system.freeMemory,
|
|
163
|
-
totalMemory: metrics.system.totalMemory
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
if (metrics.memory.heapUtilization >= this.thresholds.heapUtilizationCritical) {
|
|
167
|
-
this.sendAlert('heap-critical', 'Critical heap memory utilization', {
|
|
168
|
-
utilization: metrics.memory.heapUtilization,
|
|
169
|
-
threshold: this.thresholds.heapUtilizationCritical,
|
|
170
|
-
heapUsed: metrics.memory.heapUsed,
|
|
171
|
-
heapTotal: metrics.memory.heapTotal
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
else if (metrics.memory.heapUtilization >= this.thresholds.heapUtilizationWarning) {
|
|
175
|
-
this.sendAlert('heap-warning', 'High heap memory utilization', {
|
|
176
|
-
utilization: metrics.memory.heapUtilization,
|
|
177
|
-
threshold: this.thresholds.heapUtilizationWarning,
|
|
178
|
-
heapUsed: metrics.memory.heapUsed,
|
|
179
|
-
heapTotal: metrics.memory.heapTotal
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
if (metrics.connections.total >= this.thresholds.connectionCountCritical) {
|
|
183
|
-
this.sendAlert('connections-critical', 'Critical number of connections', {
|
|
184
|
-
connectionCount: metrics.connections.total,
|
|
185
|
-
threshold: this.thresholds.connectionCountCritical,
|
|
186
|
-
healthyConnections: metrics.connections.healthy,
|
|
187
|
-
totalClientConnections: metrics.connections.totalClientConnections
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
else if (metrics.connections.total >= this.thresholds.connectionCountWarning) {
|
|
191
|
-
this.sendAlert('connections-warning', 'High number of connections', {
|
|
192
|
-
connectionCount: metrics.connections.total,
|
|
193
|
-
threshold: this.thresholds.connectionCountWarning,
|
|
194
|
-
healthyConnections: metrics.connections.healthy,
|
|
195
|
-
totalClientConnections: metrics.connections.totalClientConnections
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
const totalMessages = metrics.messages.totalConsoleMessages + metrics.messages.totalNetworkRequests;
|
|
199
|
-
if (totalMessages >= this.thresholds.messageCountCritical) {
|
|
200
|
-
this.sendAlert('messages-critical', 'Critical number of stored messages', {
|
|
201
|
-
totalMessages,
|
|
202
|
-
threshold: this.thresholds.messageCountCritical,
|
|
203
|
-
consoleMessages: metrics.messages.totalConsoleMessages,
|
|
204
|
-
networkRequests: metrics.messages.totalNetworkRequests
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
else if (totalMessages >= this.thresholds.messageCountWarning) {
|
|
208
|
-
this.sendAlert('messages-warning', 'High number of stored messages', {
|
|
209
|
-
totalMessages,
|
|
210
|
-
threshold: this.thresholds.messageCountWarning,
|
|
211
|
-
consoleMessages: metrics.messages.totalConsoleMessages,
|
|
212
|
-
networkRequests: metrics.messages.totalNetworkRequests
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
sendAlert(alertType, message, data) {
|
|
217
|
-
const now = Date.now();
|
|
218
|
-
const lastAlert = this.lastAlertTimes.get(alertType);
|
|
219
|
-
if (!lastAlert || (now - lastAlert) >= this.alertCooldownMs) {
|
|
220
|
-
this.logger.warn(`[PERFORMANCE ALERT] ${message}`, data);
|
|
221
|
-
this.lastAlertTimes.set(alertType, now);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
getCurrentMetrics() {
|
|
225
|
-
return this.metricsHistory.length > 0
|
|
226
|
-
? this.metricsHistory[this.metricsHistory.length - 1]
|
|
227
|
-
: null;
|
|
228
|
-
}
|
|
229
|
-
getMetricsHistory(count) {
|
|
230
|
-
if (count && count < this.metricsHistory.length) {
|
|
231
|
-
return this.metricsHistory.slice(-count);
|
|
232
|
-
}
|
|
233
|
-
return [...this.metricsHistory];
|
|
234
|
-
}
|
|
235
|
-
getPerformanceSummary(periodMs = 3600000) {
|
|
236
|
-
const now = Date.now();
|
|
237
|
-
const cutoff = now - periodMs;
|
|
238
|
-
const recentMetrics = this.metricsHistory.filter(m => m.timestamp >= cutoff);
|
|
239
|
-
if (recentMetrics.length === 0) {
|
|
240
|
-
return {
|
|
241
|
-
averageMemoryUtilization: 0,
|
|
242
|
-
averageHeapUtilization: 0,
|
|
243
|
-
averageConnectionCount: 0,
|
|
244
|
-
averageMessageCount: 0,
|
|
245
|
-
peakMemoryUtilization: 0,
|
|
246
|
-
peakConnectionCount: 0,
|
|
247
|
-
alertCount: 0
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
const avgMemoryUtilization = recentMetrics.reduce((sum, m) => sum + m.system.memoryUtilization, 0) / recentMetrics.length;
|
|
251
|
-
const avgHeapUtilization = recentMetrics.reduce((sum, m) => sum + m.memory.heapUtilization, 0) / recentMetrics.length;
|
|
252
|
-
const avgConnectionCount = recentMetrics.reduce((sum, m) => sum + m.connections.total, 0) / recentMetrics.length;
|
|
253
|
-
const avgMessageCount = recentMetrics.reduce((sum, m) => sum + m.messages.totalConsoleMessages + m.messages.totalNetworkRequests, 0) / recentMetrics.length;
|
|
254
|
-
const peakMemoryUtilization = Math.max(...recentMetrics.map(m => m.system.memoryUtilization));
|
|
255
|
-
const peakConnectionCount = Math.max(...recentMetrics.map(m => m.connections.total));
|
|
256
|
-
const alertCount = Math.floor(periodMs / this.alertCooldownMs) * this.lastAlertTimes.size;
|
|
257
|
-
return {
|
|
258
|
-
averageMemoryUtilization: avgMemoryUtilization,
|
|
259
|
-
averageHeapUtilization: avgHeapUtilization,
|
|
260
|
-
averageConnectionCount: avgConnectionCount,
|
|
261
|
-
averageMessageCount: avgMessageCount,
|
|
262
|
-
peakMemoryUtilization,
|
|
263
|
-
peakConnectionCount,
|
|
264
|
-
alertCount
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
updateThresholds(newThresholds) {
|
|
268
|
-
this.thresholds = { ...this.thresholds, ...newThresholds };
|
|
269
|
-
this.logger.info('Performance thresholds updated', { thresholds: this.thresholds });
|
|
270
|
-
}
|
|
271
|
-
clearHistory() {
|
|
272
|
-
this.metricsHistory = [];
|
|
273
|
-
this.lastAlertTimes.clear();
|
|
274
|
-
this.logger.info('Performance metrics history cleared');
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
exports.PerformanceMonitor = PerformanceMonitor;
|