From 753b03d3e9eec309696a527b23568b4a1a1004b2 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Mon, 23 Jun 2025 08:50:19 +0000 Subject: [PATCH] fix(metrics): fix metrics --- ts/proxies/smart-proxy/metrics-collector.ts | 75 ++++++++++++------- .../smart-proxy/models/metrics-types.ts | 6 ++ 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/ts/proxies/smart-proxy/metrics-collector.ts b/ts/proxies/smart-proxy/metrics-collector.ts index 87b7b28..223d002 100644 --- a/ts/proxies/smart-proxy/metrics-collector.ts +++ b/ts/proxies/smart-proxy/metrics-collector.ts @@ -124,24 +124,35 @@ export class MetricsCollector implements IMetrics { const now = Date.now(); const windowStart = now - (windowSeconds * 1000); - // Aggregate bytes by route from trackers - const routeBytes = new Map(); + // Aggregate bytes by route with proper time calculation + const routeData = new Map(); for (const [_, tracker] of this.connectionByteTrackers) { - if (tracker.lastUpdate > windowStart) { - const current = routeBytes.get(tracker.routeName) || { in: 0, out: 0 }; - current.in += tracker.bytesIn; - current.out += tracker.bytesOut; - routeBytes.set(tracker.routeName, current); + // Only include connections that were active within the window + if (tracker.lastUpdate > windowStart || tracker.startTime > windowStart) { + // Calculate the actual duration this connection was active within the window + const connectionStart = Math.max(tracker.startTime, windowStart); + const connectionEnd = tracker.lastUpdate; + const durationInWindow = (connectionEnd - connectionStart) / 1000; // Convert to seconds + + if (durationInWindow > 0) { + const current = routeData.get(tracker.routeName) || { bytesIn: 0, bytesOut: 0, totalDuration: 0 }; + current.bytesIn += tracker.bytesIn; + current.bytesOut += tracker.bytesOut; + current.totalDuration += durationInWindow; + routeData.set(tracker.routeName, current); + } } } - // Convert to rates - for (const [route, bytes] of routeBytes) { - routeThroughput.set(route, { - in: Math.round(bytes.in / windowSeconds), - out: Math.round(bytes.out / windowSeconds) - }); + // Convert to rates (bytes per second) + for (const [route, data] of routeData) { + if (data.totalDuration > 0) { + routeThroughput.set(route, { + in: Math.round(data.bytesIn / data.totalDuration), + out: Math.round(data.bytesOut / data.totalDuration) + }); + } } return routeThroughput; @@ -152,24 +163,35 @@ export class MetricsCollector implements IMetrics { const now = Date.now(); const windowStart = now - (windowSeconds * 1000); - // Aggregate bytes by IP from trackers - const ipBytes = new Map(); + // Aggregate bytes by IP with proper time calculation + const ipData = new Map(); for (const [_, tracker] of this.connectionByteTrackers) { - if (tracker.lastUpdate > windowStart) { - const current = ipBytes.get(tracker.remoteIP) || { in: 0, out: 0 }; - current.in += tracker.bytesIn; - current.out += tracker.bytesOut; - ipBytes.set(tracker.remoteIP, current); + // Only include connections that were active within the window + if (tracker.lastUpdate > windowStart || tracker.startTime > windowStart) { + // Calculate the actual duration this connection was active within the window + const connectionStart = Math.max(tracker.startTime, windowStart); + const connectionEnd = tracker.lastUpdate; + const durationInWindow = (connectionEnd - connectionStart) / 1000; // Convert to seconds + + if (durationInWindow > 0) { + const current = ipData.get(tracker.remoteIP) || { bytesIn: 0, bytesOut: 0, totalDuration: 0 }; + current.bytesIn += tracker.bytesIn; + current.bytesOut += tracker.bytesOut; + current.totalDuration += durationInWindow; + ipData.set(tracker.remoteIP, current); + } } } - // Convert to rates - for (const [ip, bytes] of ipBytes) { - ipThroughput.set(ip, { - in: Math.round(bytes.in / windowSeconds), - out: Math.round(bytes.out / windowSeconds) - }); + // Convert to rates (bytes per second) + for (const [ip, data] of ipData) { + if (data.totalDuration > 0) { + ipThroughput.set(ip, { + in: Math.round(data.bytesIn / data.totalDuration), + out: Math.round(data.bytesOut / data.totalDuration) + }); + } } return ipThroughput; @@ -271,6 +293,7 @@ export class MetricsCollector implements IMetrics { remoteIP, bytesIn: 0, bytesOut: 0, + startTime: now, lastUpdate: now }); diff --git a/ts/proxies/smart-proxy/models/metrics-types.ts b/ts/proxies/smart-proxy/models/metrics-types.ts index bfc054a..278d59a 100644 --- a/ts/proxies/smart-proxy/models/metrics-types.ts +++ b/ts/proxies/smart-proxy/models/metrics-types.ts @@ -5,6 +5,11 @@ export interface IThroughputSample { timestamp: number; bytesIn: number; bytesOut: number; + tags?: { + route?: string; + ip?: string; + [key: string]: string | undefined; + }; } /** @@ -102,5 +107,6 @@ export interface IByteTracker { remoteIP: string; bytesIn: number; bytesOut: number; + startTime: number; lastUpdate: number; } \ No newline at end of file