chrome-cdp-cli 1.5.0 → 1.6.0

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.
@@ -0,0 +1,360 @@
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 = (0, logger_1.createLogger)({ component: 'MessageStore' });
12
+ }
13
+ addConsoleMessage(connectionId, message) {
14
+ this.logger.info(`[DEBUG] addConsoleMessage called for connection ${connectionId}, message type: ${message.type}, text: ${message.text.substring(0, 100)}`);
15
+ if (!this.consoleMessages.has(connectionId)) {
16
+ this.consoleMessages.set(connectionId, []);
17
+ this.logger.info(`[DEBUG] Created new message array for connection ${connectionId}`);
18
+ }
19
+ const messages = this.consoleMessages.get(connectionId);
20
+ messages.push(message);
21
+ this.logger.debug(`Added console message for connection ${connectionId}`, {
22
+ connectionId,
23
+ messageType: message.type,
24
+ messageText: message.text.substring(0, 100),
25
+ totalMessages: messages.length
26
+ });
27
+ if (messages.length > this.maxConsoleMessages) {
28
+ const removed = messages.splice(0, messages.length - this.maxConsoleMessages);
29
+ this.logger.logMemoryEvent('limit-reached', `Console message limit reached for connection ${connectionId}`, {
30
+ connectionCount: 1,
31
+ messageCount: messages.length,
32
+ messagesRemoved: removed.length,
33
+ maxLimit: this.maxConsoleMessages
34
+ });
35
+ }
36
+ this.logger.debug(`Console message stored successfully`, {
37
+ connectionId,
38
+ messageType: message.type,
39
+ source: message.source
40
+ });
41
+ }
42
+ getConsoleMessages(connectionId, filter) {
43
+ const messages = this.consoleMessages.get(connectionId) || [];
44
+ if (!filter) {
45
+ return [...messages];
46
+ }
47
+ let filteredMessages = [...messages];
48
+ if (filter.types && filter.types.length > 0) {
49
+ filteredMessages = filteredMessages.filter(msg => filter.types.includes(msg.type));
50
+ }
51
+ if (filter.textPattern) {
52
+ const pattern = new RegExp(filter.textPattern, 'i');
53
+ filteredMessages = filteredMessages.filter(msg => pattern.test(msg.text));
54
+ }
55
+ if (filter.source) {
56
+ filteredMessages = filteredMessages.filter(msg => msg.source === filter.source);
57
+ }
58
+ if (filter.startTime) {
59
+ filteredMessages = filteredMessages.filter(msg => msg.timestamp >= filter.startTime);
60
+ }
61
+ if (filter.endTime) {
62
+ filteredMessages = filteredMessages.filter(msg => msg.timestamp <= filter.endTime);
63
+ }
64
+ if (filter.maxMessages && filter.maxMessages > 0) {
65
+ filteredMessages = filteredMessages.slice(-filter.maxMessages);
66
+ }
67
+ return filteredMessages;
68
+ }
69
+ getLatestConsoleMessage(connectionId, filter) {
70
+ const messages = this.getConsoleMessages(connectionId, filter);
71
+ return messages.length > 0 ? messages[messages.length - 1] : null;
72
+ }
73
+ clearConsoleMessages(connectionId) {
74
+ this.consoleMessages.delete(connectionId);
75
+ this.logger.debug(`Cleared console messages for connection ${connectionId}`);
76
+ }
77
+ getConsoleMessageCount(connectionId, filter) {
78
+ return this.getConsoleMessages(connectionId, filter).length;
79
+ }
80
+ addNetworkRequest(connectionId, request) {
81
+ this.logger.info(`[DEBUG] addNetworkRequest called for connection ${connectionId}, method: ${request.method}, url: ${request.url.substring(0, 100)}`);
82
+ if (!this.networkRequests.has(connectionId)) {
83
+ this.networkRequests.set(connectionId, []);
84
+ this.logger.info(`[DEBUG] Created new network requests array for connection ${connectionId}`);
85
+ }
86
+ const requests = this.networkRequests.get(connectionId);
87
+ requests.push(request);
88
+ this.logger.debug(`Added network request for connection ${connectionId}`, {
89
+ connectionId,
90
+ method: request.method,
91
+ url: request.url.substring(0, 100),
92
+ totalRequests: requests.length
93
+ });
94
+ if (requests.length > this.maxNetworkRequests) {
95
+ const removed = requests.splice(0, requests.length - this.maxNetworkRequests);
96
+ this.logger.logMemoryEvent('limit-reached', `Network request limit reached for connection ${connectionId}`, {
97
+ connectionCount: 1,
98
+ requestCount: requests.length,
99
+ requestsRemoved: removed.length,
100
+ maxLimit: this.maxNetworkRequests
101
+ });
102
+ }
103
+ this.logger.debug(`Network request stored successfully`, {
104
+ connectionId,
105
+ requestId: request.requestId,
106
+ method: request.method
107
+ });
108
+ }
109
+ updateNetworkRequest(connectionId, requestId, update) {
110
+ const requests = this.networkRequests.get(connectionId);
111
+ if (!requests) {
112
+ return;
113
+ }
114
+ const request = requests.find(r => r.requestId === requestId);
115
+ if (request) {
116
+ Object.assign(request, update);
117
+ this.logger.debug(`Updated network request ${requestId} for connection ${connectionId}`);
118
+ }
119
+ }
120
+ getNetworkRequests(connectionId, filter) {
121
+ const requests = this.networkRequests.get(connectionId) || [];
122
+ if (!filter) {
123
+ return [...requests];
124
+ }
125
+ let filteredRequests = [...requests];
126
+ if (filter.methods && filter.methods.length > 0) {
127
+ filteredRequests = filteredRequests.filter(req => filter.methods.includes(req.method.toUpperCase()));
128
+ }
129
+ if (filter.statusCodes && filter.statusCodes.length > 0) {
130
+ filteredRequests = filteredRequests.filter(req => req.status && filter.statusCodes.includes(req.status));
131
+ }
132
+ if (filter.urlPattern) {
133
+ const pattern = new RegExp(filter.urlPattern, 'i');
134
+ filteredRequests = filteredRequests.filter(req => pattern.test(req.url));
135
+ }
136
+ if (filter.startTime) {
137
+ filteredRequests = filteredRequests.filter(req => req.timestamp >= filter.startTime);
138
+ }
139
+ if (filter.endTime) {
140
+ filteredRequests = filteredRequests.filter(req => req.timestamp <= filter.endTime);
141
+ }
142
+ if (!filter.includeResponseBody) {
143
+ filteredRequests = filteredRequests.map(req => ({
144
+ ...req,
145
+ responseBody: undefined
146
+ }));
147
+ }
148
+ if (filter.maxRequests && filter.maxRequests > 0) {
149
+ filteredRequests = filteredRequests.slice(-filter.maxRequests);
150
+ }
151
+ return filteredRequests;
152
+ }
153
+ getLatestNetworkRequest(connectionId, filter) {
154
+ const requests = this.getNetworkRequests(connectionId, filter);
155
+ return requests.length > 0 ? requests[requests.length - 1] : null;
156
+ }
157
+ clearNetworkRequests(connectionId) {
158
+ this.networkRequests.delete(connectionId);
159
+ this.logger.debug(`Cleared network requests for connection ${connectionId}`);
160
+ }
161
+ getNetworkRequestCount(connectionId, filter) {
162
+ return this.getNetworkRequests(connectionId, filter).length;
163
+ }
164
+ cleanupConnection(connectionId) {
165
+ this.clearConsoleMessages(connectionId);
166
+ this.clearNetworkRequests(connectionId);
167
+ this.logger.info(`Cleaned up all data for connection ${connectionId}`);
168
+ }
169
+ clearAll() {
170
+ this.consoleMessages.clear();
171
+ this.networkRequests.clear();
172
+ this.logger.info('Cleared all stored messages and requests');
173
+ }
174
+ enforceMemoryLimits() {
175
+ let totalConsoleMessages = 0;
176
+ let totalNetworkRequests = 0;
177
+ const connectionCount = Math.max(this.consoleMessages.size, this.networkRequests.size);
178
+ for (const messages of this.consoleMessages.values()) {
179
+ totalConsoleMessages += messages.length;
180
+ }
181
+ for (const requests of this.networkRequests.values()) {
182
+ totalNetworkRequests += requests.length;
183
+ }
184
+ this.logger.logMemoryEvent('cleanup', 'Memory usage check', {
185
+ memoryUsage: process.memoryUsage(),
186
+ connectionCount,
187
+ messageCount: totalConsoleMessages,
188
+ requestCount: totalNetworkRequests
189
+ });
190
+ if (totalConsoleMessages > this.maxConsoleMessages * 2) {
191
+ this.logger.logMemoryEvent('limit-reached', 'Global console message limit exceeded, cleaning up oldest messages', {
192
+ messageCount: totalConsoleMessages,
193
+ maxLimit: this.maxConsoleMessages * 2,
194
+ connectionCount
195
+ });
196
+ this.cleanupOldestConsoleMessages();
197
+ }
198
+ if (totalNetworkRequests > this.maxNetworkRequests * 2) {
199
+ this.logger.logMemoryEvent('limit-reached', 'Global network request limit exceeded, cleaning up oldest requests', {
200
+ requestCount: totalNetworkRequests,
201
+ maxLimit: this.maxNetworkRequests * 2,
202
+ connectionCount
203
+ });
204
+ this.cleanupOldestNetworkRequests();
205
+ }
206
+ }
207
+ getStorageStats() {
208
+ const stats = {
209
+ connections: 0,
210
+ totalConsoleMessages: 0,
211
+ totalNetworkRequests: 0,
212
+ consoleMessagesByConnection: {},
213
+ networkRequestsByConnection: {}
214
+ };
215
+ const connectionIds = new Set([
216
+ ...this.consoleMessages.keys(),
217
+ ...this.networkRequests.keys()
218
+ ]);
219
+ stats.connections = connectionIds.size;
220
+ for (const connectionId of connectionIds) {
221
+ const consoleCount = this.consoleMessages.get(connectionId)?.length || 0;
222
+ const networkCount = this.networkRequests.get(connectionId)?.length || 0;
223
+ stats.consoleMessagesByConnection[connectionId] = consoleCount;
224
+ stats.networkRequestsByConnection[connectionId] = networkCount;
225
+ stats.totalConsoleMessages += consoleCount;
226
+ stats.totalNetworkRequests += networkCount;
227
+ }
228
+ return stats;
229
+ }
230
+ processConsoleAPIEvent(connectionId, params) {
231
+ try {
232
+ this.logger.info(`[DEBUG] processConsoleAPIEvent called for connection ${connectionId}, type: ${params.type}`);
233
+ const message = {
234
+ connectionId,
235
+ type: this.mapConsoleType(params.type),
236
+ text: this.formatConsoleArgs(params.args || []),
237
+ args: (params.args || []).map((arg) => arg.value || arg.description || ''),
238
+ timestamp: params.timestamp || Date.now(),
239
+ stackTrace: params.stackTrace ? this.convertStackTrace(params.stackTrace.callFrames) : undefined,
240
+ source: 'Runtime.consoleAPICalled'
241
+ };
242
+ this.logger.info(`[DEBUG] Created console message: ${JSON.stringify(message).substring(0, 200)}`);
243
+ this.addConsoleMessage(connectionId, message);
244
+ this.logger.info(`[DEBUG] Console message added to store for connection ${connectionId}`);
245
+ }
246
+ catch (error) {
247
+ this.logger.error('[DEBUG] Error processing console API event:', error);
248
+ }
249
+ }
250
+ processLogEntryEvent(connectionId, params) {
251
+ try {
252
+ const entry = params.entry;
253
+ const message = {
254
+ connectionId,
255
+ type: this.mapLogLevel(entry.level),
256
+ text: entry.text || '',
257
+ args: [entry.text || ''],
258
+ timestamp: entry.timestamp || Date.now(),
259
+ stackTrace: entry.url && entry.lineNumber ? [{
260
+ functionName: '<unknown>',
261
+ url: entry.url,
262
+ lineNumber: entry.lineNumber,
263
+ columnNumber: 0
264
+ }] : undefined,
265
+ source: 'Log.entryAdded'
266
+ };
267
+ this.addConsoleMessage(connectionId, message);
268
+ }
269
+ catch (error) {
270
+ this.logger.error('Error processing log entry event:', error);
271
+ }
272
+ }
273
+ mapConsoleType(cdpType) {
274
+ switch (cdpType) {
275
+ case 'log': return 'log';
276
+ case 'info': return 'info';
277
+ case 'warning': return 'warn';
278
+ case 'error': return 'error';
279
+ case 'debug': return 'debug';
280
+ default: return 'log';
281
+ }
282
+ }
283
+ mapLogLevel(logLevel) {
284
+ switch (logLevel.toLowerCase()) {
285
+ case 'verbose':
286
+ case 'info': return 'info';
287
+ case 'warning': return 'warn';
288
+ case 'error': return 'error';
289
+ default: return 'log';
290
+ }
291
+ }
292
+ formatConsoleArgs(args) {
293
+ return args.map(arg => {
294
+ if (arg.value !== undefined) {
295
+ if (typeof arg.value === 'string') {
296
+ return arg.value;
297
+ }
298
+ return JSON.stringify(arg.value);
299
+ }
300
+ return arg.description || '';
301
+ }).join(' ');
302
+ }
303
+ convertStackTrace(callFrames) {
304
+ return callFrames.map(frame => ({
305
+ functionName: frame.functionName || '<anonymous>',
306
+ url: frame.url,
307
+ lineNumber: frame.lineNumber,
308
+ columnNumber: frame.columnNumber
309
+ }));
310
+ }
311
+ cleanupOldestConsoleMessages() {
312
+ let maxMessages = 0;
313
+ let connectionToCleanup = '';
314
+ for (const [connectionId, messages] of this.consoleMessages) {
315
+ if (messages.length > maxMessages) {
316
+ maxMessages = messages.length;
317
+ connectionToCleanup = connectionId;
318
+ }
319
+ }
320
+ if (connectionToCleanup) {
321
+ const messages = this.consoleMessages.get(connectionToCleanup);
322
+ const toRemove = Math.floor(messages.length * 0.2);
323
+ const beforeCount = messages.length;
324
+ messages.splice(0, toRemove);
325
+ this.logger.logMemoryEvent('cleanup', `Cleaned up old console messages from connection with highest usage`, {
326
+ connectionCount: 1,
327
+ messageCount: messages.length,
328
+ messagesRemoved: toRemove,
329
+ connectionId: connectionToCleanup,
330
+ beforeCount,
331
+ afterCount: messages.length
332
+ });
333
+ }
334
+ }
335
+ cleanupOldestNetworkRequests() {
336
+ let maxRequests = 0;
337
+ let connectionToCleanup = '';
338
+ for (const [connectionId, requests] of this.networkRequests) {
339
+ if (requests.length > maxRequests) {
340
+ maxRequests = requests.length;
341
+ connectionToCleanup = connectionId;
342
+ }
343
+ }
344
+ if (connectionToCleanup) {
345
+ const requests = this.networkRequests.get(connectionToCleanup);
346
+ const toRemove = Math.floor(requests.length * 0.2);
347
+ const beforeCount = requests.length;
348
+ requests.splice(0, toRemove);
349
+ this.logger.logMemoryEvent('cleanup', `Cleaned up old network requests from connection with highest usage`, {
350
+ connectionCount: 1,
351
+ requestCount: requests.length,
352
+ requestsRemoved: toRemove,
353
+ connectionId: connectionToCleanup,
354
+ beforeCount,
355
+ afterCount: requests.length
356
+ });
357
+ }
358
+ }
359
+ }
360
+ exports.MessageStore = MessageStore;
@@ -0,0 +1,277 @@
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;