Recently i’d been looking for a better interface for displaying multiple server stats.
Low and behold i found one created by Square payments.
Here’s what this thing looks like
Their project and examples can be found here:
http://square.github.com/cubism/
I’m going to assume you have an apache server and graphite server running somewhere.
So here’s a small example of how to get this going and your metrics plotting.
It’s pretty much an html file with some javascript
Create an new html file in your apache docroot with the following information ( usually /var/www/ in most ubuntu systems )
1. Put in your page title and some css includes and js includes
Alot of this is going to pull the css and js source directly from Square’s page.
I would recommend you download these files and copy them locally for your own use and serving them from apache yourself.
<meta charset="utf-8" /> Cubism.js</pre> <style> @import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,700); @import url(//square.github.com/cubism/style.css); </style> <div id="body"> <h2>Host01 Load Average</h2> <div id="graphs"></div> <script type="text/javascript" src="http://d3js.org/d3.v2.js"></script> <script type="text/javascript" src="http://square.github.com/cubism/cubism.v1.js"></script> <script type="text/javascript" src="http://square.github.com/cubism/highlight.min.js"></script> <script type="text/javascript"> {font-family:arial,helvettica,sans-serif"} </script>
2. Setup some cubism settings.
Set the time granularity with the “.step” setting
Set the number of metrics you want to display with the “.size” setting
<script type="text/javascript"> var context = cubism.context() .step( 1 * 60 * 1000 ) // 1 minute .size(960); // 1 * 960 = 4 hours
Setup more cubism graphite settings
Set the address of your graphite webserver at the “context.graphite”
Set the height of each row of metric data at “.height”
Set the time shift of how many days you want to go back at “.shift”, like you want to see data from 7 days ago.
var graphite = context.graphite("http://graphite-server.foo-bar.net"); var horizon = context.horizon().metric(graphite.metric).height(100).shift( - 0 * 24 * 60 * 60 * 1000 );
Create a list of metrics you want to see in an array
var metrics = [ 'stats.host01.cpu.load.load', 'stats.host02.cpu.load.load', 'nonNegativeDerivative(stats.host02.network.eth0.interface_tx_bytes)' ]
Call d3 and apply a bunch of stuff to the div with the id=graphs
d3.select("#graphs").append("div") .attr("class", "axis") .call(context.axis().orient("top")); d3.select("#graphs").append("div") .attr("class", "rule") .call(context.rule()); d3.select("#graphs").selectAll(".horizon") .data(metrics) .enter().append("div") .attr("class", "horizon") .call(horizon); </script>
Put it all together
The fully constructed HTML file should look something like this
<meta charset="utf-8" /> Cubism.js</pre> <style> @import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,700); @import url(//square.github.com/cubism/style.css); </style> <div id="body"> <h2>Host01 Load Average</h2> <div id="graphs"></div> <script type="text/javascript" src="http://d3js.org/d3.v2.js"></script> <script type="text/javascript" src="http://square.github.com/cubism/cubism.v1.js"></script> <script type="text/javascript" src="http://square.github.com/cubism/highlight.min.js"></script> <script type="text/javascript"> {font-family:arial,helvettica,sans-serif"} </script> <script type="text/javascript"> var context = cubism.context() .step( 1 * 60 * 1000 ) // 1 minute .size(960); // 1 * 960 = 4 hours var graphite = context.graphite("http://graphite-server.foo-bar.net"); var horizon = context.horizon().metric(graphite.metric).height(100).shift( - 0 * 24 * 60 * 60 * 1000 ); var metrics = [ 'stats.host01.cpu.load.load', 'stats.host02.cpu.load.load', 'nonNegativeDerivative(stats.host02.network.eth0.interface_tx_bytes)' ] d3.select("#graphs").append("div") .attr("class", "axis") .call(context.axis().orient("top")); d3.select("#graphs").append("div") .attr("class", "rule") .call(context.rule()); d3.select("#graphs").selectAll(".horizon") .data(metrics) .enter().append("div") .attr("class", "horizon") .call(horizon); </script>
A more complicated example using graphite.find function
<meta charset="utf-8" /> Cubism.js</pre> <style> @import url(//fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,700); @import url(http://square.github.com/cubism/style.css); </style> <div id="body"> <h2>Host01 Load Average</h2> <div id="graphs"></div> <script type="text/javascript" src="http://d3js.org/d3.v2.js"></script> <script type="text/javascript" src="http://square.github.com/cubism/cubism.v1.js"></script> <script type="text/javascript" src="http://square.github.com/cubism/highlight.min.js"></script> <script type="text/javascript"> {font-family:arial,helvettica,sans-serif"} </script> <script type="text/javascript"> var context = cubism.context() .step( 1 * 60 * 1000 ) // 1 minute .size(960); // 1 * 960 = 4 hours var graphite = context.graphite("http://graphite-server.foo-bar.net"); //////// Example: 'stats.host*.cpu.load.load' graphFind = 'stats.host0*.network.eth*.interface_*_bytes' // Set The Time Row on Top d3.select("#graphs").append("div") .attr("class", "axis") .call(context.axis().orient("top")); // Set the Vertical Line Bar d3.select("#graphs").append("div") .attr("class", "rule") .call(context.rule()); graphite.find(graphFind, function(error, results) { // Map find results to array and set to graphite.metric object type var metrics = results.sort().map(function(i) { return graphite.metric(i); //// return it as a nonNegativeDerivative // return graphite.metric('nonNegativeDerivative('+i+')'); }); // loop through array and print stuff to "graphs" div and apply .height and .colors to object for (var i=0;i<metrics.length;i++){ d3.select("#graphs").call(function(div) { div.append("div").selectAll(".horizon") .data([metrics[i]]) .enter().append("div") .attr("class", "horizon") .call(context.horizon() .height(100) .colors(["#08519c","#3182bd","#6baed6","#bdd7e7","#bae4b3","#74c476","#31a354","#006d2c"]) ); }); } // Set The Time Row on Bottom d3.select("#graphs").append("div") .attr("class", "axis") .call(context.axis().orient("bottom")); }); </script>