@push.rocks/smartproxy 19.6.2 → 19.6.7
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_ts/proxies/smart-proxy/connection-manager.d.ts +4 -7
- package/dist_ts/proxies/smart-proxy/connection-manager.js +22 -22
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.d.ts +4 -3
- package/dist_ts/proxies/smart-proxy/http-proxy-bridge.js +9 -9
- package/dist_ts/proxies/smart-proxy/metrics-collector.d.ts +68 -56
- package/dist_ts/proxies/smart-proxy/metrics-collector.js +226 -176
- package/dist_ts/proxies/smart-proxy/models/interfaces.d.ts +5 -0
- package/dist_ts/proxies/smart-proxy/models/metrics-types.d.ts +94 -48
- package/dist_ts/proxies/smart-proxy/nftables-manager.d.ts +4 -4
- package/dist_ts/proxies/smart-proxy/nftables-manager.js +6 -6
- package/dist_ts/proxies/smart-proxy/port-manager.d.ts +4 -7
- package/dist_ts/proxies/smart-proxy/port-manager.js +6 -9
- package/dist_ts/proxies/smart-proxy/route-connection-handler.d.ts +4 -15
- package/dist_ts/proxies/smart-proxy/route-connection-handler.js +128 -128
- package/dist_ts/proxies/smart-proxy/security-manager.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/security-manager.js +9 -9
- package/dist_ts/proxies/smart-proxy/smart-proxy.d.ts +20 -13
- package/dist_ts/proxies/smart-proxy/smart-proxy.js +16 -13
- package/dist_ts/proxies/smart-proxy/throughput-tracker.d.ts +36 -0
- package/dist_ts/proxies/smart-proxy/throughput-tracker.js +117 -0
- package/dist_ts/proxies/smart-proxy/timeout-manager.d.ts +4 -3
- package/dist_ts/proxies/smart-proxy/timeout-manager.js +16 -16
- package/dist_ts/proxies/smart-proxy/tls-manager.d.ts +3 -3
- package/dist_ts/proxies/smart-proxy/tls-manager.js +12 -12
- package/package.json +8 -17
- package/readme.hints.md +0 -897
- package/readme.md +960 -54
- package/readme.plan.md +301 -562
- package/ts/proxies/smart-proxy/connection-manager.ts +23 -21
- package/ts/proxies/smart-proxy/http-proxy-bridge.ts +9 -8
- package/ts/proxies/smart-proxy/metrics-collector.ts +277 -189
- package/ts/proxies/smart-proxy/models/interfaces.ts +7 -0
- package/ts/proxies/smart-proxy/models/metrics-types.ts +93 -41
- package/ts/proxies/smart-proxy/nftables-manager.ts +5 -5
- package/ts/proxies/smart-proxy/port-manager.ts +6 -14
- package/ts/proxies/smart-proxy/route-connection-handler.ts +136 -136
- package/ts/proxies/smart-proxy/security-manager.ts +8 -8
- package/ts/proxies/smart-proxy/smart-proxy.ts +26 -35
- package/ts/proxies/smart-proxy/throughput-tracker.ts +144 -0
- package/ts/proxies/smart-proxy/timeout-manager.ts +16 -15
- package/ts/proxies/smart-proxy/tls-manager.ts +11 -11
- package/readme.connections.md +0 -724
- package/readme.delete.md +0 -187
- package/readme.memory-leaks-fixed.md +0 -45
- package/readme.metrics.md +0 -591
- package/readme.monitoring.md +0 -202
- package/readme.proxy-chain-summary.md +0 -112
- package/readme.proxy-protocol-example.md +0 -462
- package/readme.proxy-protocol.md +0 -415
- package/readme.routing.md +0 -341
- package/readme.websocket-keepalive-config.md +0 -140
- package/readme.websocket-keepalive-fix.md +0 -63
package/readme.metrics.md
DELETED
|
@@ -1,591 +0,0 @@
|
|
|
1
|
-
# SmartProxy Metrics Implementation Plan
|
|
2
|
-
|
|
3
|
-
This document outlines the plan for implementing comprehensive metrics tracking in SmartProxy.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The metrics system will provide real-time insights into proxy performance, connection statistics, and throughput data. The implementation will be efficient, thread-safe, and have minimal impact on proxy performance.
|
|
8
|
-
|
|
9
|
-
**Key Design Decisions**:
|
|
10
|
-
|
|
11
|
-
1. **On-demand computation**: Instead of maintaining duplicate state, the MetricsCollector computes metrics on-demand from existing data structures.
|
|
12
|
-
|
|
13
|
-
2. **SmartProxy-centric architecture**: MetricsCollector receives the SmartProxy instance, providing access to all components:
|
|
14
|
-
- ConnectionManager for connection data
|
|
15
|
-
- RouteManager for route metadata
|
|
16
|
-
- Settings for configuration
|
|
17
|
-
- Future components without API changes
|
|
18
|
-
|
|
19
|
-
This approach:
|
|
20
|
-
- Eliminates synchronization issues
|
|
21
|
-
- Reduces memory overhead
|
|
22
|
-
- Simplifies the implementation
|
|
23
|
-
- Guarantees metrics accuracy
|
|
24
|
-
- Leverages existing battle-tested components
|
|
25
|
-
- Provides flexibility for future enhancements
|
|
26
|
-
|
|
27
|
-
## Metrics Interface
|
|
28
|
-
|
|
29
|
-
```typescript
|
|
30
|
-
interface IProxyStats {
|
|
31
|
-
getActiveConnections(): number;
|
|
32
|
-
getConnectionsByRoute(): Map<string, number>;
|
|
33
|
-
getConnectionsByIP(): Map<string, number>;
|
|
34
|
-
getTotalConnections(): number;
|
|
35
|
-
getRequestsPerSecond(): number;
|
|
36
|
-
getThroughput(): { bytesIn: number, bytesOut: number };
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## Implementation Plan
|
|
41
|
-
|
|
42
|
-
### 1. Create MetricsCollector Class
|
|
43
|
-
|
|
44
|
-
**Location**: `/ts/proxies/smart-proxy/metrics-collector.ts`
|
|
45
|
-
|
|
46
|
-
```typescript
|
|
47
|
-
import type { SmartProxy } from './smart-proxy.js';
|
|
48
|
-
|
|
49
|
-
export class MetricsCollector implements IProxyStats {
|
|
50
|
-
constructor(
|
|
51
|
-
private smartProxy: SmartProxy
|
|
52
|
-
) {}
|
|
53
|
-
|
|
54
|
-
// RPS tracking (the only state we need to maintain)
|
|
55
|
-
private requestTimestamps: number[] = [];
|
|
56
|
-
private readonly RPS_WINDOW_SIZE = 60000; // 1 minute window
|
|
57
|
-
|
|
58
|
-
// All other metrics are computed on-demand from SmartProxy's components
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
### 2. Integration Points
|
|
63
|
-
|
|
64
|
-
Since metrics are computed on-demand from ConnectionManager's records, we only need minimal integration:
|
|
65
|
-
|
|
66
|
-
#### A. Request Tracking for RPS
|
|
67
|
-
|
|
68
|
-
**File**: `/ts/proxies/smart-proxy/route-connection-handler.ts`
|
|
69
|
-
|
|
70
|
-
```typescript
|
|
71
|
-
// In handleNewConnection when a new connection is accepted
|
|
72
|
-
this.metricsCollector.recordRequest();
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
#### B. SmartProxy Component Access
|
|
76
|
-
|
|
77
|
-
Through the SmartProxy instance, MetricsCollector can access:
|
|
78
|
-
- `smartProxy.connectionManager` - All active connections and their details
|
|
79
|
-
- `smartProxy.routeManager` - Route configurations and metadata
|
|
80
|
-
- `smartProxy.settings` - Configuration for thresholds and limits
|
|
81
|
-
- `smartProxy.servers` - Server instances and port information
|
|
82
|
-
- Any other components as needed for future metrics
|
|
83
|
-
|
|
84
|
-
No additional hooks needed!
|
|
85
|
-
|
|
86
|
-
### 3. Metric Implementations
|
|
87
|
-
|
|
88
|
-
#### A. Active Connections
|
|
89
|
-
|
|
90
|
-
```typescript
|
|
91
|
-
getActiveConnections(): number {
|
|
92
|
-
return this.smartProxy.connectionManager.getConnectionCount();
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
#### B. Connections by Route
|
|
97
|
-
|
|
98
|
-
```typescript
|
|
99
|
-
getConnectionsByRoute(): Map<string, number> {
|
|
100
|
-
const routeCounts = new Map<string, number>();
|
|
101
|
-
|
|
102
|
-
// Compute from active connections
|
|
103
|
-
for (const [_, record] of this.smartProxy.connectionManager.getConnections()) {
|
|
104
|
-
const routeName = record.routeName || 'unknown';
|
|
105
|
-
const current = routeCounts.get(routeName) || 0;
|
|
106
|
-
routeCounts.set(routeName, current + 1);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return routeCounts;
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
#### C. Connections by IP
|
|
114
|
-
|
|
115
|
-
```typescript
|
|
116
|
-
getConnectionsByIP(): Map<string, number> {
|
|
117
|
-
const ipCounts = new Map<string, number>();
|
|
118
|
-
|
|
119
|
-
// Compute from active connections
|
|
120
|
-
for (const [_, record] of this.smartProxy.connectionManager.getConnections()) {
|
|
121
|
-
const ip = record.remoteIP;
|
|
122
|
-
const current = ipCounts.get(ip) || 0;
|
|
123
|
-
ipCounts.set(ip, current + 1);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return ipCounts;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Additional helper methods for IP tracking
|
|
130
|
-
getTopIPs(limit: number = 10): Array<{ip: string, connections: number}> {
|
|
131
|
-
const ipCounts = this.getConnectionsByIP();
|
|
132
|
-
const sorted = Array.from(ipCounts.entries())
|
|
133
|
-
.sort((a, b) => b[1] - a[1])
|
|
134
|
-
.slice(0, limit)
|
|
135
|
-
.map(([ip, connections]) => ({ ip, connections }));
|
|
136
|
-
|
|
137
|
-
return sorted;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
isIPBlocked(ip: string, maxConnectionsPerIP: number): boolean {
|
|
141
|
-
const ipCounts = this.getConnectionsByIP();
|
|
142
|
-
const currentConnections = ipCounts.get(ip) || 0;
|
|
143
|
-
return currentConnections >= maxConnectionsPerIP;
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
#### D. Total Connections
|
|
148
|
-
|
|
149
|
-
```typescript
|
|
150
|
-
getTotalConnections(): number {
|
|
151
|
-
// Get from termination stats
|
|
152
|
-
const stats = this.smartProxy.connectionManager.getTerminationStats();
|
|
153
|
-
let total = this.smartProxy.connectionManager.getConnectionCount(); // Add active connections
|
|
154
|
-
|
|
155
|
-
// Add all terminated connections
|
|
156
|
-
for (const reason in stats.incoming) {
|
|
157
|
-
total += stats.incoming[reason];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return total;
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
#### E. Requests Per Second
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
getRequestsPerSecond(): number {
|
|
168
|
-
const now = Date.now();
|
|
169
|
-
const windowStart = now - this.RPS_WINDOW_SIZE;
|
|
170
|
-
|
|
171
|
-
// Clean old timestamps
|
|
172
|
-
this.requestTimestamps = this.requestTimestamps.filter(ts => ts > windowStart);
|
|
173
|
-
|
|
174
|
-
// Calculate RPS based on window
|
|
175
|
-
const requestsInWindow = this.requestTimestamps.length;
|
|
176
|
-
return requestsInWindow / (this.RPS_WINDOW_SIZE / 1000);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
recordRequest(): void {
|
|
180
|
-
this.requestTimestamps.push(Date.now());
|
|
181
|
-
|
|
182
|
-
// Prevent unbounded growth
|
|
183
|
-
if (this.requestTimestamps.length > 10000) {
|
|
184
|
-
this.cleanupOldRequests();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
#### F. Throughput Tracking
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
getThroughput(): { bytesIn: number, bytesOut: number } {
|
|
193
|
-
let bytesIn = 0;
|
|
194
|
-
let bytesOut = 0;
|
|
195
|
-
|
|
196
|
-
// Sum bytes from all active connections
|
|
197
|
-
for (const [_, record] of this.smartProxy.connectionManager.getConnections()) {
|
|
198
|
-
bytesIn += record.bytesReceived;
|
|
199
|
-
bytesOut += record.bytesSent;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return { bytesIn, bytesOut };
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Get throughput rate (bytes per second) for last minute
|
|
206
|
-
getThroughputRate(): { bytesInPerSec: number, bytesOutPerSec: number } {
|
|
207
|
-
const now = Date.now();
|
|
208
|
-
let recentBytesIn = 0;
|
|
209
|
-
let recentBytesOut = 0;
|
|
210
|
-
let connectionCount = 0;
|
|
211
|
-
|
|
212
|
-
// Calculate bytes transferred in last minute from active connections
|
|
213
|
-
for (const [_, record] of this.smartProxy.connectionManager.getConnections()) {
|
|
214
|
-
const connectionAge = now - record.incomingStartTime;
|
|
215
|
-
if (connectionAge < 60000) { // Connection started within last minute
|
|
216
|
-
recentBytesIn += record.bytesReceived;
|
|
217
|
-
recentBytesOut += record.bytesSent;
|
|
218
|
-
connectionCount++;
|
|
219
|
-
} else {
|
|
220
|
-
// For older connections, estimate rate based on average
|
|
221
|
-
const rate = connectionAge / 60000;
|
|
222
|
-
recentBytesIn += record.bytesReceived / rate;
|
|
223
|
-
recentBytesOut += record.bytesSent / rate;
|
|
224
|
-
connectionCount++;
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return {
|
|
229
|
-
bytesInPerSec: Math.round(recentBytesIn / 60),
|
|
230
|
-
bytesOutPerSec: Math.round(recentBytesOut / 60)
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### 4. Performance Optimizations
|
|
236
|
-
|
|
237
|
-
Since metrics are computed on-demand from existing data structures, performance optimizations are minimal:
|
|
238
|
-
|
|
239
|
-
#### A. Caching for Frequent Queries
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
private cachedMetrics: {
|
|
243
|
-
timestamp: number;
|
|
244
|
-
connectionsByRoute?: Map<string, number>;
|
|
245
|
-
connectionsByIP?: Map<string, number>;
|
|
246
|
-
} = { timestamp: 0 };
|
|
247
|
-
|
|
248
|
-
private readonly CACHE_TTL = 1000; // 1 second cache
|
|
249
|
-
|
|
250
|
-
getConnectionsByRoute(): Map<string, number> {
|
|
251
|
-
const now = Date.now();
|
|
252
|
-
|
|
253
|
-
// Return cached value if fresh
|
|
254
|
-
if (this.cachedMetrics.connectionsByRoute &&
|
|
255
|
-
now - this.cachedMetrics.timestamp < this.CACHE_TTL) {
|
|
256
|
-
return this.cachedMetrics.connectionsByRoute;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Compute fresh value
|
|
260
|
-
const routeCounts = new Map<string, number>();
|
|
261
|
-
for (const [_, record] of this.smartProxy.connectionManager.getConnections()) {
|
|
262
|
-
const routeName = record.routeName || 'unknown';
|
|
263
|
-
const current = routeCounts.get(routeName) || 0;
|
|
264
|
-
routeCounts.set(routeName, current + 1);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
// Cache and return
|
|
268
|
-
this.cachedMetrics.connectionsByRoute = routeCounts;
|
|
269
|
-
this.cachedMetrics.timestamp = now;
|
|
270
|
-
return routeCounts;
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
#### B. RPS Cleanup
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
// Only cleanup needed is for RPS timestamps
|
|
278
|
-
private cleanupOldRequests(): void {
|
|
279
|
-
const cutoff = Date.now() - this.RPS_WINDOW_SIZE;
|
|
280
|
-
this.requestTimestamps = this.requestTimestamps.filter(ts => ts > cutoff);
|
|
281
|
-
}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
### 5. SmartProxy Integration
|
|
285
|
-
|
|
286
|
-
#### A. Add to SmartProxy Class
|
|
287
|
-
|
|
288
|
-
```typescript
|
|
289
|
-
export class SmartProxy {
|
|
290
|
-
private metricsCollector: MetricsCollector;
|
|
291
|
-
|
|
292
|
-
constructor(options: ISmartProxyOptions) {
|
|
293
|
-
// ... existing code ...
|
|
294
|
-
|
|
295
|
-
// Pass SmartProxy instance to MetricsCollector
|
|
296
|
-
this.metricsCollector = new MetricsCollector(this);
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Public API
|
|
300
|
-
public getStats(): IProxyStats {
|
|
301
|
-
return this.metricsCollector;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
#### B. Configuration Options
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
interface ISmartProxyOptions {
|
|
310
|
-
// ... existing options ...
|
|
311
|
-
|
|
312
|
-
metrics?: {
|
|
313
|
-
enabled?: boolean; // Default: true
|
|
314
|
-
rpsWindowSize?: number; // Default: 60000 (1 minute)
|
|
315
|
-
throughputWindowSize?: number; // Default: 60000 (1 minute)
|
|
316
|
-
cleanupInterval?: number; // Default: 60000 (1 minute)
|
|
317
|
-
};
|
|
318
|
-
}
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### 6. Advanced Metrics (Future Enhancement)
|
|
322
|
-
|
|
323
|
-
```typescript
|
|
324
|
-
interface IAdvancedProxyStats extends IProxyStats {
|
|
325
|
-
// Latency metrics
|
|
326
|
-
getAverageLatency(): number;
|
|
327
|
-
getLatencyPercentiles(): { p50: number, p95: number, p99: number };
|
|
328
|
-
|
|
329
|
-
// Error metrics
|
|
330
|
-
getErrorRate(): number;
|
|
331
|
-
getErrorsByType(): Map<string, number>;
|
|
332
|
-
|
|
333
|
-
// Route-specific metrics
|
|
334
|
-
getRouteMetrics(routeName: string): IRouteMetrics;
|
|
335
|
-
|
|
336
|
-
// Time-series data
|
|
337
|
-
getHistoricalMetrics(duration: number): IHistoricalMetrics;
|
|
338
|
-
|
|
339
|
-
// Server/Port metrics (leveraging SmartProxy access)
|
|
340
|
-
getPortUtilization(): Map<number, { connections: number, maxConnections: number }>;
|
|
341
|
-
getCertificateExpiry(): Map<string, Date>;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Example implementation showing SmartProxy component access
|
|
345
|
-
getPortUtilization(): Map<number, { connections: number, maxConnections: number }> {
|
|
346
|
-
const portStats = new Map();
|
|
347
|
-
|
|
348
|
-
// Access servers through SmartProxy
|
|
349
|
-
for (const [port, server] of this.smartProxy.servers) {
|
|
350
|
-
const connections = Array.from(this.smartProxy.connectionManager.getConnections())
|
|
351
|
-
.filter(([_, record]) => record.localPort === port).length;
|
|
352
|
-
|
|
353
|
-
// Access route configuration through SmartProxy
|
|
354
|
-
const routes = this.smartProxy.routeManager.getRoutesForPort(port);
|
|
355
|
-
const maxConnections = routes[0]?.advanced?.maxConnections ||
|
|
356
|
-
this.smartProxy.settings.defaults?.security?.maxConnections ||
|
|
357
|
-
10000;
|
|
358
|
-
|
|
359
|
-
portStats.set(port, { connections, maxConnections });
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return portStats;
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### 7. HTTP Metrics Endpoint (Optional)
|
|
367
|
-
|
|
368
|
-
```typescript
|
|
369
|
-
// Expose metrics via HTTP endpoint
|
|
370
|
-
class MetricsHttpHandler {
|
|
371
|
-
handleRequest(req: IncomingMessage, res: ServerResponse): void {
|
|
372
|
-
if (req.url === '/metrics') {
|
|
373
|
-
const stats = this.proxy.getStats();
|
|
374
|
-
|
|
375
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
376
|
-
res.end(JSON.stringify({
|
|
377
|
-
activeConnections: stats.getActiveConnections(),
|
|
378
|
-
totalConnections: stats.getTotalConnections(),
|
|
379
|
-
requestsPerSecond: stats.getRequestsPerSecond(),
|
|
380
|
-
throughput: stats.getThroughput(),
|
|
381
|
-
connectionsByRoute: Object.fromEntries(stats.getConnectionsByRoute()),
|
|
382
|
-
connectionsByIP: Object.fromEntries(stats.getConnectionsByIP()),
|
|
383
|
-
topIPs: stats.getTopIPs(20)
|
|
384
|
-
}));
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
### 8. Testing Strategy
|
|
391
|
-
|
|
392
|
-
The simplified design makes testing much easier since we can mock the ConnectionManager's data:
|
|
393
|
-
|
|
394
|
-
#### A. Unit Tests
|
|
395
|
-
|
|
396
|
-
```typescript
|
|
397
|
-
// test/test.metrics-collector.ts
|
|
398
|
-
tap.test('MetricsCollector computes metrics correctly', async () => {
|
|
399
|
-
// Mock ConnectionManager with test data
|
|
400
|
-
const mockConnectionManager = {
|
|
401
|
-
getConnectionCount: () => 2,
|
|
402
|
-
getConnections: () => new Map([
|
|
403
|
-
['conn1', { remoteIP: '192.168.1.1', routeName: 'api', bytesReceived: 1000, bytesSent: 500 }],
|
|
404
|
-
['conn2', { remoteIP: '192.168.1.1', routeName: 'web', bytesReceived: 2000, bytesSent: 1000 }]
|
|
405
|
-
]),
|
|
406
|
-
getTerminationStats: () => ({ incoming: { normal: 10, timeout: 2 } })
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
const collector = new MetricsCollector(mockConnectionManager as any);
|
|
410
|
-
|
|
411
|
-
expect(collector.getActiveConnections()).toEqual(2);
|
|
412
|
-
expect(collector.getConnectionsByIP().get('192.168.1.1')).toEqual(2);
|
|
413
|
-
expect(collector.getTotalConnections()).toEqual(14); // 2 active + 12 terminated
|
|
414
|
-
});
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
#### B. Integration Tests
|
|
418
|
-
|
|
419
|
-
```typescript
|
|
420
|
-
// test/test.metrics-integration.ts
|
|
421
|
-
tap.test('SmartProxy provides accurate metrics', async () => {
|
|
422
|
-
const proxy = new SmartProxy({ /* config */ });
|
|
423
|
-
await proxy.start();
|
|
424
|
-
|
|
425
|
-
// Create connections and verify metrics
|
|
426
|
-
const stats = proxy.getStats();
|
|
427
|
-
expect(stats.getActiveConnections()).toEqual(0);
|
|
428
|
-
});
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
#### C. Performance Tests
|
|
432
|
-
|
|
433
|
-
```typescript
|
|
434
|
-
// test/test.metrics-performance.ts
|
|
435
|
-
tap.test('Metrics collection has minimal performance impact', async () => {
|
|
436
|
-
// Measure proxy performance with and without metrics
|
|
437
|
-
// Ensure overhead is < 1%
|
|
438
|
-
});
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
### 9. Implementation Phases
|
|
442
|
-
|
|
443
|
-
#### Phase 1: Core Metrics (Days 1-2)
|
|
444
|
-
- [ ] Create MetricsCollector class
|
|
445
|
-
- [ ] Implement all metric methods (reading from ConnectionManager)
|
|
446
|
-
- [ ] Add RPS tracking
|
|
447
|
-
- [ ] Add to SmartProxy with getStats() method
|
|
448
|
-
|
|
449
|
-
#### Phase 2: Testing & Optimization (Days 3-4)
|
|
450
|
-
- [ ] Add comprehensive unit tests with mocked data
|
|
451
|
-
- [ ] Add integration tests with real proxy
|
|
452
|
-
- [ ] Implement caching for performance
|
|
453
|
-
- [ ] Add RPS cleanup mechanism
|
|
454
|
-
|
|
455
|
-
#### Phase 3: Advanced Features (Days 5-7)
|
|
456
|
-
- [ ] Add HTTP metrics endpoint
|
|
457
|
-
- [ ] Implement Prometheus export format
|
|
458
|
-
- [ ] Add IP-based rate limiting helpers
|
|
459
|
-
- [ ] Create monitoring dashboard example
|
|
460
|
-
|
|
461
|
-
**Note**: The simplified design reduces implementation time from 4 weeks to 1 week!
|
|
462
|
-
|
|
463
|
-
### 10. Usage Examples
|
|
464
|
-
|
|
465
|
-
```typescript
|
|
466
|
-
// Basic usage
|
|
467
|
-
const proxy = new SmartProxy({
|
|
468
|
-
routes: [...],
|
|
469
|
-
metrics: { enabled: true }
|
|
470
|
-
});
|
|
471
|
-
|
|
472
|
-
await proxy.start();
|
|
473
|
-
|
|
474
|
-
// Get metrics
|
|
475
|
-
const stats = proxy.getStats();
|
|
476
|
-
console.log(`Active connections: ${stats.getActiveConnections()}`);
|
|
477
|
-
console.log(`RPS: ${stats.getRequestsPerSecond()}`);
|
|
478
|
-
console.log(`Throughput: ${JSON.stringify(stats.getThroughput())}`);
|
|
479
|
-
|
|
480
|
-
// Monitor specific routes
|
|
481
|
-
const routeConnections = stats.getConnectionsByRoute();
|
|
482
|
-
for (const [route, count] of routeConnections) {
|
|
483
|
-
console.log(`Route ${route}: ${count} connections`);
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
// Monitor connections by IP
|
|
487
|
-
const ipConnections = stats.getConnectionsByIP();
|
|
488
|
-
for (const [ip, count] of ipConnections) {
|
|
489
|
-
console.log(`IP ${ip}: ${count} connections`);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// Get top IPs by connection count
|
|
493
|
-
const topIPs = stats.getTopIPs(10);
|
|
494
|
-
console.log('Top 10 IPs:', topIPs);
|
|
495
|
-
|
|
496
|
-
// Check if IP should be rate limited
|
|
497
|
-
if (stats.isIPBlocked('192.168.1.100', 100)) {
|
|
498
|
-
console.log('IP has too many connections');
|
|
499
|
-
}
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
### 11. Monitoring Integration
|
|
503
|
-
|
|
504
|
-
```typescript
|
|
505
|
-
// Export to monitoring systems
|
|
506
|
-
class PrometheusExporter {
|
|
507
|
-
export(stats: IProxyStats): string {
|
|
508
|
-
return `
|
|
509
|
-
# HELP smartproxy_active_connections Current number of active connections
|
|
510
|
-
# TYPE smartproxy_active_connections gauge
|
|
511
|
-
smartproxy_active_connections ${stats.getActiveConnections()}
|
|
512
|
-
|
|
513
|
-
# HELP smartproxy_total_connections Total connections since start
|
|
514
|
-
# TYPE smartproxy_total_connections counter
|
|
515
|
-
smartproxy_total_connections ${stats.getTotalConnections()}
|
|
516
|
-
|
|
517
|
-
# HELP smartproxy_requests_per_second Current requests per second
|
|
518
|
-
# TYPE smartproxy_requests_per_second gauge
|
|
519
|
-
smartproxy_requests_per_second ${stats.getRequestsPerSecond()}
|
|
520
|
-
`;
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
### 12. Documentation
|
|
526
|
-
|
|
527
|
-
- Add metrics section to main README
|
|
528
|
-
- Create metrics API documentation
|
|
529
|
-
- Add monitoring setup guide
|
|
530
|
-
- Provide dashboard configuration examples
|
|
531
|
-
|
|
532
|
-
## Success Criteria
|
|
533
|
-
|
|
534
|
-
1. **Performance**: Metrics collection adds < 1% overhead
|
|
535
|
-
2. **Accuracy**: All metrics are accurate within 1% margin
|
|
536
|
-
3. **Memory**: No memory leaks over 24-hour operation
|
|
537
|
-
4. **Thread Safety**: No race conditions under high load
|
|
538
|
-
5. **Usability**: Simple, intuitive API for accessing metrics
|
|
539
|
-
|
|
540
|
-
## Privacy and Security Considerations
|
|
541
|
-
|
|
542
|
-
### IP Address Tracking
|
|
543
|
-
|
|
544
|
-
1. **Privacy Compliance**:
|
|
545
|
-
- Consider GDPR and other privacy regulations when storing IP addresses
|
|
546
|
-
- Implement configurable IP anonymization (e.g., mask last octet)
|
|
547
|
-
- Add option to disable IP tracking entirely
|
|
548
|
-
|
|
549
|
-
2. **Security**:
|
|
550
|
-
- Use IP metrics for rate limiting and DDoS protection
|
|
551
|
-
- Implement automatic blocking for IPs exceeding connection limits
|
|
552
|
-
- Consider integration with IP reputation services
|
|
553
|
-
|
|
554
|
-
3. **Implementation Options**:
|
|
555
|
-
```typescript
|
|
556
|
-
interface IMetricsOptions {
|
|
557
|
-
trackIPs?: boolean; // Default: true
|
|
558
|
-
anonymizeIPs?: boolean; // Default: false
|
|
559
|
-
maxConnectionsPerIP?: number; // Default: 100
|
|
560
|
-
ipBlockDuration?: number; // Default: 3600000 (1 hour)
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
## Future Enhancements
|
|
565
|
-
|
|
566
|
-
1. **Distributed Metrics**: Aggregate metrics across multiple proxy instances
|
|
567
|
-
2. **Historical Storage**: Store metrics in time-series database
|
|
568
|
-
3. **Alerting**: Built-in alerting based on metric thresholds
|
|
569
|
-
4. **Custom Metrics**: Allow users to define custom metrics
|
|
570
|
-
5. **GraphQL API**: Provide GraphQL endpoint for flexible metric queries
|
|
571
|
-
6. **IP Analytics**:
|
|
572
|
-
- Geographic distribution of connections
|
|
573
|
-
- Automatic anomaly detection for IP patterns
|
|
574
|
-
- Integration with threat intelligence feeds
|
|
575
|
-
|
|
576
|
-
## Benefits of the Simplified Design
|
|
577
|
-
|
|
578
|
-
By using a SmartProxy-centric architecture with on-demand computation:
|
|
579
|
-
|
|
580
|
-
1. **Zero Synchronization Issues**: Metrics always reflect the true state
|
|
581
|
-
2. **Minimal Memory Overhead**: No duplicate data structures
|
|
582
|
-
3. **Simpler Implementation**: ~200 lines instead of ~1000 lines
|
|
583
|
-
4. **Easier Testing**: Can mock SmartProxy components
|
|
584
|
-
5. **Better Performance**: No overhead from state updates
|
|
585
|
-
6. **Guaranteed Accuracy**: Single source of truth
|
|
586
|
-
7. **Faster Development**: 1 week instead of 4 weeks
|
|
587
|
-
8. **Future Flexibility**: Access to all SmartProxy components without API changes
|
|
588
|
-
9. **Holistic Metrics**: Can correlate data across components (connections, routes, settings, certificates, etc.)
|
|
589
|
-
10. **Clean Architecture**: MetricsCollector is a true SmartProxy component, not an isolated module
|
|
590
|
-
|
|
591
|
-
This approach leverages the existing, well-tested SmartProxy infrastructure while providing a clean, simple metrics API that can grow with the proxy's capabilities.
|