summaryrefslogtreecommitdiffstats
path: root/static/status-dnbd3.html
diff options
context:
space:
mode:
authorSimon Rettberg2019-01-29 16:06:26 +0100
committerSimon Rettberg2019-01-29 16:06:26 +0100
commit1e8ef96e022883f056610d55055622fb22016c0c (patch)
treee932d9a1320181e11c264905eaf91babb9dba115 /static/status-dnbd3.html
parentSmall labeling change (diff)
downloaddnbd3-status-1e8ef96e022883f056610d55055622fb22016c0c.tar.gz
dnbd3-status-1e8ef96e022883f056610d55055622fb22016c0c.tar.xz
dnbd3-status-1e8ef96e022883f056610d55055622fb22016c0c.zip
Make colors more good and less bad
Diffstat (limited to 'static/status-dnbd3.html')
-rw-r--r--static/status-dnbd3.html624
1 files changed, 0 insertions, 624 deletions
diff --git a/static/status-dnbd3.html b/static/status-dnbd3.html
deleted file mode 100644
index 0fe1a09..0000000
--- a/static/status-dnbd3.html
+++ /dev/null
@@ -1,624 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<html>
-<head>
- <script src="d3.v3.min.js"></script>
- <script type="text/javascript" src="jquery-1.7.1.min.js"></script>
- <script src="smoothie.js"></script>
- <style type="text/css">
- #graph, #statistics, #traffic {position: absolute }
- .link { stroke-opacity: 0.75; stroke: #56f; }
- .circle { stroke: #56f; stroke-width: 1px; }
- .nodetext { pointer-events: none; font: 10px sans-serif; }
- body { width:100%; height:100%; margin:0; padding:0; overflow: hidden; }
- svg, div, canvas { margin:0; padding:0; }
- </style>
-</head>
-<body>
-<div id="graph"></div>
-<div id="statistics"><div id="debug"></div></div>
-<div> <canvas id="traffic" width="100%" height="150"></canvas></div>
-</body>
-<script type="text/javascript">
-
-// Initialize the statistics chart at the bottom.
-var smoothie = new SmoothieChart({'millisPerPixel': 300, 'grid': {'millisPerLine': 30000}, timestampFormatter:SmoothieChart.timeFormatter, yMaxFormatter: bytesToString, yMinFormatter: bytesToString, valueTransformFunction: logarithmicScaling, minValue: 0, maxValue: 262144000, labels: {fontSize: 13}});
-smoothie.streamTo(document.getElementById("traffic"), 2000);
-
-// For coloring the servers and the chart-lines.
-var colorList = d3.scale.category10();
-
-// Max intensity ~ 50MB/s
-var maxIntensity = 50000;
-
-var pendingLinks = [];
-var intLinks = [];
-var newLinks = [];
-var links = {};
-var nodes = {};
-
-// color for links
-// idle links (blue)
-var idleColor = { "r": 85, "g": 102, "b": 255};
-// active links (green)
-var activeColor = { "r": 0, "g": 230, "b": 20};
-// peaking links (red)
-var peakColor = { "r": 255, "g": 40, "b": 30};
-
-var clusterDirections = [];
-
-// IDs need to begin with a letter.
-function makeId(prefix, text) {
- return prefix + text.replace(/\./g, "-");
-}
-
-// Log scaling for the traffic graph
-function logarithmicScaling(value) {
- return Math.log(value/1000000+1);
-}
-
-function getCluster(ip) {
- var p = ip.split('.', 4);
- var i;
- if (p.length !== 4) return false;
- p = p[0] + '-' + p[1] + '-' + p[2];
- for (i = 0; i < clusterDirections.length; ++i) {
- if (clusterDirections[i].id === p)
- return function() { return clusterDirections[i] };
- }
- clusterDirections.push({'id':p});
- var len = clusterDirections.length;
- var col = len > 10 ? d3.scale.category20() : d3.scale.category10();
- for (i = 0; i < len; ++i) {
- clusterDirections[i].x = Math.sin(2*(i/clusterDirections.length)*3.14159);
- clusterDirections[i].y = Math.cos(2*(i/clusterDirections.length)*3.14159);
- clusterDirections[i].color = col(clusterDirections[i].id);
- }
- i = clusterDirections.length - 1;
- return function() { return clusterDirections[i] };
-}
-
-function myGraph(el) {
- var changed = false;
-
- // Add/update and remove elements on the graph object
- this.updateNode = function (id) {
- var title = id;
- var id = makeId("a", id);
-
- var node = findNode(id);
-
- // Add node, if it doesn't exist
- if (!node) {
- var len = Math.min(5, nodes.length);
- var nx = 0, ny = 0, i;
- if (len > 0) {
- for (i = 0; i < len; ++i) {
- nx += nodes[i].x;
- ny += nodes[i].y;
- }
- nx /= len;
- ny /= len;
- }
- nodes.push(node = {"id": id, "title": title, "x": nx, "y":ny, "cluster":getCluster(title)});
- changed = true;
- } else if (!node.isServer && servers[title]) {
- node.isServer = true;
- node.cluster = false;
- node.color = servers[title].color;
- // Change color and radius if server.
- var visNode = vis.select("#" + id);
- if (visNode) {
- visNode.select("circle")
- .attr("r", 15)
- .style("stroke-width", "3px");
- }
- }
- node.lifetime = 2;
- }
-
- // Remove nodes/edges that haven't reported for a while.
- this.decay = function () {
- for (var i = nodes.length - 1; i >= 0; --i) {
- if ( nodes[i].lifetime <= 0 ) {
- for (var j = links.length - 1; j >= 0; --j) {
- if ((links[j].source === nodes[i]) || (links[j].target === nodes[i])) links.splice(j,1);
- }
- nodes.splice(i, 1);
- changed = true;
- continue;
- }
- nodes[i].lifetime--;
- }
- for (var i = links.length - 1; i >= 0; --i) {
- if (links[i].lifetime <= 0) {
- links.splice(i, 1);
- changed = true;
- continue;
- }
- links[i].lifetime--;
- }
- }
-
- // Add/update links in the graph
- this.updateLink = function (edge, timestamp) {
- var sourceId = edge.source;
- var targetId = edge.target;
- var width = '2.5px';
-
- // Change color to red for links between servers
- if (servers[sourceId] && servers[targetId]) width = '3.5px';
-
- sourceId = makeId("a", sourceId);
- targetId = makeId("a", targetId);
- var sourceNode = findNode(sourceId);
- var targetNode = findNode(targetId);
-
- if ((typeof(sourceNode) !== 'undefined') && (typeof(targetNode) !== 'undefined')) {
- var link = findLink(sourceNode, targetNode);
- // Add non existing links
- if (!link) {
- var index = $.inArray(sourceId + targetId, pendingLinks);
- if (index !== -1) {
- links.push({"id": sourceId + "-" + targetId ,"source": sourceNode, "target": targetNode, "lifetime":2, "color": idleColor, "downloadRate" : 0, "lastReceived": 0, "lastTimestamp": 0, "lastUptime": 0, "colorIntensity": 0, "width": width });
- changed = true;
- } else {
- newLinks.push(sourceId + targetId);
- }
- } else {
- link.lifetime = 2;
-
- // Calculate download rate for clients and color links.
- if (link.lastTimestamp != 0) {
- if(timestamp - lastTime > 0) {
- // Download rate in KB/s
- link.downloadRate = ((edge.received - link.lastReceived) / (timestamp - lastTime)) * 4 * 1000;
- // Clients may have multiple connections with different received data -> prevent negative download rate...
- if(link.downloadRate < 0) link.downloadRate = 0;
-
- // only need fiddle with colors if needed.
- if (link.downloadRate > 0) {
- increasColorIntensity(link);
- colorLink(link);
- updateLinkColor(link);
- }
- }
- } else {
- link['downloadRate'] = 0;
- }
- link['lastReceived'] = edge.received;
- link['lastTimestamp'] = timestamp;
- }
- }
- }
-
- // Color a link according to its intensity, does not apply the color in the svg! Use updateLinkColor function for that.
- function colorLink(link) {
- var red, green, blue;
- // Green colors between 0 - 1 MB/s
- if( link.colorIntensity <= 1000 ) {
- // Blending idle (blue) and active (green) color
- var factor = link.colorIntensity / 1000;
- var cFactor = 1 - factor;
-
- red = Math.sqrt(cFactor * Math.pow(idleColor.r, 2) + factor * Math.pow(activeColor.r, 2));
- green = Math.sqrt(cFactor * Math.pow(idleColor.g, 2) + factor * Math.pow(activeColor.g, 2));
- blue = Math.sqrt(cFactor * Math.pow(idleColor.b, 2) + factor * Math.pow(activeColor.b, 2));
-
- } else { // Red over 1MB/s
- // Blending active (green) and peak (red) color
- var factor = (link.colorIntensity - 1000)/ (maxIntensity - 1000);
- var cFactor = 1 - factor;
-
- red = Math.sqrt(cFactor * Math.pow(activeColor.r, 2) + factor * Math.pow(peakColor.r, 2));
- green = Math.sqrt(cFactor * Math.pow(activeColor.g, 2) + factor * Math.pow(peakColor.g, 2));
- blue = Math.sqrt(cFactor * Math.pow(activeColor.b, 2) + factor * Math.pow(peakColor.b, 2));
- }
- link.color = "rgb("+ Math.floor(red) + ", " + Math.floor(green) + ", " + Math.floor(blue) + ")";
- }
-
- // Update the color of a link in the svg.
- function updateLinkColor(link) {
- // Prevent future searches for links to improve performance.
- if(!link.visObject) {
- link.visObject = vis.select("#" + link.source.id + "-" + link.target.id);
- }
- var visLink = link.visObject;
- visLink.style({stroke: function(d) { return d.color; }});
- }
-
- // Interval for fading out the color of active links
- function decayLinkColor() {
- for (var i = 0; i < links.length ; i++) {
- var link = links[i];
- // Do nothing if there is no intensity to decay.
- if(link.colorIntensity > 0) {
- // Fading rate of colored links
- var fadingValue = (link.colorIntensity * 0.15) + 10;
- link.colorIntensity -= fadingValue;
- if (link.colorIntensity < 0) {
- link.colorIntensity = 0;
- } else if (link.colorIntensity < link.downloadRate) {
- link.colorIntensity = link.downloadRate;
- }
- colorLink(link);
- updateLinkColor(link);
- }
- }
- }
- window.setInterval(decayLinkColor, 500);
- window.setInterval(function() {
- if (force.alpha() == 0) {
- force.alpha(0.015);
- force.tick();
- force.stop();
- }
- }, 125);
-
-
- // Set the color intensity of link according to its download rate.
- function increasColorIntensity(link) {
- if (link.colorIntensity < link.downloadRate) {
- link.colorIntensity = link.downloadRate;
- }
- if (link.colorIntensity >= maxIntensity) {
- link.colorIntensity = maxIntensity;
- }
- }
-
- function findLink(sourceId, targetId) {
- for (var i = 0; i < links.length; ++i) {
- if ( (links[i].source === sourceId && links[i].target === targetId)
- || (links[i].source === targetId && links[i].target === sourceId) )
- return links[i];
- }
- }
-
- var findNode = function (id) {
- for (var i = 0; i < nodes.length; i++) {
- if (nodes[i].id === id)
- return nodes[i];
- }
- }
-
-
- var findNodeIndex = function (id) {
- for (var i=0; i < nodes.length; i++) {
- if (nodes[i].id === id)
- return i;
- };
- }
-
- var w = 100, h = 100;
- var lastW = -1, lastH = -1;
-
- var updateBounds = function() {
- var width = window.innerWidth;
- // Chart needs to fit under the graph and the statistics
- h = window.innerHeight - 150;
- // Width for the graph and the statistics div
- w = width/3*2;
- if (lastW === w && lastH === h) return;
- lastW = w;
- lastH = h;
- vis.attr("width", w);
- vis.attr("height", h);
- force.size([w, h]);
- $(el).attr("width", w);
- $(el).attr("height", h);
- // Positions for statistics and the traffic graph
- $("#statistics").attr("width", w/2).css("width", w/2 + "px").css("left", w + "px");
- $("#statistics").attr("height", h).css("height", h + "px");
- $("#traffic").attr("width", width).css("top", h + "px");
- }
-
- var vis = this.vis = d3.select(el).append("svg:svg")
- .attr("width", w)
- .attr("height", h);
-
- // Settings for movement of the graph
- var force = d3.layout.force()
- // Force of center gravitation
- .gravity(.12)
- // Desired distance of the links
- .distance(function(bla) { if (bla.source.isServer && bla.target.isServer) return 10; return 4; })
- // Strength of the links (how strongly the distance is enforced) (0-1)
- .linkStrength(0.5)
- // Force with which all nodes attract each other
- .charge(function(bla) { return bla.isServer ? -3.5 : -0.9; })
- // Friction for the graph nodes
- .friction(0.4)
- .theta(0.75)
- .size([w, h]);
-
- nodes = force.nodes();
- links = force.links();
-
-
- var updateCounter = 0;
- this.update = function () {
- if(changed) {
- update();
- }
- if (++updateCounter < 10) force.alpha(force.alpha() + 0.05);
- }
-
- // Update the complete svg.
- var svgNodes = [];
- var svgLinks = [];
- function update() {
- changed = false;
-
- svgNodes = vis.selectAll("g.node")
- .data(nodes, function(d) { return d.id; });
-
- var nodeEnter = svgNodes.enter().append("g")
- .attr("class", "node")
- .attr("id", function(d) { return d.id; })
- .on("mouseover", function(d) {
- // Highlight statistics div
- var statDiv = document.getElementById(makeId("b", d.title));
- if (statDiv){
- statDiv.setAttribute("style", "background-color:blue; color:white;");
- }
-
- // Increase line width of server in traffic chart
- var s = servers[d.title];
- if (!s) return;
- smoothie.seriesSet[s.index].options.lineWidth = 4;
- })
- .on("mouseout", function(d) {
- // Make statistics div normal again
- var statDiv = document.getElementById(makeId("b", d.title));
- if (statDiv){
- statDiv.setAttribute("style", "background-color:white; color:black;");
- }
-
- // Reset line width
- var s = servers[d.title];
- if (!s) return;
- smoothie.seriesSet[s.index].options.lineWidth = 2;
- });
-
- nodeEnter.append("circle")
- .attr("class", "circle")
- .attr("r", 4);
-
- nodeEnter.append("text")
- .attr("class", "nodetext")
- .attr("dx", -32)
- .attr("dy", "-1em")
- .text(function(d) {return d.title});
-
- svgNodes.exit().remove();
-
- svgLinks = vis.selectAll("line.link")
- .data(links, function(d) { return d.source.id + "-" + d.target.id; });
-
- svgLinks.enter().insert("line")
- .attr("class", "link")
- .attr("id", function(d) {return d.id; })
- .style({stroke: function(d) { return d.color }, "stroke-width": function(d) { return d.width } });
-
- svgLinks.exit().remove();
-
- // Put all nodes on top again by adding them again
- var jGraph = $('#graph').find('svg');
- vis.selectAll('g.node').forEach(function(e){jGraph.append(e)});
- svgNodes.selectAll('circle').style({ "fill": function(d) { return d.color ? d.color : d.cluster().color } });
-
- force.on("tick", renderTick);
-
- updateBounds();
- force.start();
- }
-
- var lastScale = false;
- // Render function
- function renderTick(e) {
- var k = 1 * e.alpha;
- nodes.forEach(function(o, i) {
- if (typeof(o.cluster) === 'function') {
- var c = o.cluster();
- o.x += k * c.x;
- o.y += k * c.y;
- }
- });
- var lx = 1000000, ly = 1000000, ux = -1000000, uy = -1000000;
- for (var i = 0; i < links.length; ++i) { // Use links not nodes so we ignore orphans
- if (links[i].source.x < lx) lx = links[i].source.x;
- if (links[i].source.x > ux) ux = links[i].source.x;
- if (links[i].source.y < ly) ly = links[i].source.y;
- if (links[i].source.y > uy) uy = links[i].source.y;
- if (links[i].target.x < lx) lx = links[i].target.x;
- if (links[i].target.x > ux) ux = links[i].target.x;
- if (links[i].target.y < ly) ly = links[i].target.y;
- if (links[i].target.y > uy) uy = links[i].target.y;
- }
- var width = (ux - lx), height = (uy - ly);
- var desiredScale;
- var offX = 0, offY = 0;
- if ( (width / w) > (height / h) ) {
- desiredScale = (w - 40) / width;
- } else {
- desiredScale = (h - 40) / height;
- }
- if (lastScale === false) lastScale = desiredScale;
- var absDiff = Math.abs(desiredScale - lastScale);
-
- var newScale = desiredScale;
- if (false) {
- newScale = desiredScale;
- } else if (desiredScale < lastScale) {
- newScale = Math.min(lastScale * 0.99, lastScale - absDiff * 0.001);
- if (newScale < desiredScale) newScale = desiredScale;
- } else if (desiredScale > lastScale) {
- newScale = Math.max(lastScale * 1.01, lastScale + absDiff * 0.001);
- if (newScale > desiredScale) newScale = desiredScale;
- }
- lastScale = newScale;
- if ( (width / w) > (height / h) ) {
- offY = (h - (height * newScale + 20)) / 2;
- } else {
- offX = (w - (width * newScale + 20)) / 2;
- }
-
- var fixX = function(x) {
- return (x - lx) * newScale + 20 + offX;
- }
- var fixY = function(y) {
- return (y - ly) * newScale + 20 + offY;
- }
- svgLinks.attr("x1", function(d) { return fixX(d.source.x); })
- .attr("y1", function(d) { return fixY(d.source.y); })
- .attr("x2", function(d) { return fixX(d.target.x); })
- .attr("y2", function(d) { return fixY(d.target.y); });
-
- svgNodes.attr("transform", function(d) {
- return "translate(" + fixX(d.x) + "," + fixY(d.y) + ")";
- });
- };
-
- window.onresize = update;
- update();
-}
-
-graph = new myGraph("#graph");
-
-var servers = {};
-var serverCount = 0;
-var lastTime = 0;
-
-// Get new data
-setInterval( function() {
- $.get('/data.json', function(data) {
- if (data.timestamp < lastTime) lastTime = data.timestamp;
- if(data.timestamp === lastTime) return;
- var g = data.graph;
- var stats = data.servers;
- updateGraph(g, data);
- // updateTrafficGraph has to be called before updateTextStatistics to populate servers
- updateTrafficGraph(stats, data);
- updateTextStatistics(stats);
- lastTime = data.timestamp;
-}, 'json').always(function() {
- graph.decay();
- graph.update();
- });
-}, 2000);
-
-
-// Update data of the graph
-function updateGraph(g, data) {
- if (g) {
- for (var i = 0; i < g.nodes.length; ++i) {
- graph.updateNode(g.nodes[i].name);
- }
- for (var i = 0; i < g.edges.length; ++i) {
- graph.updateLink(g.edges[i], data.timestamp);
- }
- pendingLinks = intLinks;
- intLinks = newLinks;
- newLinks = [];
- }
-}
-
-
-// Convert bytes to GiB or TiB and return a string in form "10,23 GiB"
-function bytesToString( bytes ) {
- var convertedValue;
- var unit;
- if (bytes >= 1099511627776 ) {
- convertedValue = Math.round( (bytes / 1099511627776) * 100 ) / 100 ;
- unit = " TiB";
- } else if (bytes >= 1073741824 ) {
- convertedValue = Math.round( (bytes / 1073741824) * 100 ) / 100 ;
- unit = " GiB";
- } else if (bytes >= 1048576 ) {
- convertedValue = Math.round( (bytes / 1048576) * 100 ) / 100 ;
- unit = " MiB";
- } else if ( bytes >= 1024 ) {
- convertedValue = Math.round( (bytes / 1024) * 100 ) / 100 ;
- unit = " KiB";
- } else {
- convertedValue = Math.round(bytes);
- unit = " B";
- }
- return convertedValue + unit;
-}
-
-// Update data of the statistics divs
-function updateTextStatistics(stats) {
- var glob = $('#gstats');
- if (glob.length === 0) {
- $('#statistics').append('<div id="gstats"></div>');
- glob = $('#gstats');
- }
- glob.html('<p><b>Global</b><br>'
- + 'Upload: ' + bytesToString(globalUploadRate) + '/s<br>'
- + 'Upload Peak: ' + bytesToString(globalUploadMax) + '/s<p>');
- if (stats) {
- for (var i = 0; i < stats.length; ++i) {
- var divId = makeId("b", stats[i].address);
- var server = $('#' + divId);
- if (server.length === 0) {
- $("#statistics").append('<div id="' + makeId ("b", stats[i].address) + '"></div>');
- server = $("#" + divId);
- }
-
- var upload = servers[stats[i].address].uploadRate;
- upload = upload ? upload : 0;
- // Generate the HTML string
- server.html( "<p><b> Server: " + stats[i].address + "</b><br>"
- + "Number of clients: "
- + stats[i].clientCount + "<br>"
- + "uptime: " + Math.floor(stats[i].uptime / (3600 * 24)) + "d "
- + Math.floor(stats[i].uptime / 3600) % 24 + "h " + Math.floor((stats[i].uptime) / 60) % 60 + "min" + "<br>"
- + "Sent: " + bytesToString(stats[i].bytesSent) + "<br>"
- + "Received: " + bytesToString(stats[i].bytesReceived) + "<br>"
- + "Upload: " + bytesToString(servers[stats[i].address].uploadRate) + "/s<br>"
- + "Upload Peak: " + bytesToString(servers[stats[i].address].uploadPeak) + "/s" + "</p>"
- );
- }
- }
-}
-
-var globalUploadRate = 0, globalUploadMax = 0;
-
-// Update the traffic graph
-function updateTrafficGraph(stats, data) {
- if (stats) {
- globalUploadRate = 0;
- for (var i = 0; i < stats.length; ++i) {
- var server = servers[stats[i].address];
- if (!server) {
- servers[stats[i].address] = server = { 'lastUptime': 0, 'lastTimestamp': 0, 'lastSent': 0, 'line': new TimeSeries({logarithmicScale: true}), 'index': serverCount++ , 'uploadRate': 0, 'downloadRate': 0, 'uploadPeak': 0 }
- server.color = colorList(stats[i].address);
- smoothie.addTimeSeries(server['line'], {lineWidth:2, strokeStyle: server.color});
- }
- // Server seems to have rebootet, redo values but add no point to chart.
- if (server['lastUptime'] > stats[i].uptime) {
- server['lastUptime'] = 0;
- }
-
- // Add points to graph and set the upload rate for the statistics
- if (server['lastUptime'] != 0) {
- // Upload rate in bytes/s
- server['uploadRate'] = (stats[i].bytesSent - server['lastSent'])/(stats[i].timestamp - server.lastTimestamp) * 1000;
- if (server['uploadRate'] > server['uploadPeak']) server['uploadPeak'] = server['uploadRate'];
- // Rate in MiB/s
- server['line'].append(new Date().getTime(), server['uploadRate']);
- } else {
- server['uploadRate'] = 0;
- }
-
- server['lastUptime'] = stats[i].uptime;
- server['lastSent'] = stats[i].bytesSent;
- server['lastTimestamp'] = stats[i].timestamp;
- globalUploadRate += server['uploadRate'];
- }
- if (globalUploadRate > globalUploadMax) globalUploadMax = globalUploadRate;
- }
-}
-
-</script>