fix(metrics): fix metrics

This commit is contained in:
Juergen Kunz
2025-06-22 23:40:02 +00:00
parent 92fde9d0d7
commit d24e51117d
6 changed files with 545 additions and 127 deletions

View File

@ -43,15 +43,32 @@ export class OpsViewNetwork extends DeesElement {
private networkRequests: INetworkRequest[] = [];
@state()
private trafficData: Array<{ x: number; y: number }> = [];
private trafficData: Array<{ x: string | number; y: number }> = [];
@state()
private isLoading = false;
private lastTrafficUpdateTime = 0;
private trafficUpdateInterval = 1000; // Update every 1 second
private requestCountHistory = new Map<number, number>(); // Track requests per time bucket
private trafficUpdateTimer: any = null;
// Track bytes for calculating true per-second throughput
private lastBytesIn = 0;
private lastBytesOut = 0;
private lastBytesSampleTime = 0;
constructor() {
super();
this.subscribeToStateParts();
this.initializeTrafficData();
this.updateNetworkData();
this.startTrafficUpdateTimer();
}
async disconnectedCallback() {
await super.disconnectedCallback();
this.stopTrafficUpdateTimer();
}
private subscribeToStateParts() {
@ -65,6 +82,31 @@ export class OpsViewNetwork extends DeesElement {
this.updateNetworkData();
});
}
private initializeTrafficData() {
const now = Date.now();
const timeRanges = {
'1m': 60 * 1000,
'5m': 5 * 60 * 1000,
'15m': 15 * 60 * 1000,
'1h': 60 * 60 * 1000,
'24h': 24 * 60 * 60 * 1000,
};
const range = timeRanges[this.selectedTimeRange];
const bucketSize = range / 60;
// Initialize with empty data points
this.trafficData = Array.from({ length: 60 }, (_, i) => {
const time = now - ((59 - i) * bucketSize);
return {
x: new Date(time).toISOString(),
y: 0,
};
});
this.lastTrafficUpdateTime = now;
}
public static styles = [
cssManager.defaultStyles,
@ -181,7 +223,7 @@ export class OpsViewNetwork extends DeesElement {
<dees-button-group>
${(['1m', '5m', '15m', '1h', '24h'] as const).map(range => html`
<dees-button
@click=${() => this.selectedTimeRange = range}
@click=${() => this.handleTimeRangeChange(range)}
.type=${this.selectedTimeRange === range ? 'highlighted' : 'normal'}
>
${range}
@ -223,10 +265,11 @@ export class OpsViewNetwork extends DeesElement {
.label=${'Network Traffic'}
.series=${[
{
name: 'Requests/min',
name: 'Throughput (Mbps)',
data: this.trafficData,
}
]}
.yAxisFormatter=${(val: number) => `${val} Mbps`}
></dees-chart-area>
<!-- Top IPs Section -->
@ -394,10 +437,13 @@ export class OpsViewNetwork extends DeesElement {
const throughput = this.calculateThroughput();
const activeConnections = this.statsState.serverStats?.activeConnections || 0;
// Generate trend data for requests per second
const trendData = Array.from({ length: 20 }, (_, i) =>
Math.max(0, reqPerSec + (Math.random() - 0.5) * 10)
);
// Use actual traffic data for trends (last 20 points)
const trendData = this.trafficData.slice(-20).map(point => point.y);
// If we don't have enough data, pad with the current value
while (trendData.length < 20) {
trendData.unshift(reqPerSec);
}
const tiles: IStatsTile[] = [
{
@ -532,25 +578,107 @@ export class OpsViewNetwork extends DeesElement {
const range = timeRanges[this.selectedTimeRange];
const bucketSize = range / 60; // 60 data points
// Create buckets for traffic data
const buckets = new Map<number, number>();
// Check if enough time has passed to add a new data point
const timeSinceLastUpdate = now - this.lastTrafficUpdateTime;
const shouldAddNewPoint = timeSinceLastUpdate >= this.trafficUpdateInterval;
// Count requests per bucket
this.networkRequests.forEach(req => {
if (req.timestamp >= now - range) {
const bucketIndex = Math.floor((now - req.timestamp) / bucketSize);
const bucketTime = now - (bucketIndex * bucketSize);
buckets.set(bucketTime, (buckets.get(bucketTime) || 0) + 1);
}
console.log('UpdateTrafficData called:', {
networkRequestsCount: this.networkRequests.length,
timeSinceLastUpdate,
shouldAddNewPoint,
currentDataPoints: this.trafficData.length
});
// Convert to chart data
this.trafficData = Array.from({ length: 60 }, (_, i) => {
const time = now - (i * bucketSize);
return {
x: time,
y: buckets.get(time) || 0,
if (!shouldAddNewPoint && this.trafficData.length > 0) {
// Not enough time has passed, don't update
return;
}
// Calculate actual per-second throughput by tracking deltas
let throughputMbps = 0;
// Get total bytes from all active connections
let currentBytesIn = 0;
let currentBytesOut = 0;
this.networkRequests.forEach(req => {
currentBytesIn += req.bytesIn;
currentBytesOut += req.bytesOut;
});
// If we have a previous sample, calculate the delta
if (this.lastBytesSampleTime > 0) {
const timeDelta = (now - this.lastBytesSampleTime) / 1000; // Convert to seconds
const bytesInDelta = Math.max(0, currentBytesIn - this.lastBytesIn);
const bytesOutDelta = Math.max(0, currentBytesOut - this.lastBytesOut);
// Calculate bytes per second for this interval
const bytesPerSecond = (bytesInDelta + bytesOutDelta) / timeDelta;
// Convert to Mbps (1 Mbps = 125000 bytes/second)
throughputMbps = bytesPerSecond / 125000;
console.log('Throughput calculation:', {
timeDelta,
bytesInDelta,
bytesOutDelta,
bytesPerSecond,
throughputMbps
});
}
// Update last sample values
this.lastBytesIn = currentBytesIn;
this.lastBytesOut = currentBytesOut;
this.lastBytesSampleTime = now;
if (this.trafficData.length === 0) {
// Initialize if empty
this.initializeTrafficData();
} else {
// Add new data point and remove oldest if we have 60 points
const newDataPoint = {
x: new Date(now).toISOString(),
y: Math.round(throughputMbps * 10) / 10 // Round to 1 decimal place
};
}).reverse();
// Create new array with existing data plus new point
const newTrafficData = [...this.trafficData, newDataPoint];
// Keep only the last 60 points
if (newTrafficData.length > 60) {
newTrafficData.shift(); // Remove oldest point
}
this.trafficData = newTrafficData;
this.lastTrafficUpdateTime = now;
console.log('Added new traffic data point:', {
timestamp: newDataPoint.x,
throughputMbps: newDataPoint.y,
totalPoints: this.trafficData.length
});
}
}
private startTrafficUpdateTimer() {
this.stopTrafficUpdateTimer(); // Clear any existing timer
this.trafficUpdateTimer = setInterval(() => {
this.updateTrafficData();
}, 1000); // Check every second, but only update when interval has passed
}
private stopTrafficUpdateTimer() {
if (this.trafficUpdateTimer) {
clearInterval(this.trafficUpdateTimer);
this.trafficUpdateTimer = null;
}
}
private handleTimeRangeChange(range: '1m' | '5m' | '15m' | '1h' | '24h') {
this.selectedTimeRange = range;
// Reinitialize traffic data for new time range
this.initializeTrafficData();
this.updateNetworkData();
}
}