|
|
|
@@ -28,6 +28,13 @@ interface INetworkRequest {
|
|
|
|
|
|
|
|
|
|
|
|
@customElement('ops-view-network')
|
|
|
|
@customElement('ops-view-network')
|
|
|
|
export class OpsViewNetwork extends DeesElement {
|
|
|
|
export class OpsViewNetwork extends DeesElement {
|
|
|
|
|
|
|
|
/** How far back the traffic chart shows */
|
|
|
|
|
|
|
|
private static readonly CHART_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
|
|
|
|
|
|
|
|
/** How often a new data point is added */
|
|
|
|
|
|
|
|
private static readonly UPDATE_INTERVAL_MS = 1000; // 1 second
|
|
|
|
|
|
|
|
/** Derived: max data points the buffer holds */
|
|
|
|
|
|
|
|
private static readonly MAX_DATA_POINTS = OpsViewNetwork.CHART_WINDOW_MS / OpsViewNetwork.UPDATE_INTERVAL_MS;
|
|
|
|
|
|
|
|
|
|
|
|
@state()
|
|
|
|
@state()
|
|
|
|
accessor statsState = appstate.statsStatePart.getState()!;
|
|
|
|
accessor statsState = appstate.statsStatePart.getState()!;
|
|
|
|
|
|
|
|
|
|
|
|
@@ -46,7 +53,7 @@ export class OpsViewNetwork extends DeesElement {
|
|
|
|
|
|
|
|
|
|
|
|
// Track if we need to update the chart to avoid unnecessary re-renders
|
|
|
|
// Track if we need to update the chart to avoid unnecessary re-renders
|
|
|
|
private lastChartUpdate = 0;
|
|
|
|
private lastChartUpdate = 0;
|
|
|
|
private chartUpdateThreshold = 1000; // Minimum ms between chart updates
|
|
|
|
private chartUpdateThreshold = OpsViewNetwork.UPDATE_INTERVAL_MS; // Minimum ms between chart updates
|
|
|
|
|
|
|
|
|
|
|
|
private trafficUpdateTimer: any = null;
|
|
|
|
private trafficUpdateTimer: any = null;
|
|
|
|
private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend
|
|
|
|
private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend
|
|
|
|
@@ -104,13 +111,11 @@ export class OpsViewNetwork extends DeesElement {
|
|
|
|
|
|
|
|
|
|
|
|
private initializeTrafficData() {
|
|
|
|
private initializeTrafficData() {
|
|
|
|
const now = Date.now();
|
|
|
|
const now = Date.now();
|
|
|
|
// Fixed 5 minute time range
|
|
|
|
const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetwork;
|
|
|
|
const range = 5 * 60 * 1000; // 5 minutes
|
|
|
|
|
|
|
|
const bucketSize = range / 60; // 60 data points
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize with empty data points for both in and out
|
|
|
|
// Initialize with empty data points for both in and out
|
|
|
|
const emptyData = Array.from({ length: 60 }, (_, i) => {
|
|
|
|
const emptyData = Array.from({ length: MAX_DATA_POINTS }, (_, i) => {
|
|
|
|
const time = now - ((59 - i) * bucketSize);
|
|
|
|
const time = now - ((MAX_DATA_POINTS - 1 - i) * UPDATE_INTERVAL_MS);
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
x: new Date(time).toISOString(),
|
|
|
|
x: new Date(time).toISOString(),
|
|
|
|
y: 0,
|
|
|
|
y: 0,
|
|
|
|
@@ -143,23 +148,23 @@ export class OpsViewNetwork extends DeesElement {
|
|
|
|
y: Math.round((p.out * 8) / 1000000 * 10) / 10,
|
|
|
|
y: Math.round((p.out * 8) / 1000000 * 10) / 10,
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
// Use history as the chart data, keeping the most recent 60 points (5 min window)
|
|
|
|
const { MAX_DATA_POINTS, UPDATE_INTERVAL_MS } = OpsViewNetwork;
|
|
|
|
const sliceStart = Math.max(0, historyIn.length - 60);
|
|
|
|
|
|
|
|
|
|
|
|
// Use history as the chart data, keeping the most recent points within the window
|
|
|
|
|
|
|
|
const sliceStart = Math.max(0, historyIn.length - MAX_DATA_POINTS);
|
|
|
|
this.trafficDataIn = historyIn.slice(sliceStart);
|
|
|
|
this.trafficDataIn = historyIn.slice(sliceStart);
|
|
|
|
this.trafficDataOut = historyOut.slice(sliceStart);
|
|
|
|
this.trafficDataOut = historyOut.slice(sliceStart);
|
|
|
|
|
|
|
|
|
|
|
|
// If fewer than 60 points, pad the front with zeros
|
|
|
|
// If fewer than MAX_DATA_POINTS, pad the front with zeros
|
|
|
|
if (this.trafficDataIn.length < 60) {
|
|
|
|
if (this.trafficDataIn.length < MAX_DATA_POINTS) {
|
|
|
|
const now = Date.now();
|
|
|
|
const now = Date.now();
|
|
|
|
const range = 5 * 60 * 1000;
|
|
|
|
const padCount = MAX_DATA_POINTS - this.trafficDataIn.length;
|
|
|
|
const bucketSize = range / 60;
|
|
|
|
|
|
|
|
const padCount = 60 - this.trafficDataIn.length;
|
|
|
|
|
|
|
|
const firstTimestamp = this.trafficDataIn.length > 0
|
|
|
|
const firstTimestamp = this.trafficDataIn.length > 0
|
|
|
|
? new Date(this.trafficDataIn[0].x).getTime()
|
|
|
|
? new Date(this.trafficDataIn[0].x).getTime()
|
|
|
|
: now;
|
|
|
|
: now;
|
|
|
|
|
|
|
|
|
|
|
|
const padIn = Array.from({ length: padCount }, (_, i) => ({
|
|
|
|
const padIn = Array.from({ length: padCount }, (_, i) => ({
|
|
|
|
x: new Date(firstTimestamp - ((padCount - i) * bucketSize)).toISOString(),
|
|
|
|
x: new Date(firstTimestamp - ((padCount - i) * UPDATE_INTERVAL_MS)).toISOString(),
|
|
|
|
y: 0,
|
|
|
|
y: 0,
|
|
|
|
}));
|
|
|
|
}));
|
|
|
|
const padOut = padIn.map(p => ({ ...p }));
|
|
|
|
const padOut = padIn.map(p => ({ ...p }));
|
|
|
|
@@ -296,7 +301,7 @@ export class OpsViewNetwork extends DeesElement {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]}
|
|
|
|
]}
|
|
|
|
.realtimeMode=${true}
|
|
|
|
.realtimeMode=${true}
|
|
|
|
.rollingWindow=${300000}
|
|
|
|
.rollingWindow=${OpsViewNetwork.CHART_WINDOW_MS}
|
|
|
|
.yAxisFormatter=${(val: number) => `${val} Mbit/s`}
|
|
|
|
.yAxisFormatter=${(val: number) => `${val} Mbit/s`}
|
|
|
|
></dees-chart-area>
|
|
|
|
></dees-chart-area>
|
|
|
|
|
|
|
|
|
|
|
|
@@ -709,9 +714,8 @@ export class OpsViewNetwork extends DeesElement {
|
|
|
|
private startTrafficUpdateTimer() {
|
|
|
|
private startTrafficUpdateTimer() {
|
|
|
|
this.stopTrafficUpdateTimer(); // Clear any existing timer
|
|
|
|
this.stopTrafficUpdateTimer(); // Clear any existing timer
|
|
|
|
this.trafficUpdateTimer = setInterval(() => {
|
|
|
|
this.trafficUpdateTimer = setInterval(() => {
|
|
|
|
// Add a new data point every second
|
|
|
|
|
|
|
|
this.addTrafficDataPoint();
|
|
|
|
this.addTrafficDataPoint();
|
|
|
|
}, 1000); // Update every second
|
|
|
|
}, OpsViewNetwork.UPDATE_INTERVAL_MS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private addTrafficDataPoint() {
|
|
|
|
private addTrafficDataPoint() {
|
|
|
|
@@ -742,7 +746,7 @@ export class OpsViewNetwork extends DeesElement {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// In-place mutation then reassign for Lit reactivity (avoids 4 intermediate arrays)
|
|
|
|
// In-place mutation then reassign for Lit reactivity (avoids 4 intermediate arrays)
|
|
|
|
if (this.trafficDataIn.length >= 60) {
|
|
|
|
if (this.trafficDataIn.length >= OpsViewNetwork.MAX_DATA_POINTS) {
|
|
|
|
this.trafficDataIn.shift();
|
|
|
|
this.trafficDataIn.shift();
|
|
|
|
this.trafficDataOut.shift();
|
|
|
|
this.trafficDataOut.shift();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|