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);
});
});