@serve.zone/dcrouter 17.1.8 → 17.2.2
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/deno.json +1 -1
- package/dist_serve/bundle.js +901 -860
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/monitoring/classes.metricsmanager.d.ts +5 -1
- package/dist_ts/monitoring/classes.metricsmanager.js +18 -3
- package/dist_ts/opsserver/handlers/security.handler.js +5 -1
- package/dist_ts/opsserver/handlers/stats.handler.js +3 -1
- package/dist_ts_interfaces/data/stats.d.ts +7 -0
- package/dist_ts_interfaces/requests/stats.d.ts +2 -0
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/appstate/network.d.ts +2 -0
- package/dist_ts_web/appstate/network.js +5 -1
- package/dist_ts_web/appstate/runtime.js +3 -1
- package/dist_ts_web/elements/network/network-activity-history.d.ts +24 -0
- package/dist_ts_web/elements/network/network-activity-history.js +65 -0
- package/dist_ts_web/elements/network/ops-view-network-activity.d.ts +14 -17
- package/dist_ts_web/elements/network/ops-view-network-activity.js +154 -77
- package/package.json +3 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/monitoring/classes.metricsmanager.ts +18 -3
- package/ts/opsserver/handlers/security.handler.ts +4 -0
- package/ts/opsserver/handlers/stats.handler.ts +2 -0
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/appstate/network.ts +6 -0
- package/ts_web/appstate/runtime.ts +2 -0
- package/ts_web/elements/network/network-activity-history.ts +126 -0
- package/ts_web/elements/network/ops-view-network-activity.ts +195 -81
|
@@ -101,6 +101,8 @@ export class SecurityHandler {
|
|
|
101
101
|
topASNs: networkStats.topASNs,
|
|
102
102
|
totalDataTransferred: networkStats.totalDataTransferred,
|
|
103
103
|
throughputHistory: networkStats.throughputHistory || [],
|
|
104
|
+
frontendConnectionHistory: networkStats.frontendConnectionHistory || [],
|
|
105
|
+
backendConnectionHistory: networkStats.backendConnectionHistory || [],
|
|
104
106
|
throughputByIP,
|
|
105
107
|
domainActivity: networkStats.domainActivity || [],
|
|
106
108
|
requestsPerSecond: networkStats.requestsPerSecond || 0,
|
|
@@ -121,6 +123,8 @@ export class SecurityHandler {
|
|
|
121
123
|
totalDataTransferred: { bytesIn: 0, bytesOut: 0 },
|
|
122
124
|
throughputHistory: [],
|
|
123
125
|
throughputByIP: [],
|
|
126
|
+
frontendConnectionHistory: [],
|
|
127
|
+
backendConnectionHistory: [],
|
|
124
128
|
domainActivity: [],
|
|
125
129
|
requestsPerSecond: 0,
|
|
126
130
|
requestsTotal: 0,
|
|
@@ -336,6 +336,8 @@ export class StatsHandler {
|
|
|
336
336
|
topASNs: stats.topASNs || [],
|
|
337
337
|
domainActivity: stats.domainActivity || [],
|
|
338
338
|
throughputHistory: stats.throughputHistory || [],
|
|
339
|
+
frontendConnectionHistory: stats.frontendConnectionHistory || [],
|
|
340
|
+
backendConnectionHistory: stats.backendConnectionHistory || [],
|
|
339
341
|
requestsPerSecond: stats.requestsPerSecond || 0,
|
|
340
342
|
requestsTotal: stats.requestsTotal || 0,
|
|
341
343
|
backends: stats.backends || [],
|
|
@@ -19,6 +19,8 @@ export interface INetworkState {
|
|
|
19
19
|
ipIntelligence: interfaces.data.IIpIntelligenceRecord[];
|
|
20
20
|
domainActivity: interfaces.data.IDomainActivity[];
|
|
21
21
|
throughputHistory: Array<{ timestamp: number; in: number; out: number }>;
|
|
22
|
+
frontendConnectionHistory: interfaces.data.IProtocolConnectionHistoryPoint[];
|
|
23
|
+
backendConnectionHistory: interfaces.data.IProtocolConnectionHistoryPoint[];
|
|
22
24
|
requestsPerSecond: number;
|
|
23
25
|
requestsTotal: number;
|
|
24
26
|
backends: interfaces.data.IBackendInfo[];
|
|
@@ -43,6 +45,8 @@ export const networkStatePart = await appState.getStatePart<INetworkState>(
|
|
|
43
45
|
ipIntelligence: [],
|
|
44
46
|
domainActivity: [],
|
|
45
47
|
throughputHistory: [],
|
|
48
|
+
frontendConnectionHistory: [],
|
|
49
|
+
backendConnectionHistory: [],
|
|
46
50
|
requestsPerSecond: 0,
|
|
47
51
|
requestsTotal: 0,
|
|
48
52
|
backends: [],
|
|
@@ -150,6 +154,8 @@ export const fetchNetworkStatsAction = networkStatePart.createAction(async (stat
|
|
|
150
154
|
ipIntelligence: currentState.ipIntelligence,
|
|
151
155
|
domainActivity: networkStatsResponse.domainActivity || [],
|
|
152
156
|
throughputHistory: networkStatsResponse.throughputHistory || [],
|
|
157
|
+
frontendConnectionHistory: networkStatsResponse.frontendConnectionHistory || [],
|
|
158
|
+
backendConnectionHistory: networkStatsResponse.backendConnectionHistory || [],
|
|
153
159
|
requestsPerSecond: networkStatsResponse.requestsPerSecond || 0,
|
|
154
160
|
requestsTotal: networkStatsResponse.requestsTotal || 0,
|
|
155
161
|
backends: networkStatsResponse.backends || [],
|
|
@@ -340,6 +340,8 @@ async function dispatchCombinedRefreshActionInner() {
|
|
|
340
340
|
throughputByIP: network.topEndpoints.map(e => ({ ip: e.endpoint, in: e.bandwidth?.in || 0, out: e.bandwidth?.out || 0 })),
|
|
341
341
|
domainActivity: network.domainActivity || [],
|
|
342
342
|
throughputHistory: network.throughputHistory || [],
|
|
343
|
+
frontendConnectionHistory: network.frontendConnectionHistory || [],
|
|
344
|
+
backendConnectionHistory: network.backendConnectionHistory || [],
|
|
343
345
|
requestsPerSecond: network.requestsPerSecond || 0,
|
|
344
346
|
requestsTotal: network.requestsTotal || 0,
|
|
345
347
|
backends: network.backends || [],
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export interface IChartPoint {
|
|
2
|
+
x: string | number;
|
|
3
|
+
y: number;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface IProtocolConnectionHistoryPointLike {
|
|
7
|
+
timestamp: number;
|
|
8
|
+
total: number;
|
|
9
|
+
protocols: Record<string, number>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TProtocolChartSeries = Array<{
|
|
13
|
+
name: string;
|
|
14
|
+
data: IChartPoint[];
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
export const PROTOCOL_ORDER = ['HTTP/1.1', 'HTTP/2', 'HTTP/3', 'WebSocket', 'Other'] as const;
|
|
18
|
+
export const PROTOCOL_SERIES_ORDER = ['Total Active', ...PROTOCOL_ORDER] as const;
|
|
19
|
+
|
|
20
|
+
const toEpochSecond = (timestampArg: string | number): number => {
|
|
21
|
+
const timestampMs = typeof timestampArg === 'number'
|
|
22
|
+
? timestampArg
|
|
23
|
+
: new Date(timestampArg).getTime();
|
|
24
|
+
return Math.floor(timestampMs / 1000);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const getLatestHistoryEpochSecond = (
|
|
28
|
+
historyArg: Array<{ timestamp: number }>,
|
|
29
|
+
): number => historyArg.reduce(
|
|
30
|
+
(latest, point) => Math.max(latest, Math.floor(point.timestamp / 1000)),
|
|
31
|
+
0,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const mergeChartPoints = (
|
|
35
|
+
localPointsArg: IChartPoint[],
|
|
36
|
+
canonicalPointsArg: IChartPoint[],
|
|
37
|
+
maximumPointsArg: number,
|
|
38
|
+
): IChartPoint[] => {
|
|
39
|
+
const pointsBySecond = new Map<number, IChartPoint>();
|
|
40
|
+
for (const point of localPointsArg) {
|
|
41
|
+
const epochSecond = toEpochSecond(point.x);
|
|
42
|
+
if (Number.isFinite(epochSecond)) {
|
|
43
|
+
pointsBySecond.set(epochSecond, point);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
// Canonical engine samples win when a locally repeated cached sample used the same second.
|
|
47
|
+
for (const point of canonicalPointsArg) {
|
|
48
|
+
const epochSecond = toEpochSecond(point.x);
|
|
49
|
+
if (Number.isFinite(epochSecond)) {
|
|
50
|
+
pointsBySecond.set(epochSecond, point);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return [...pointsBySecond.entries()]
|
|
55
|
+
.sort(([secondA], [secondB]) => secondA - secondB)
|
|
56
|
+
.map(([, point]) => point)
|
|
57
|
+
.slice(-maximumPointsArg);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const createProtocolConnectionSeries = (
|
|
61
|
+
historyArg: IProtocolConnectionHistoryPointLike[] = [],
|
|
62
|
+
): TProtocolChartSeries => PROTOCOL_SERIES_ORDER.map((seriesName) => ({
|
|
63
|
+
name: seriesName,
|
|
64
|
+
data: historyArg.map((point) => ({
|
|
65
|
+
x: new Date(point.timestamp).toISOString(),
|
|
66
|
+
y: seriesName === 'Total Active'
|
|
67
|
+
? point.total
|
|
68
|
+
: (point.protocols[seriesName] ?? 0),
|
|
69
|
+
})),
|
|
70
|
+
}));
|
|
71
|
+
|
|
72
|
+
export const mergeProtocolConnectionHistory = (
|
|
73
|
+
localSeriesArg: TProtocolChartSeries,
|
|
74
|
+
canonicalHistoryArg: IProtocolConnectionHistoryPointLike[],
|
|
75
|
+
maximumPointsArg: number,
|
|
76
|
+
): TProtocolChartSeries => {
|
|
77
|
+
const localSeriesByName = new Map(localSeriesArg.map((series) => [series.name, series]));
|
|
78
|
+
const canonicalSeriesByName = new Map(
|
|
79
|
+
createProtocolConnectionSeries(canonicalHistoryArg)
|
|
80
|
+
.map((series) => [series.name, series]),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
return PROTOCOL_SERIES_ORDER.map((seriesName) => ({
|
|
84
|
+
name: seriesName,
|
|
85
|
+
data: mergeChartPoints(
|
|
86
|
+
localSeriesByName.get(seriesName)?.data ?? [],
|
|
87
|
+
canonicalSeriesByName.get(seriesName)?.data ?? [],
|
|
88
|
+
maximumPointsArg,
|
|
89
|
+
),
|
|
90
|
+
}));
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const getProtocolConnectionTotal = (
|
|
94
|
+
protocolsArg: Record<string, number>,
|
|
95
|
+
): number => (protocolsArg['HTTP/1.1'] ?? 0)
|
|
96
|
+
+ (protocolsArg['HTTP/2'] ?? 0)
|
|
97
|
+
+ (protocolsArg['HTTP/3'] ?? 0)
|
|
98
|
+
+ (protocolsArg.Other ?? 0);
|
|
99
|
+
|
|
100
|
+
export const appendProtocolConnectionSample = (
|
|
101
|
+
localSeriesArg: TProtocolChartSeries,
|
|
102
|
+
timestampArg: string | number,
|
|
103
|
+
protocolsArg: Record<string, number>,
|
|
104
|
+
maximumPointsArg: number,
|
|
105
|
+
): TProtocolChartSeries => {
|
|
106
|
+
const localSeriesByName = new Map(localSeriesArg.map((series) => [series.name, series]));
|
|
107
|
+
return PROTOCOL_SERIES_ORDER.map((seriesName) => ({
|
|
108
|
+
name: seriesName,
|
|
109
|
+
data: mergeChartPoints(
|
|
110
|
+
localSeriesByName.get(seriesName)?.data ?? [],
|
|
111
|
+
[{
|
|
112
|
+
x: timestampArg,
|
|
113
|
+
y: seriesName === 'Total Active'
|
|
114
|
+
? getProtocolConnectionTotal(protocolsArg)
|
|
115
|
+
: (protocolsArg[seriesName] ?? 0),
|
|
116
|
+
}],
|
|
117
|
+
maximumPointsArg,
|
|
118
|
+
),
|
|
119
|
+
}));
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const shouldRestartNetworkActivityTimer = (
|
|
123
|
+
isConnectedArg: boolean,
|
|
124
|
+
documentHiddenArg: boolean,
|
|
125
|
+
): boolean => isConnectedArg && !documentHiddenArg;
|
|
126
|
+
|
|
@@ -4,6 +4,25 @@ import * as interfaces from '../../../dist_ts_interfaces/index.js';
|
|
|
4
4
|
import { viewHostCss } from '../shared/css.js';
|
|
5
5
|
import { type IStatsTile } from '@design.estate/dees-catalog';
|
|
6
6
|
|
|
7
|
+
import {
|
|
8
|
+
appendProtocolConnectionSample,
|
|
9
|
+
createProtocolConnectionSeries,
|
|
10
|
+
getLatestHistoryEpochSecond,
|
|
11
|
+
mergeChartPoints,
|
|
12
|
+
mergeProtocolConnectionHistory,
|
|
13
|
+
shouldRestartNetworkActivityTimer,
|
|
14
|
+
type IChartPoint,
|
|
15
|
+
type TProtocolChartSeries,
|
|
16
|
+
} from './network-activity-history.js';
|
|
17
|
+
|
|
18
|
+
const PROTOCOL_COLORS: Record<string, string> = {
|
|
19
|
+
'HTTP/1.1': '#1976d2',
|
|
20
|
+
'HTTP/2': '#388e3c',
|
|
21
|
+
'HTTP/3': '#7b1fa2',
|
|
22
|
+
'WebSocket': '#f57c00',
|
|
23
|
+
'Other': '#757575',
|
|
24
|
+
};
|
|
25
|
+
|
|
7
26
|
declare global {
|
|
8
27
|
interface HTMLElementTagNameMap {
|
|
9
28
|
'ops-view-network-activity': OpsViewNetworkActivity;
|
|
@@ -12,8 +31,8 @@ declare global {
|
|
|
12
31
|
|
|
13
32
|
@customElement('ops-view-network-activity')
|
|
14
33
|
export class OpsViewNetworkActivity extends DeesElement {
|
|
15
|
-
/** How far back the
|
|
16
|
-
private static readonly CHART_WINDOW_MS =
|
|
34
|
+
/** How far back the realtime charts show */
|
|
35
|
+
private static readonly CHART_WINDOW_MS = 10 * 60 * 1000; // 10 minutes
|
|
17
36
|
/** How often a new data point is added */
|
|
18
37
|
private static readonly UPDATE_INTERVAL_MS = 1000; // 1 second
|
|
19
38
|
/** Derived: max data points the buffer holds */
|
|
@@ -27,10 +46,16 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
27
46
|
|
|
28
47
|
|
|
29
48
|
@state()
|
|
30
|
-
accessor trafficDataIn:
|
|
49
|
+
accessor trafficDataIn: IChartPoint[] = [];
|
|
50
|
+
|
|
51
|
+
@state()
|
|
52
|
+
accessor trafficDataOut: IChartPoint[] = [];
|
|
53
|
+
|
|
54
|
+
@state()
|
|
55
|
+
accessor frontendConnectionSeries: TProtocolChartSeries = createProtocolConnectionSeries();
|
|
31
56
|
|
|
32
57
|
@state()
|
|
33
|
-
accessor
|
|
58
|
+
accessor backendConnectionSeries: TProtocolChartSeries = createProtocolConnectionSeries();
|
|
34
59
|
|
|
35
60
|
// Track if we need to update the chart to avoid unnecessary re-renders
|
|
36
61
|
private lastChartUpdate = 0;
|
|
@@ -38,8 +63,10 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
38
63
|
|
|
39
64
|
private trafficUpdateTimer: any = null;
|
|
40
65
|
private requestsPerSecHistory: number[] = []; // Track requests/sec over time for trend
|
|
41
|
-
private historyLoaded = false; // Whether server-side throughput history has been loaded
|
|
42
66
|
private visibilityHandler: (() => void) | null = null;
|
|
67
|
+
private lastThroughputHistoryEpochSecond = 0;
|
|
68
|
+
private lastFrontendHistoryEpochSecond = 0;
|
|
69
|
+
private lastBackendHistoryEpochSecond = 0;
|
|
43
70
|
|
|
44
71
|
constructor() {
|
|
45
72
|
super();
|
|
@@ -57,7 +84,16 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
57
84
|
if (document.hidden) {
|
|
58
85
|
this.stopTrafficUpdateTimer();
|
|
59
86
|
} else {
|
|
60
|
-
|
|
87
|
+
void appstate.networkStatePart
|
|
88
|
+
.dispatchAction(appstate.fetchNetworkStatsAction, null)
|
|
89
|
+
.catch((error) => {
|
|
90
|
+
console.error('Failed to refresh network history after visibility resume:', error);
|
|
91
|
+
})
|
|
92
|
+
.finally(() => {
|
|
93
|
+
if (shouldRestartNetworkActivityTimer(this.isConnected, document.hidden)) {
|
|
94
|
+
this.startTrafficUpdateTimer();
|
|
95
|
+
}
|
|
96
|
+
});
|
|
61
97
|
}
|
|
62
98
|
};
|
|
63
99
|
document.addEventListener('visibilitychange', this.visibilityHandler);
|
|
@@ -106,51 +142,92 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
106
142
|
this.trafficDataOut = emptyData.map(point => ({ ...point }));
|
|
107
143
|
}
|
|
108
144
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (!history || history.length === 0) return;
|
|
118
|
-
|
|
119
|
-
this.historyLoaded = true;
|
|
120
|
-
|
|
121
|
-
// Convert history points to chart data format (bytes/sec → Mbit/s)
|
|
122
|
-
const historyIn = history.map(p => ({
|
|
123
|
-
x: new Date(p.timestamp).toISOString(),
|
|
124
|
-
y: Math.round((p.in * 8) / 1000000 * 10) / 10,
|
|
145
|
+
private mergeThroughputHistory(): void {
|
|
146
|
+
const history = this.networkState.throughputHistory || [];
|
|
147
|
+
const latestHistoryEpochSecond = getLatestHistoryEpochSecond(history);
|
|
148
|
+
if (latestHistoryEpochSecond <= this.lastThroughputHistoryEpochSecond) return;
|
|
149
|
+
|
|
150
|
+
const canonicalIn = history.map((point) => ({
|
|
151
|
+
x: new Date(point.timestamp).toISOString(),
|
|
152
|
+
y: Math.round(((point.in * 8) / 1000000) * 10) / 10,
|
|
125
153
|
}));
|
|
126
|
-
const
|
|
127
|
-
x: new Date(
|
|
128
|
-
y: Math.round((
|
|
154
|
+
const canonicalOut = history.map((point) => ({
|
|
155
|
+
x: new Date(point.timestamp).toISOString(),
|
|
156
|
+
y: Math.round(((point.out * 8) / 1000000) * 10) / 10,
|
|
129
157
|
}));
|
|
130
158
|
|
|
131
|
-
|
|
159
|
+
this.trafficDataIn = mergeChartPoints(
|
|
160
|
+
this.trafficDataIn,
|
|
161
|
+
canonicalIn,
|
|
162
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
163
|
+
);
|
|
164
|
+
this.trafficDataOut = mergeChartPoints(
|
|
165
|
+
this.trafficDataOut,
|
|
166
|
+
canonicalOut,
|
|
167
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
168
|
+
);
|
|
169
|
+
this.lastThroughputHistoryEpochSecond = latestHistoryEpochSecond;
|
|
170
|
+
}
|
|
132
171
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
172
|
+
private getProtocolCounts(
|
|
173
|
+
distributionArg: interfaces.data.IProtocolDistribution,
|
|
174
|
+
): Record<string, number> {
|
|
175
|
+
return {
|
|
176
|
+
'HTTP/1.1': distributionArg.h1Active,
|
|
177
|
+
'HTTP/2': distributionArg.h2Active,
|
|
178
|
+
'HTTP/3': distributionArg.h3Active,
|
|
179
|
+
'WebSocket': distributionArg.wsActive,
|
|
180
|
+
'Other': distributionArg.otherActive,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private getProtocolSeriesWithColors(seriesArg: TProtocolChartSeries) {
|
|
185
|
+
return seriesArg.map((series) => ({
|
|
186
|
+
...series,
|
|
187
|
+
color: series.name === 'Total Active' ? '#ef4444' : (PROTOCOL_COLORS[series.name] ?? '#757575'),
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private mergeProtocolConnectionHistories(): void {
|
|
192
|
+
const frontendHistory = this.networkState.frontendConnectionHistory || [];
|
|
193
|
+
const latestFrontendEpochSecond = getLatestHistoryEpochSecond(frontendHistory);
|
|
194
|
+
if (latestFrontendEpochSecond > this.lastFrontendHistoryEpochSecond) {
|
|
195
|
+
this.frontendConnectionSeries = mergeProtocolConnectionHistory(
|
|
196
|
+
this.frontendConnectionSeries,
|
|
197
|
+
frontendHistory,
|
|
198
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
199
|
+
);
|
|
200
|
+
this.lastFrontendHistoryEpochSecond = latestFrontendEpochSecond;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const backendHistory = this.networkState.backendConnectionHistory || [];
|
|
204
|
+
const latestBackendEpochSecond = getLatestHistoryEpochSecond(backendHistory);
|
|
205
|
+
if (latestBackendEpochSecond > this.lastBackendHistoryEpochSecond) {
|
|
206
|
+
this.backendConnectionSeries = mergeProtocolConnectionHistory(
|
|
207
|
+
this.backendConnectionSeries,
|
|
208
|
+
backendHistory,
|
|
209
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
210
|
+
);
|
|
211
|
+
this.lastBackendHistoryEpochSecond = latestBackendEpochSecond;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
151
214
|
|
|
152
|
-
|
|
153
|
-
|
|
215
|
+
private addProtocolConnectionDataPoints(timestampArg: string): void {
|
|
216
|
+
if (this.networkState.frontendProtocols) {
|
|
217
|
+
this.frontendConnectionSeries = appendProtocolConnectionSample(
|
|
218
|
+
this.frontendConnectionSeries,
|
|
219
|
+
timestampArg,
|
|
220
|
+
this.getProtocolCounts(this.networkState.frontendProtocols),
|
|
221
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
if (this.networkState.backendProtocols) {
|
|
225
|
+
this.backendConnectionSeries = appendProtocolConnectionSample(
|
|
226
|
+
this.backendConnectionSeries,
|
|
227
|
+
timestampArg,
|
|
228
|
+
this.getProtocolCounts(this.networkState.backendProtocols),
|
|
229
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
230
|
+
);
|
|
154
231
|
}
|
|
155
232
|
}
|
|
156
233
|
|
|
@@ -162,6 +239,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
162
239
|
display: flex;
|
|
163
240
|
flex-direction: column;
|
|
164
241
|
gap: 24px;
|
|
242
|
+
container-type: inline-size;
|
|
165
243
|
}
|
|
166
244
|
|
|
167
245
|
|
|
@@ -268,9 +346,31 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
268
346
|
|
|
269
347
|
.protocolChartGrid {
|
|
270
348
|
display: grid;
|
|
271
|
-
grid-template-columns: repeat(2, 1fr);
|
|
349
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
350
|
+
gap: 16px;
|
|
351
|
+
min-width: 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.protocolChartColumn {
|
|
355
|
+
display: flex;
|
|
356
|
+
flex-direction: column;
|
|
272
357
|
gap: 16px;
|
|
358
|
+
min-width: 0;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.protocolChartColumn > dees-chart-donut,
|
|
362
|
+
.protocolChartColumn > dees-chart-area {
|
|
363
|
+
width: 100%;
|
|
364
|
+
max-width: 100%;
|
|
365
|
+
min-width: 0;
|
|
273
366
|
}
|
|
367
|
+
|
|
368
|
+
@container (max-width: 800px) {
|
|
369
|
+
.protocolChartGrid {
|
|
370
|
+
grid-template-columns: minmax(0, 1fr);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
274
374
|
`,
|
|
275
375
|
];
|
|
276
376
|
|
|
@@ -557,13 +657,7 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
557
657
|
const fp = this.networkState.frontendProtocols;
|
|
558
658
|
const bp = this.networkState.backendProtocols;
|
|
559
659
|
|
|
560
|
-
const protoColors
|
|
561
|
-
'HTTP/1.1': '#1976d2',
|
|
562
|
-
'HTTP/2': '#388e3c',
|
|
563
|
-
'HTTP/3': '#7b1fa2',
|
|
564
|
-
'WebSocket': '#f57c00',
|
|
565
|
-
'Other': '#757575',
|
|
566
|
-
};
|
|
660
|
+
const protoColors = PROTOCOL_COLORS;
|
|
567
661
|
|
|
568
662
|
const buildDonutData = (dist: interfaces.data.IProtocolDistribution | null) => {
|
|
569
663
|
if (!dist) return [];
|
|
@@ -581,22 +675,40 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
581
675
|
|
|
582
676
|
return html`
|
|
583
677
|
<div class="protocolChartGrid">
|
|
584
|
-
<
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
678
|
+
<div class="protocolChartColumn">
|
|
679
|
+
<dees-chart-donut
|
|
680
|
+
.label=${'Frontend Protocols'}
|
|
681
|
+
.data=${frontendData.length > 0 ? frontendData : [{ name: 'No Traffic', value: 1, color: '#757575' }]}
|
|
682
|
+
.showLegend=${true}
|
|
683
|
+
.showLabels=${true}
|
|
684
|
+
.innerRadiusPercent=${'55%'}
|
|
685
|
+
.valueFormatter=${(val: number) => `${val} active`}
|
|
686
|
+
></dees-chart-donut>
|
|
687
|
+
<dees-chart-area
|
|
688
|
+
.label=${'Frontend Active Connections'}
|
|
689
|
+
.series=${this.getProtocolSeriesWithColors(this.frontendConnectionSeries)}
|
|
690
|
+
.realtimeMode=${true}
|
|
691
|
+
.rollingWindow=${OpsViewNetworkActivity.CHART_WINDOW_MS}
|
|
692
|
+
.yAxisFormatter=${(val: number) => `${Math.round(val)} active`}
|
|
693
|
+
></dees-chart-area>
|
|
694
|
+
</div>
|
|
695
|
+
<div class="protocolChartColumn">
|
|
696
|
+
<dees-chart-donut
|
|
697
|
+
.label=${'Backend Protocols'}
|
|
698
|
+
.data=${backendData.length > 0 ? backendData : [{ name: 'No Traffic', value: 1, color: '#757575' }]}
|
|
699
|
+
.showLegend=${true}
|
|
700
|
+
.showLabels=${true}
|
|
701
|
+
.innerRadiusPercent=${'55%'}
|
|
702
|
+
.valueFormatter=${(val: number) => `${val} active`}
|
|
703
|
+
></dees-chart-donut>
|
|
704
|
+
<dees-chart-area
|
|
705
|
+
.label=${'Backend Active Connections'}
|
|
706
|
+
.series=${this.getProtocolSeriesWithColors(this.backendConnectionSeries)}
|
|
707
|
+
.realtimeMode=${true}
|
|
708
|
+
.rollingWindow=${OpsViewNetworkActivity.CHART_WINDOW_MS}
|
|
709
|
+
.yAxisFormatter=${(val: number) => `${Math.round(val)} active`}
|
|
710
|
+
></dees-chart-area>
|
|
711
|
+
</div>
|
|
600
712
|
</div>
|
|
601
713
|
`;
|
|
602
714
|
}
|
|
@@ -962,10 +1074,8 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
962
1074
|
this.requestsPerSecHistory.shift();
|
|
963
1075
|
}
|
|
964
1076
|
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
this.loadThroughputHistory();
|
|
968
|
-
}
|
|
1077
|
+
this.mergeThroughputHistory();
|
|
1078
|
+
this.mergeProtocolConnectionHistories();
|
|
969
1079
|
}
|
|
970
1080
|
|
|
971
1081
|
private startTrafficUpdateTimer() {
|
|
@@ -1005,13 +1115,17 @@ export class OpsViewNetworkActivity extends DeesElement {
|
|
|
1005
1115
|
y: Math.round(throughputOutMbps * 10) / 10
|
|
1006
1116
|
};
|
|
1007
1117
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
this.
|
|
1014
|
-
|
|
1118
|
+
this.trafficDataIn = mergeChartPoints(
|
|
1119
|
+
this.trafficDataIn,
|
|
1120
|
+
[newDataPointIn],
|
|
1121
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
1122
|
+
);
|
|
1123
|
+
this.trafficDataOut = mergeChartPoints(
|
|
1124
|
+
this.trafficDataOut,
|
|
1125
|
+
[newDataPointOut],
|
|
1126
|
+
OpsViewNetworkActivity.MAX_DATA_POINTS,
|
|
1127
|
+
);
|
|
1128
|
+
this.addProtocolConnectionDataPoints(timestamp);
|
|
1015
1129
|
|
|
1016
1130
|
this.lastChartUpdate = now;
|
|
1017
1131
|
}
|