fix(metrics): fix metrics

This commit is contained in:
Juergen Kunz
2025-06-23 13:07:30 +00:00
parent cc9e76fade
commit caa15e539e
3 changed files with 110 additions and 42 deletions

View File

@ -124,35 +124,49 @@ export class MetricsCollector implements IMetrics {
const now = Date.now();
const windowStart = now - (windowSeconds * 1000);
// Aggregate bytes by route with proper time calculation
const routeData = new Map<string, { bytesIn: number; bytesOut: number; totalDuration: number }>();
// Aggregate bytes by route - calculate actual bytes transferred in window
const routeData = new Map<string, { bytesIn: number; bytesOut: number }>();
for (const [_, tracker] of this.connectionByteTrackers) {
// 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 (tracker.lastUpdate > windowStart) {
let windowBytesIn = 0;
let windowBytesOut = 0;
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);
if (tracker.windowSnapshots && tracker.windowSnapshots.length > 0) {
// Find the earliest snapshot within or just before the window
let startSnapshot = { timestamp: tracker.startTime, bytesIn: 0, bytesOut: 0 };
for (const snapshot of tracker.windowSnapshots) {
if (snapshot.timestamp <= windowStart) {
startSnapshot = snapshot;
} else {
break;
}
}
// Calculate bytes transferred since window start
windowBytesIn = tracker.bytesIn - startSnapshot.bytesIn;
windowBytesOut = tracker.bytesOut - startSnapshot.bytesOut;
} else if (tracker.startTime > windowStart) {
// Connection started within window, use all its bytes
windowBytesIn = tracker.bytesIn;
windowBytesOut = tracker.bytesOut;
}
// Add to route totals
const current = routeData.get(tracker.routeName) || { bytesIn: 0, bytesOut: 0 };
current.bytesIn += windowBytesIn;
current.bytesOut += windowBytesOut;
routeData.set(tracker.routeName, current);
}
}
// 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)
});
}
routeThroughput.set(route, {
in: Math.round(data.bytesIn / windowSeconds),
out: Math.round(data.bytesOut / windowSeconds)
});
}
return routeThroughput;
@ -163,35 +177,49 @@ export class MetricsCollector implements IMetrics {
const now = Date.now();
const windowStart = now - (windowSeconds * 1000);
// Aggregate bytes by IP with proper time calculation
const ipData = new Map<string, { bytesIn: number; bytesOut: number; totalDuration: number }>();
// Aggregate bytes by IP - calculate actual bytes transferred in window
const ipData = new Map<string, { bytesIn: number; bytesOut: number }>();
for (const [_, tracker] of this.connectionByteTrackers) {
// 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 (tracker.lastUpdate > windowStart) {
let windowBytesIn = 0;
let windowBytesOut = 0;
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);
if (tracker.windowSnapshots && tracker.windowSnapshots.length > 0) {
// Find the earliest snapshot within or just before the window
let startSnapshot = { timestamp: tracker.startTime, bytesIn: 0, bytesOut: 0 };
for (const snapshot of tracker.windowSnapshots) {
if (snapshot.timestamp <= windowStart) {
startSnapshot = snapshot;
} else {
break;
}
}
// Calculate bytes transferred since window start
windowBytesIn = tracker.bytesIn - startSnapshot.bytesIn;
windowBytesOut = tracker.bytesOut - startSnapshot.bytesOut;
} else if (tracker.startTime > windowStart) {
// Connection started within window, use all its bytes
windowBytesIn = tracker.bytesIn;
windowBytesOut = tracker.bytesOut;
}
// Add to IP totals
const current = ipData.get(tracker.remoteIP) || { bytesIn: 0, bytesOut: 0 };
current.bytesIn += windowBytesIn;
current.bytesOut += windowBytesOut;
ipData.set(tracker.remoteIP, current);
}
}
// 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)
});
}
ipThroughput.set(ip, {
in: Math.round(data.bytesIn / windowSeconds),
out: Math.round(data.bytesOut / windowSeconds)
});
}
return ipThroughput;
@ -294,7 +322,8 @@ export class MetricsCollector implements IMetrics {
bytesIn: 0,
bytesOut: 0,
startTime: now,
lastUpdate: now
lastUpdate: now,
windowSnapshots: [] // Initialize empty snapshots array
});
// Cleanup old request timestamps
@ -323,6 +352,22 @@ export class MetricsCollector implements IMetrics {
tracker.bytesIn += bytesIn;
tracker.bytesOut += bytesOut;
tracker.lastUpdate = Date.now();
// Initialize snapshots array if not present
if (!tracker.windowSnapshots) {
tracker.windowSnapshots = [];
}
// Add current snapshot - we'll use these for accurate windowed calculations
tracker.windowSnapshots.push({
timestamp: Date.now(),
bytesIn: tracker.bytesIn,
bytesOut: tracker.bytesOut
});
// Keep only snapshots from last 5 minutes to prevent memory growth
const fiveMinutesAgo = Date.now() - 300000;
tracker.windowSnapshots = tracker.windowSnapshots.filter(s => s.timestamp > fiveMinutesAgo);
}
}