mirror of
https://github.com/LibreQoE/LibreQoS.git
synced 2025-02-25 18:55:32 -06:00
Initial tree and circuit capacity dashlet displays. Quite Ugly.
This commit is contained in:
parent
afda5d3bdf
commit
9248ae469b
@ -0,0 +1,75 @@
|
|||||||
|
import {BaseDashlet} from "./base_dashlet";
|
||||||
|
import {clearDashDiv, simpleRow, simpleRowHtml, theading} from "../helpers/builders";
|
||||||
|
import {scaleNumber, scaleNanos, formatRtt} from "../helpers/scaling";
|
||||||
|
import {redactCell} from "../helpers/redact";
|
||||||
|
|
||||||
|
export class CircuitCapacityDash extends BaseDashlet {
|
||||||
|
constructor(slot) {
|
||||||
|
super(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
title() {
|
||||||
|
return "Circuits At Capacity";
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip() {
|
||||||
|
return "<h5>Circuits at Capacity</h5><p>Customer circuits using close to their maximum capacities, and possibly in need of an upsell.</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeTo() {
|
||||||
|
return [ "CircuitCapacity" ];
|
||||||
|
}
|
||||||
|
|
||||||
|
buildContainer() {
|
||||||
|
let base = super.buildContainer();
|
||||||
|
base.style.height = "250px";
|
||||||
|
base.style.overflow = "auto";
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(msg) {
|
||||||
|
if (msg.event === "CircuitCapacity") {
|
||||||
|
let target = document.getElementById(this.id);
|
||||||
|
|
||||||
|
let table = document.createElement("table");
|
||||||
|
table.classList.add("table", "table-striped", "small");
|
||||||
|
let thead = document.createElement("thead");
|
||||||
|
thead.classList.add("small");
|
||||||
|
thead.appendChild(theading("Circuit"));
|
||||||
|
thead.appendChild(theading("% Utilization (DL)"));
|
||||||
|
thead.appendChild(theading("% Utilization (UL)"));
|
||||||
|
thead.appendChild(theading("RTT"));
|
||||||
|
table.appendChild(thead);
|
||||||
|
let tbody = document.createElement("tbody");
|
||||||
|
msg.data.forEach((c) => {
|
||||||
|
if (c.capacity[0] < 0.9 && c.capacity[1] < 0.9) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let row = document.createElement("tr");
|
||||||
|
row.classList.add("small");
|
||||||
|
|
||||||
|
let linkCol = document.createElement("td");
|
||||||
|
let link = document.createElement("a");
|
||||||
|
link.href = "circuit.html?id=" + encodeURI(c.circuit_id);
|
||||||
|
link.innerText = c.circuit_name;
|
||||||
|
redactCell(link);
|
||||||
|
linkCol.appendChild(link);
|
||||||
|
row.appendChild(linkCol);
|
||||||
|
|
||||||
|
row.appendChild(simpleRow((c.capacity[0]*100).toFixed(0)));
|
||||||
|
row.appendChild(simpleRow((c.capacity[1]*100).toFixed(0)));
|
||||||
|
row.appendChild(simpleRowHtml(formatRtt(c.rtt)));
|
||||||
|
tbody.appendChild(row);
|
||||||
|
})
|
||||||
|
table.appendChild(tbody);
|
||||||
|
|
||||||
|
// Display it
|
||||||
|
clearDashDiv(this.id, target);
|
||||||
|
target.appendChild(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,8 @@ import {TopTreeSummary} from "./top_tree_summary";
|
|||||||
import {CombinedTopDashlet} from "./combined_top_dash";
|
import {CombinedTopDashlet} from "./combined_top_dash";
|
||||||
import {RttHisto3dDash} from "./rtt_histo3d_dash";
|
import {RttHisto3dDash} from "./rtt_histo3d_dash";
|
||||||
import {QueueStatsTotalDash} from "./queue_stats_total";
|
import {QueueStatsTotalDash} from "./queue_stats_total";
|
||||||
|
import {TreeCapacityDash} from "./tree_capacity_dash";
|
||||||
|
import {CircuitCapacityDash} from "./circuit_capacity_dash";
|
||||||
|
|
||||||
export const DashletMenu = [
|
export const DashletMenu = [
|
||||||
{ name: "Throughput Bits/Second", tag: "throughputBps", size: 3 },
|
{ name: "Throughput Bits/Second", tag: "throughputBps", size: 3 },
|
||||||
@ -40,6 +42,8 @@ export const DashletMenu = [
|
|||||||
{ name: "Combined Top 10 Box", tag: "combinedTop10", size: 3 },
|
{ name: "Combined Top 10 Box", tag: "combinedTop10", size: 3 },
|
||||||
{ name: "Total Cake Stats", tag: "totalCakeStats", size: 3 },
|
{ name: "Total Cake Stats", tag: "totalCakeStats", size: 3 },
|
||||||
{ name: "Round-Trip Time Histogram 3D", tag: "rttHistogram3D", size: 12 },
|
{ name: "Round-Trip Time Histogram 3D", tag: "rttHistogram3D", size: 12 },
|
||||||
|
{ name: "Circuits At Capacity", tag: "circuitCapacity", size: 6 },
|
||||||
|
{ name: "Tree Nodes At Capacity", tag: "treeCapacity", size: 6 },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function widgetFactory(widgetName, count) {
|
export function widgetFactory(widgetName, count) {
|
||||||
@ -65,6 +69,8 @@ export function widgetFactory(widgetName, count) {
|
|||||||
case "treeSummary" : widget = new TopTreeSummary(count); break;
|
case "treeSummary" : widget = new TopTreeSummary(count); break;
|
||||||
case "combinedTop10" : widget = new CombinedTopDashlet(count); break;
|
case "combinedTop10" : widget = new CombinedTopDashlet(count); break;
|
||||||
case "totalCakeStats" : widget = new QueueStatsTotalDash(count); break;
|
case "totalCakeStats" : widget = new QueueStatsTotalDash(count); break;
|
||||||
|
case "circuitCapacity" : widget = new CircuitCapacityDash(count); break;
|
||||||
|
case "treeCapacity" : widget = new TreeCapacityDash(count); break;
|
||||||
default: {
|
default: {
|
||||||
console.log("I don't know how to construct a widget of type [" + widgetName + "]");
|
console.log("I don't know how to construct a widget of type [" + widgetName + "]");
|
||||||
return null;
|
return null;
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
import {BaseDashlet} from "./base_dashlet";
|
||||||
|
import {clearDashDiv, simpleRow, simpleRowHtml, theading} from "../helpers/builders";
|
||||||
|
import {scaleNumber, scaleNanos, formatRtt} from "../helpers/scaling";
|
||||||
|
|
||||||
|
export class TreeCapacityDash extends BaseDashlet {
|
||||||
|
constructor(slot) {
|
||||||
|
super(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
title() {
|
||||||
|
return "Tree Nodes At Capacity";
|
||||||
|
}
|
||||||
|
|
||||||
|
tooltip() {
|
||||||
|
return "<h5>Tree Nodes at Capacity</h5><p>Distribution Nodes approaching their maximum capacity, possibly in need of an upgrade or a better shaping policy.</p>";
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribeTo() {
|
||||||
|
return [ "TreeCapacity" ];
|
||||||
|
}
|
||||||
|
|
||||||
|
buildContainer() {
|
||||||
|
let base = super.buildContainer();
|
||||||
|
base.style.height = "250px";
|
||||||
|
base.style.overflow = "auto";
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
onMessage(msg) {
|
||||||
|
if (msg.event === "TreeCapacity") {
|
||||||
|
//console.log(msg.data);
|
||||||
|
let target = document.getElementById(this.id);
|
||||||
|
|
||||||
|
let table = document.createElement("table");
|
||||||
|
table.classList.add("table", "table-striped", "small");
|
||||||
|
let thead = document.createElement("thead");
|
||||||
|
thead.classList.add("small");
|
||||||
|
thead.appendChild(theading("Node"));
|
||||||
|
thead.appendChild(theading("% Utilization (DL)"));
|
||||||
|
thead.appendChild(theading("% Utilization (UL)"));
|
||||||
|
thead.appendChild(theading("RTT"));
|
||||||
|
table.appendChild(thead);
|
||||||
|
let tbody = document.createElement("tbody");
|
||||||
|
|
||||||
|
msg.data.forEach((node) => {
|
||||||
|
if (node.max_down === 0 || node.max_up === 0) {
|
||||||
|
// No divisions by zero
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let down = node.down / node.max_down;
|
||||||
|
let up = node.up / node.max_up;
|
||||||
|
|
||||||
|
if (down < 0.75 && up < 0.75) {
|
||||||
|
// Not at capacity
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let row = document.createElement("tr");
|
||||||
|
row.classList.add("small");
|
||||||
|
|
||||||
|
row.appendChild(simpleRow(node.name));
|
||||||
|
row.appendChild(simpleRow((down*100).toFixed(0)));
|
||||||
|
row.appendChild(simpleRow((up*100).toFixed(0)));
|
||||||
|
row.appendChild(simpleRowHtml(formatRtt(node.rtt)));
|
||||||
|
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
table.appendChild(tbody);
|
||||||
|
|
||||||
|
// Display it
|
||||||
|
clearDashDiv(this.id, target);
|
||||||
|
target.appendChild(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,13 +33,13 @@ pub async fn circuit_capacity(channels: Arc<PubSub>) {
|
|||||||
THROUGHPUT_TRACKER.raw_data.iter().for_each(|c| {
|
THROUGHPUT_TRACKER.raw_data.iter().for_each(|c| {
|
||||||
if let Some(circuit_id) = &c.circuit_id {
|
if let Some(circuit_id) = &c.circuit_id {
|
||||||
if let Some(accumulator) = circuits.get_mut(circuit_id) {
|
if let Some(accumulator) = circuits.get_mut(circuit_id) {
|
||||||
accumulator.bytes += c.bytes;
|
accumulator.bytes += c.bytes_per_second;
|
||||||
if let Some(latency) = c.median_latency() {
|
if let Some(latency) = c.median_latency() {
|
||||||
accumulator.median_rtt = latency;
|
accumulator.median_rtt = latency;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
circuits.insert(circuit_id.clone(), CircuitAccumulator {
|
circuits.insert(circuit_id.clone(), CircuitAccumulator {
|
||||||
bytes: c.bytes,
|
bytes: c.bytes_per_second,
|
||||||
median_rtt: c.median_latency().unwrap_or(0.0),
|
median_rtt: c.median_latency().unwrap_or(0.0),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -51,9 +51,9 @@ pub async fn circuit_capacity(channels: Arc<PubSub>) {
|
|||||||
let shaped_devices = SHAPED_DEVICES.read().unwrap();
|
let shaped_devices = SHAPED_DEVICES.read().unwrap();
|
||||||
circuits.iter().filter_map(|(circuit_id, accumulator)| {
|
circuits.iter().filter_map(|(circuit_id, accumulator)| {
|
||||||
if let Some(device) = shaped_devices.devices.iter().find(|sd| sd.circuit_id == *circuit_id) {
|
if let Some(device) = shaped_devices.devices.iter().find(|sd| sd.circuit_id == *circuit_id) {
|
||||||
let down_mbps = accumulator.bytes.down as f64 * 8.0 / 1_000_000.0;
|
let down_mbps = (accumulator.bytes.down as f64 * 8.0) / 1_000_000.0;
|
||||||
let down = down_mbps / device.download_max_mbps as f64;
|
let down = down_mbps / device.download_max_mbps as f64;
|
||||||
let up_mbps = accumulator.bytes.up as f64 * 8.0 / 1_000_000.0;
|
let up_mbps = (accumulator.bytes.up as f64 * 8.0) / 1_000_000.0;
|
||||||
let up = up_mbps / device.upload_max_mbps as f64;
|
let up = up_mbps / device.upload_max_mbps as f64;
|
||||||
|
|
||||||
Some(Capacity {
|
Some(Capacity {
|
||||||
|
Loading…
Reference in New Issue
Block a user