diff --git a/static/graph.html b/static/graph.html
index 8d4291417..9e1e68091 100644
--- a/static/graph.html
+++ b/static/graph.html
@@ -1,55 +1,53 @@
-
+
-
-
-
+
+
diff --git a/static/js/rickshaw.js b/static/js/rickshaw.js
index 883485fd8..a2e286a6e 100644
--- a/static/js/rickshaw.js
+++ b/static/js/rickshaw.js
@@ -1,147 +1,207 @@
-var url = "http://juliusv.com:9090/api/query?expr=targets_healthy_scrape_latency_ms%5B'10m'%5D&json=JSON";
-
-// Graph options
- // Grid off/on
- // Stacked off/on
- // Area off/on
- // Legend position
- // Short link
-// Graph title
-// Palette
-// Background
-// Enable tooltips
-// width/height
-// Axis options
- // Y-Range min/max
- // (X-Range min/max)
- // X-Axis format
- // Y-Axis format
- // Y-Axis title
- // X-Axis title
- // Log scale
+// Graph options we might want:
+// Grid off/on
+// Stacked off/on
+// Area off/on
+// Legend position
+// Short link
+// Graph title
+// Palette
+// Background
+// Enable tooltips
+// width/height
+// Axis options
+// Y-Range min/max
+// (X-Range min/max)
+// X-Axis format
+// Y-Axis format
+// Y-Axis title
+// X-Axis title
+// Log scale
var graph = null;
var data = [];
+var timeFactors = {
+ "y": 60 * 60 * 24 * 365,
+ "w": 60 * 60 * 24 * 7,
+ "d": 60 * 60 * 24,
+ "h": 60 * 60,
+ "m": 60,
+ "s": 1
+};
+
+var steps = ["1s", "10s", "1m", "5m", "15m", "30m", "1h", "2h", "6h", "12h",
+ "1d", "2d", "1w", "2w", "4w", "8w", "1y", "2y"];
+
+function parseRange(rangeText) {
+ var rangeRE = new RegExp("^([0-9]+)([ywdhms]+)$");
+ var matches = rangeText.match(rangeRE);
+ if (matches.length != 3) {
+ return 60;
+ }
+ var value = parseInt(matches[1]);
+ var unit = matches[2];
+ return value * timeFactors[unit];
+}
+
+function increaseRange() {
+ var rangeSeconds = parseRange($("#range_input").val());
+ for (var i = 0; i < steps.length; i++) {
+ if (rangeSeconds < parseRange(steps[i])) {
+ $("#range_input").val(steps[i]);
+ submitQuery();
+ return;
+ }
+ }
+}
+
+function decreaseRange() {
+ var rangeSeconds = parseRange($("#range_input").val());
+ for (var i = steps.length - 1; i >= 0; i--) {
+ if (rangeSeconds > parseRange(steps[i])) {
+ $("#range_input").val(steps[i]);
+ submitQuery();
+ return;
+ }
+ }
+}
+
function submitQuery() {
$("#spinner").show();
- $("#load_time").empty();
- var form = $("#queryForm");
+ $("#eval_stats").empty();
+
+ var form = $("#query_form");
var startTime = new Date().getTime();
+ var rangeSeconds = parseRange($("#range_input").val());
+ $("#range").val(rangeSeconds);
+ var resolution = $("#step_input").val() || Math.max(Math.floor(rangeSeconds / 250), 1);
+ $("#step").val(resolution);
+
$.ajax({
- method: form.attr("method"),
- url: form.attr("action"),
- dataType: "json",
- data: form.serialize(),
- success: function(json, textStatus) {
- data = transformData(json);
- if (data.length == 0) {
- alert("No datapoints found.");
- return;
- }
- graph = null;
- $("#chart").empty();
- $("#legend").empty();
- $("#y_axis").empty();
- showGraph();
- },
- error: function() {
- alert("Error executing query!");
- },
- complete: function() {
- var duration = new Date().getTime() - startTime;
- $("#load_time").html("Load time: " + duration + "ms");
- $("#spinner").hide();
+ method: form.attr("method"),
+ url: form.attr("action"),
+ dataType: "json",
+ data: form.serialize(),
+ success: function(json, textStatus) {
+ data = transformData(json);
+ if (data.length == 0) {
+ alert("No datapoints found.");
+ return;
}
+ updateGraph(true);
+ },
+ error: function() {
+ alert("Error executing query!");
+ },
+ complete: function() {
+ var duration = new Date().getTime() - startTime;
+ $("#eval_stats").html("Load time: " + duration + "ms, resolution: " + resolution + "s");
+ $("#spinner").hide();
+ }
});
return false;
}
function metricToTsName(labels) {
- var tsName = labels["name"] + "{";
- var labelStrings = [];
- for (label in labels) {
- if (label != "name") {
- labelStrings.push(label + "='" + labels[label] + "'");
- }
- }
- tsName += labelStrings.join(",") + "}";
- return tsName;
+ var tsName = labels["name"] + "{";
+ var labelStrings = [];
+ for (label in labels) {
+ if (label != "name") {
+ labelStrings.push(label + "='" + labels[label] + "'");
+ }
+ }
+ tsName += labelStrings.join(",") + "}";
+ return tsName;
}
function parseValue(value) {
- if (value == "NaN") {
- return 0; // TODO: what to do here?
- } else {
- return parseFloat(value)
- }
+ if (value == "NaN" || value == "Inf" || value == "-Inf") {
+ return 0; // TODO: what should we really do here?
+ } else {
+ return parseFloat(value)
+ }
}
function transformData(json) {
- var palette = new Rickshaw.Color.Palette();
- if (json.Type != "matrix") {
- alert("Result is not of matrix type!");
- return [];
+ var palette = new Rickshaw.Color.Palette();
+ if (json.Type != "matrix") {
+ alert("Result is not of matrix type! Please enter a correct expression.");
+ return [];
+ }
+ var data = json.Value.map(function(ts) {
+ return {
+ name: metricToTsName(ts.Metric),
+ data: ts.Values.map(function(value) {
+ return {
+ x: value.Timestamp,
+ y: parseValue(value.Value)
}
- var data = json.Value.map(function(ts) {
- return {
- name: metricToTsName(ts.Metric),
- data: ts.Values.map(function(value) {
- return {
- x: value.Timestamp,
- y: parseValue(value.Value)
- }
- }),
- color: palette.color()
- };
- var metricStr = ts['name'];
- });
- return data;
+ }),
+ color: palette.color()
+ };
+ });
+ Rickshaw.Series.zeroFill(data);
+ return data;
}
function showGraph() {
- graph = new Rickshaw.Graph( {
- element: document.querySelector("#chart"),
- width: 1200,
- height: 800,
- renderer: 'line',
- series: data
- } );
- //graph.configure({offset: 'wiggle'});
+ graph = new Rickshaw.Graph({
+ element: document.querySelector("#chart"),
+ height: 800,
+ renderer: ($("#stacked").is(":checked") ? "stack" : "line"),
+ interpolation: "linear",
+ series: data
+ });
- var x_axis = new Rickshaw.Graph.Axis.Time( { graph: graph } );
+ var x_axis = new Rickshaw.Graph.Axis.Time({ graph: graph });
- var y_axis = new Rickshaw.Graph.Axis.Y( {
- element: document.querySelector("#y_axis"),
- graph: graph,
- orientation: 'left',
- tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
- } );
+ var y_axis = new Rickshaw.Graph.Axis.Y({
+ graph: graph,
+ tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
+ });
- var legend = new Rickshaw.Graph.Legend( {
- element: document.querySelector('#legend'),
- graph: graph
- } );
+ graph.render();
+}
+function updateGraph(reloadGraph) {
+ if (graph == null || reloadGraph) {
+ $("#chart").empty();
+ $("#legend").empty();
+ showGraph();
+ } else {
+ graph.configure({
+ renderer: ($("#stacked").is(":checked") ? "stack" : "line"),
+ interpolation: "linear",
+ series: data
+ });
graph.render();
+ }
- var hoverDetail = new Rickshaw.Graph.HoverDetail( {
- graph: graph
- } );
+ var hoverDetail = new Rickshaw.Graph.HoverDetail({
+ graph: graph
+ });
- var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( {
- graph: graph,
- legend: legend
- } );
+ var legend = new Rickshaw.Graph.Legend({
+ element: document.querySelector("#legend"),
+ graph: graph
+ });
+
+ var shelving = new Rickshaw.Graph.Behavior.Series.Toggle({
+ graph: graph,
+ legend: legend
+ });
}
function init() {
jQuery.ajaxSetup({
- cache: false
+ cache: false
});
$("#spinner").hide();
- $("#queryForm").submit(submitQuery);
+ $("#query_form").submit(submitQuery);
+ $("#inc_range").click(increaseRange);
+ $("#dec_range").click(decreaseRange);
+ $("#stacked").change(updateGraph);
$("#expr").focus();
}