Offer visual sankey alternatives for Top 10 Downloaders, Worst 10 RTT and Worst 10 Retransmit.

This commit is contained in:
Herbert Wolverson 2024-07-25 15:54:42 -05:00
parent f9e416ba07
commit 699542501c
5 changed files with 171 additions and 80 deletions

View File

@ -22,6 +22,8 @@ import {TreeCapacityDash} from "./tree_capacity_dash";
import {CircuitCapacityDash} from "./circuit_capacity_dash"; import {CircuitCapacityDash} from "./circuit_capacity_dash";
import {TopTreeSankey} from "./top_tree_sankey"; import {TopTreeSankey} from "./top_tree_sankey";
import {Top10DownloadersVisual} from "./top10_downloads_graphic"; import {Top10DownloadersVisual} from "./top10_downloads_graphic";
import {Worst10DownloadersVisual} from "./worst10_downloaders_graphic";
import {Worst10RetransmitsVisual} from "./worst10_retransmits_graphic";
export const DashletMenu = [ export const DashletMenu = [
{ name: "Throughput Bits/Second", tag: "throughputBps", size: 3 }, { name: "Throughput Bits/Second", tag: "throughputBps", size: 3 },
@ -33,7 +35,9 @@ export const DashletMenu = [
{ name: "Top 10 Downloaders", tag: "top10downloaders", size: 6 }, { name: "Top 10 Downloaders", tag: "top10downloaders", size: 6 },
{ name: "Top 10 Downloaders (Visual)", tag: "top10downloadersV", size: 6 }, { name: "Top 10 Downloaders (Visual)", tag: "top10downloadersV", size: 6 },
{ name: "Worst 10 Round-Trip Time", tag: "worst10downloaders", size: 6 }, { name: "Worst 10 Round-Trip Time", tag: "worst10downloaders", size: 6 },
{ name: "Worst 10 Round-Trip Time (Visual)", tag: "worst10downloadersV", size: 6 },
{ name: "Worst 10 Retransmits", tag: "worst10retransmits", size: 6 }, { name: "Worst 10 Retransmits", tag: "worst10retransmits", size: 6 },
{ name: "Worst 10 Retransmits (Visual)", tag: "worst10retransmitsV", size: 6 },
{ name: "Top 10 Flows (total bytes)", tag: "top10flowsBytes", size: 6 }, { name: "Top 10 Flows (total bytes)", tag: "top10flowsBytes", size: 6 },
{ name: "Top 10 Flows (rate)", tag: "top10flowsRate", size: 6 }, { name: "Top 10 Flows (rate)", tag: "top10flowsRate", size: 6 },
{ name: "Top 10 Endpoints by Country", tag: "top10endpointsCountry", size: 6 }, { name: "Top 10 Endpoints by Country", tag: "top10endpointsCountry", size: 6 },
@ -63,7 +67,9 @@ export function widgetFactory(widgetName, count) {
case "top10downloaders":widget = new Top10Downloaders(count); break; case "top10downloaders":widget = new Top10Downloaders(count); break;
case "top10downloadersV":widget = new Top10DownloadersVisual(count); break; case "top10downloadersV":widget = new Top10DownloadersVisual(count); break;
case "worst10downloaders":widget = new Worst10Downloaders(count); break; case "worst10downloaders":widget = new Worst10Downloaders(count); break;
case "worst10downloadersV":widget = new Worst10DownloadersVisual(count); break;
case "worst10retransmits":widget = new Worst10Retransmits(count); break; case "worst10retransmits":widget = new Worst10Retransmits(count); break;
case "worst10retransmitsV":widget = new Worst10RetransmitsVisual(count); break;
case "top10flowsBytes" : widget = new Top10FlowsBytes(count); break; case "top10flowsBytes" : widget = new Top10FlowsBytes(count); break;
case "top10flowsRate" : widget = new Top10FlowsRate(count); break; case "top10flowsRate" : widget = new Top10FlowsRate(count); break;
case "top10endpointsCountry" : widget = new Top10EndpointsByCountry(count); break; case "top10endpointsCountry" : widget = new Top10EndpointsByCountry(count); break;

View File

@ -1,40 +1,10 @@
import {BaseDashlet} from "./base_dashlet"; import {BaseDashlet} from "./base_dashlet";
import {RttHistogram} from "../graphs/rtt_histo";
import {clearDashDiv, theading, TopNTableFromMsgData, topNTableHeader, topNTableRow} from "../helpers/builders";
import { import {
scaleNumber, scaleNumber,
rttCircleSpan,
formatThroughput,
formatRtt,
formatRetransmit,
lerpGreenToRedViaOrange, lerpColor lerpGreenToRedViaOrange, lerpColor
} from "../helpers/scaling"; } from "../helpers/scaling";
import {redactCell} from "../helpers/redact";
import {DashboardGraph} from "../graphs/dashboard_graph"; import {DashboardGraph} from "../graphs/dashboard_graph";
import {TopNSankey} from "../graphs/top_n_sankey";
class Top10DownloadSankey extends DashboardGraph {
constructor(id) {
super(id);
this.option = {
series: [
{
nodeAlign: 'left',
type: 'sankey',
data: [],
links: []
}
]
};
this.option && this.chart.setOption(this.option);
}
update(data, links) {
this.option.series[0].data = data;
this.option.series[0].links = links;
this.chart.hideLoading();
this.chart.setOption(this.option);
}
}
export class Top10DownloadersVisual extends BaseDashlet { export class Top10DownloadersVisual extends BaseDashlet {
constructor(slot) { constructor(slot) {
@ -65,60 +35,13 @@ export class Top10DownloadersVisual extends BaseDashlet {
setup() { setup() {
super.setup(); super.setup();
this.graph = new Top10DownloadSankey(this.graphDivId()); this.graph = new TopNSankey(this.graphDivId());
} }
onMessage(msg) { onMessage(msg) {
if (msg.event === "TopDownloads") { if (msg.event === "TopDownloads") {
//console.log(msg); //console.log(msg);
this.graph.processMessage(msg);
let nodes = [];
let links = [];
nodes.push({
name: "Root",
label: "Root",
});
msg.data.forEach((r) => {
let label = {
fontSize: 9,
color: "#999"
};
let name = r.ip_address+ " (" + scaleNumber(r.bits_per_second.down, 0) + ", " + r.tcp_retransmits.down + "/" + r.tcp_retransmits.up + ")";
let bytes = r.bits_per_second.down / 8;
let bytesAsMegabits = bytes / 1000000;
let maxBytes = r.plan.down / 8;
let percent = Math.min(100, (bytesAsMegabits / maxBytes) * 100);
let capacityColor = lerpGreenToRedViaOrange(100 - percent, 100);
let rttColor = lerpGreenToRedViaOrange(200 - r.median_tcp_rtt, 200);
let percentRxmit = Math.min(100, r.tcp_retransmits.down + r.tcp_retransmits.up) / 100;
let rxmitColor = lerpColor([0, 255, 0], [255, 0, 0], percentRxmit);
nodes.push({
name: name,
label: label,
itemStyle: {
color: rxmitColor,
borderWidth: 4,
borderColor: rttColor,
}
});
links.push({
source: "Root",
target: name,
value: r.bits_per_second.down,
lineStyle: {
color: capacityColor
}
});
});
this.graph.update(nodes, links);
} }
} }
} }

View File

@ -0,0 +1,41 @@
import {BaseDashlet} from "./base_dashlet";
import {TopNSankey} from "../graphs/top_n_sankey";
export class Worst10DownloadersVisual extends BaseDashlet {
constructor(slot) {
super(slot);
}
canBeSlowedDown() {
return true;
}
title() {
return "Worst 10 Round-Trip Time";
}
tooltip() {
return "<h5>Worst 10 Round-Trip Time</h5><p>Worst 10 Downloaders by round-trip time, including IP address, download and upload rates, round-trip time, TCP retransmits, and shaping plan.</p>";
}
subscribeTo() {
return [ "WorstRTT" ];
}
buildContainer() {
let base = super.buildContainer();
base.appendChild(this.graphDiv());
return base;
}
setup() {
super.setup();
this.graph = new TopNSankey(this.graphDivId());
}
onMessage(msg) {
if (msg.event === "WorstRTT") {
this.graph.processMessage(msg);
}
}
}

View File

@ -0,0 +1,45 @@
import {BaseDashlet} from "./base_dashlet";
import {RttHistogram} from "../graphs/rtt_histo";
import {clearDashDiv, theading, TopNTableFromMsgData, topNTableHeader, topNTableRow} from "../helpers/builders";
import {scaleNumber, rttCircleSpan, formatRtt, formatThroughput} from "../helpers/scaling";
import {redactCell} from "../helpers/redact";
import {TopNSankey} from "../graphs/top_n_sankey";
export class Worst10RetransmitsVisual extends BaseDashlet {
constructor(slot) {
super(slot);
}
canBeSlowedDown() {
return true;
}
title() {
return "Worst 10 TCP Re-transmits";
}
tooltip() {
return "<h5>Worst 10 TCP Re-transmits</h5><p>Worst 10 Downloaders by TCP retransmits, including IP address, download and upload rates, round-trip time, TCP retransmits, and shaping plan.</p>";
}
subscribeTo() {
return [ "WorstRetransmits" ];
}
buildContainer() {
let base = super.buildContainer();
base.appendChild(this.graphDiv());
return base;
}
setup() {
super.setup();
this.graph = new TopNSankey(this.graphDivId());
}
onMessage(msg) {
if (msg.event === "WorstRetransmits") {
this.graph.processMessage(msg);
}
}
}

View File

@ -0,0 +1,76 @@
import {DashboardGraph} from "./dashboard_graph";
import {lerpColor, lerpGreenToRedViaOrange, scaleNumber} from "../helpers/scaling";
export class TopNSankey extends DashboardGraph {
constructor(id) {
super(id);
this.option = {
series: [
{
nodeAlign: 'left',
type: 'sankey',
data: [],
links: []
}
]
};
this.option && this.chart.setOption(this.option);
}
update(data, links) {
this.option.series[0].data = data;
this.option.series[0].links = links;
this.chart.hideLoading();
this.chart.setOption(this.option);
}
processMessage(msg) {
let nodes = [];
let links = [];
nodes.push({
name: "Root",
label: "Root",
});
msg.data.forEach((r) => {
let label = {
fontSize: 9,
color: "#999"
};
let name = r.ip_address+ " (" + scaleNumber(r.bits_per_second.down, 0) + ", " + r.tcp_retransmits.down + "/" + r.tcp_retransmits.up + ")";
let bytes = r.bits_per_second.down / 8;
let bytesAsMegabits = bytes / 1000000;
let maxBytes = r.plan.down / 8;
let percent = Math.min(100, (bytesAsMegabits / maxBytes) * 100);
let capacityColor = lerpGreenToRedViaOrange(100 - percent, 100);
let rttColor = lerpGreenToRedViaOrange(200 - r.median_tcp_rtt, 200);
let percentRxmit = Math.min(100, r.tcp_retransmits.down + r.tcp_retransmits.up) / 100;
let rxmitColor = lerpColor([0, 255, 0], [255, 0, 0], percentRxmit);
nodes.push({
name: name,
label: label,
itemStyle: {
color: rxmitColor,
borderWidth: 4,
borderColor: rttColor,
}
});
links.push({
source: "Root",
target: name,
value: r.bits_per_second.down,
lineStyle: {
color: capacityColor
}
});
});
this.update(nodes, links);
}
}