Even though Splunk has advanced charting and visualization capabilities, sometimes you might want to use third-party tools to display your data. For example, you might set up a website with Google Charts.
This example performs a simple Splunk search (using exec_mode=oneshot
for simplicity), and presents the results using Google Charts. The result format that Splunk provides is very similar to what Google Charts expects. So, with just a little data massaging, you can have a chart up and running in no time.
var http = new splunkjs.ProxyHttp("/proxy"); service = new splunkjs.Service(http, { scheme: scheme, host: host, port: port, username: username, password: password, version: version }); var drawChart = function(rows) { var chart = new google.visualization.ComboChart(document.getElementById('google-container')); var data = google.visualization.arrayToDataTable(rows); var options = { title : 'HTTP Status Codes For Every 10 Minutes on Splunkd', vAxis: {title: "Count", logScale: true}, hAxis: {title: "Time"}, seriesType: "bars", isStacked: false }; chart.draw(data, options); }; // First, we log in service.login(function(err, success) { // We check for both errors in the connection as well // as if the login itself failed. if (err || !success) { console.log("Error in logging in"); done(err || "Login failed"); return; } // OK, we're logged in, let's do a oneshot search and just // get the results var query = "" + 'search index=_internal sourcetype=splunkd* | head 10000 | bucket span=10m _time | eval formatted_time=strftime(_time, "%D %H:%M") | chart count over formatted_time by status usenull=f'; service.oneshotSearch(query, {}, function(err, results) { if (err) { console.log(err); alert("An error occurred with the search"); return; } // The format Google Charts needs data in is very similar to ours - we just // need to put the field headers in the same array, and convert the strings // into numbers. var rows = results.rows.slice(); var fields = results.fields.slice(); var timeIndex = utils.indexOf(fields, "formatted_time"); for(var i = 0; i < rows.length; i++) { var row = rows[i]; for(var j = 0; j < row.length; j++) { // Don't change the time field if (j !== timeIndex) { row[j] = parseInt(row[j]); } } } // Add the headers in rows.unshift(results.fields); drawChart(rows); }); });
Rickshaw is a time-series visualization library built by the excellent folks over at Shutterstock. This library is built on the immensely powerful d3 library, and exposes a lot of the raw power of d3 in a user-friendly way.
Much like the Google Charts example, this example shows how to create a simple line graph from a Splunk search. This graph shows the HTTP status codes broken down by minute, as observed by splunkd.
This might look like a lot of code, but most of it is for setting up the Rickshaw graph—so have no fear!
Note: This example doesn't work in Internet Explorer 9 or earlier, due to browser limitations.
var http = new splunkjs.ProxyHttp("/proxy"); service = new splunkjs.Service(http, { scheme: scheme, host: host, port: port, username: username, password: password, version: version }); var palette = new Rickshaw.Color.Palette( { scheme: 'httpStatus' } ); var transformData = function(d) { var data = []; var statusCounts = {}; Rickshaw.keys(d).sort().forEach( function(t) { Rickshaw.keys(d[t]).forEach( function(status) { statusCounts[status] = statusCounts[status] || []; statusCounts[status].push( { x: parseFloat(t), y: d[t][status] } ); } ); } ); Rickshaw.keys(statusCounts).sort().forEach( function(status) { data.push( { name: status, data: statusCounts[status], color: palette.color(status) } ); } ); Rickshaw.Series.zeroFill(data); return data; }; var drawChart = function(rows, fields) { var data = {}; var timeIndex = utils.indexOf(fields, "formatted_time"); for(var i = 0; i < rows.length; i++) { var row = rows[i]; var timeValue = parseInt(row[timeIndex]); data[timeValue] = {}; for(var j = 0; j < row.length; j++) { if (j !== timeIndex) { data[timeValue][fields[j]] = row[j]; } } } var transformed = transformData(data); // Setup the graph var graph = new Rickshaw.Graph( { element: document.getElementById("rickshaw-chart"), series: transformed, renderer: 'line', width: 550 }); var y_ticks = new Rickshaw.Graph.Axis.Y({ graph: graph, orientation: 'left', tickFormat: Rickshaw.Fixtures.Number.formatKMBT, element: document.getElementById('y_axis') }); // Render the graph graph.render(); var hoverDetail = new Rickshaw.Graph.HoverDetail( { graph: graph }); var legend = new Rickshaw.Graph.Legend( { graph: graph, element: document.getElementById('rickshaw-legend') }); var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( { graph: graph, legend: legend }); var axes = new Rickshaw.Graph.Axis.Time({ graph: graph }); axes.render(); }; // First, we log in service.login(function(err, success) { // We check for both errors in the connection as well // as if the login itself failed. if (err || !success) { console.log("Error in logging in"); done(err || "Login failed"); return; } // OK, we're logged in, let's do a oneshot search and just // get the results var query = "" + 'search index=_internal sourcetype=splunkd* | head 10000 ' + '| timechart span=1m count by status | eval formatted_time=_time' + '| fields - NULL, _*, _time'; service.oneshotSearch(query, {count: 0}, function(err, results) { if (err) { console.log(err); alert("An error occurred with the search"); return; } var rows = results.rows.slice(); var fields = results.fields.slice(); var timeIndex = utils.indexOf(fields, "formatted_time"); for(var i = 0; i < rows.length; i++) { var row = rows[i]; for(var j = 0; j < row.length; j++) { // Don't change the time field if (j !== timeIndex && fields[j] !== "_time") { row[j] = parseInt(row[j]); } } } drawChart(rows, fields); }); });