Revert "Revert the /graph changes."

This reverts commit aa43d34a86.

This brings back the /graph changes so that @grandbora can continue to
work on the redirect for backwards compatibility. And other changes
can already take the new /graph parameters into account.
This commit is contained in:
beorn7 2016-09-03 21:05:23 +02:00
parent a60378c777
commit 094a098ce6
5 changed files with 267 additions and 136 deletions

View File

@ -182,12 +182,12 @@ func TestTemplateExpansion(t *testing.T) {
{
// graphLink.
text: "{{ graphLink \"up\" }}",
output: "/graph#%5B%7B%22expr%22%3A%22up%22%2C%22tab%22%3A0%7D%5D",
output: "/graph?g0.expr=up&g0.tab=0",
},
{
// tableLink.
text: "{{ tableLink \"up\" }}",
output: "/graph#%5B%7B%22expr%22%3A%22up%22%2C%22tab%22%3A1%7D%5D",
output: "/graph?g0.expr=up&g0.tab=1",
},
{
// tmpl.

View File

@ -17,7 +17,6 @@ import (
"fmt"
"net/url"
"regexp"
"strings"
)
var (
@ -27,22 +26,15 @@ var (
// TableLinkForExpression creates an escaped relative link to the table view of
// the provided expression.
func TableLinkForExpression(expr string) string {
// url.QueryEscape percent-escapes everything except spaces, for which it
// uses "+". However, in the non-query part of a URI, only percent-escaped
// spaces are legal, so we need to manually replace "+" with "%20" after
// query-escaping the string.
//
// See also:
// http://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20.
urlData := url.QueryEscape(fmt.Sprintf(`[{"expr":%q,"tab":1}]`, expr))
return fmt.Sprintf("/graph#%s", strings.Replace(urlData, "+", "%20", -1))
escapedExpression := url.QueryEscape(expr)
return fmt.Sprintf("/graph?g0.expr=%s&g0.tab=1", escapedExpression)
}
// GraphLinkForExpression creates an escaped relative link to the graph view of
// the provided expression.
func GraphLinkForExpression(expr string) string {
urlData := url.QueryEscape(fmt.Sprintf(`[{"expr":%q,"tab":0}]`, expr))
return fmt.Sprintf("/graph#%s", strings.Replace(urlData, "+", "%20", -1))
escapedExpression := url.QueryEscape(expr)
return fmt.Sprintf("/graph?g0.expr=%s&g0.tab=0", escapedExpression)
}
// SanitizeLabelName replaces anything that doesn't match

View File

@ -0,0 +1,49 @@
// Copyright 2016 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package strutil
import (
"testing"
)
type linkTest struct {
expression string
expectedGraphLink string
expectedTableLink string
}
var linkTests = []linkTest{
{
"sum(incoming_http_requests_total) by (system)",
"/graph?g0.expr=sum%28incoming_http_requests_total%29+by+%28system%29&g0.tab=0",
"/graph?g0.expr=sum%28incoming_http_requests_total%29+by+%28system%29&g0.tab=1",
},
{
"sum(incoming_http_requests_total{system=\"trackmetadata\"})",
"/graph?g0.expr=sum%28incoming_http_requests_total%7Bsystem%3D%22trackmetadata%22%7D%29&g0.tab=0",
"/graph?g0.expr=sum%28incoming_http_requests_total%7Bsystem%3D%22trackmetadata%22%7D%29&g0.tab=1",
},
}
func TestLink(t *testing.T) {
for _, tt := range linkTests {
if graphLink := GraphLinkForExpression(tt.expression); graphLink != tt.expectedGraphLink {
t.Errorf("GraphLinkForExpression failed for expression (%#q), want %q got %q", tt.expression, tt.expectedGraphLink, graphLink)
}
if tableLink := TableLinkForExpression(tt.expression); tableLink != tt.expectedTableLink {
t.Errorf("TableLinkForExpression failed for expression (%#q), want %q got %q", tt.expression, tt.expectedTableLink, tableLink)
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,16 +1,18 @@
var Prometheus = Prometheus || {};
var graphs = [];
var graphTemplate;
var SECOND = 1000;
Handlebars.registerHelper('pathPrefix', function() { return PATH_PREFIX; });
Prometheus.Graph = function(element, options) {
Prometheus.Graph = function(element, options, handleChange, handleRemove) {
this.el = element;
this.graphHTML = null;
this.options = options;
this.changeHandler = null;
this.handleChange = handleChange;
this.handleRemove = function() {
handleRemove(this);
};
this.rickshawGraph = null;
this.data = [];
@ -69,7 +71,7 @@ Prometheus.Graph.prototype.initialize = function() {
};
$(this).on('keyup input', function() { resizeTextarea(this); });
});
self.expr.change(storeGraphOptionsInURL);
self.expr.change(self.handleChange);
self.rangeInput = self.queryForm.find("input[name=range_input]");
self.stackedBtn = self.queryForm.find(".stacked_btn");
@ -85,7 +87,7 @@ Prometheus.Graph.prototype.initialize = function() {
self.tabs.on("shown.bs.tab", function(e) {
var target = $(e.target);
self.options.tab = target.parent().index();
storeGraphOptionsInURL();
self.handleChange();
if ($("#" + target.attr("aria-controls")).hasClass("reload")) {
self.submitQuery();
}
@ -208,10 +210,6 @@ Prometheus.Graph.prototype.populateInsertableMetrics = function() {
});
};
Prometheus.Graph.prototype.onChange = function(handler) {
this.changeHandler = handler;
};
Prometheus.Graph.prototype.getOptions = function() {
var self = this;
var options = {};
@ -544,7 +542,7 @@ Prometheus.Graph.prototype.updateGraph = function() {
legend: legend
});
self.changeHandler();
self.handleChange();
};
Prometheus.Graph.prototype.resizeGraph = function() {
@ -622,41 +620,10 @@ Prometheus.Graph.prototype.handleConsoleResponse = function(data, textStatus) {
Prometheus.Graph.prototype.remove = function() {
var self = this;
$(self.graphHTML).remove();
graphs = graphs.filter(function(e) {return e !== self});
storeGraphOptionsInURL();
self.handleRemove();
self.handleChange();
};
function parseGraphOptionsFromURL() {
var hashOptions = window.location.hash.slice(1);
if (!hashOptions) {
return [];
}
var optionsJSON = decodeURIComponent(window.location.hash.slice(1));
options = JSON.parse(optionsJSON);
return options;
}
// NOTE: This needs to be kept in sync with rules/helpers.go:GraphLinkForExpression!
function storeGraphOptionsInURL() {
var allGraphsOptions = [];
for (var i = 0; i < graphs.length; i++) {
allGraphsOptions.push(graphs[i].getOptions());
}
var optionsJSON = JSON.stringify(allGraphsOptions);
window.location.hash = encodeURIComponent(optionsJSON);
}
function addGraph(options) {
var graph = new Prometheus.Graph($("#graph_container"), options);
graphs.push(graph);
graph.onChange(function() {
storeGraphOptionsInURL();
});
$(window).resize(function() {
graph.resizeGraph();
});
}
function escapeHTML(string) {
var entityMap = {
"&": "&amp;",
@ -672,6 +639,135 @@ function escapeHTML(string) {
});
}
Prometheus.Page = function() {
this.graphs = [];
};
Prometheus.Page.prototype.init = function() {
var graphOptions = this.parseURL();
if (graphOptions.length === 0) {
graphOptions.push({});
}
graphOptions.forEach(this.addGraph, this);
$("#add_graph").click(this.addGraph.bind(this, {}));
};
Prometheus.Page.prototype.parseURL = function() {
if (window.location.search == "") {
return [];
}
var queryParams = window.location.search.substring(1).split('&');
var queryParamHelper = new Prometheus.Page.QueryParamHelper();
return queryParamHelper.parseQueryParams(queryParams);
};
Prometheus.Page.prototype.addGraph = function(options) {
var graph = new Prometheus.Graph(
$("#graph_container"),
options,
this.updateURL.bind(this),
this.removeGraph.bind(this)
);
this.graphs.push(graph);
$(window).resize(function() {
graph.resizeGraph();
});
};
// NOTE: This needs to be kept in sync with /util/strutil/strconv.go:GraphLinkForExpression
Prometheus.Page.prototype.updateURL = function() {
var queryString = this.graphs.map(function(graph, index) {
var graphOptions = graph.getOptions();
var queryParamHelper = new Prometheus.Page.QueryParamHelper();
var queryObject = queryParamHelper.generateQueryObject(graphOptions, index);
return $.param(queryObject);
}, this).join("&");
history.pushState({}, "", "graph?" + queryString);
};
Prometheus.Page.prototype.removeGraph = function(graph) {
this.graphs = this.graphs.filter(function(g) {return g !== graph});
};
Prometheus.Page.QueryParamHelper = function() {};
Prometheus.Page.QueryParamHelper.prototype.parseQueryParams = function(queryParams) {
var orderedQueryParams = this.filterInvalidParams(queryParams).sort();
return this.fetchOptionsFromOrderedParams(orderedQueryParams, 0);
};
Prometheus.Page.QueryParamHelper.queryParamFormat = /^g\d+\..+=.+$/;
Prometheus.Page.QueryParamHelper.prototype.filterInvalidParams = function(paramTuples) {
return paramTuples.filter(function(paramTuple) {
return Prometheus.Page.QueryParamHelper.queryParamFormat.test(paramTuple);
});
};
Prometheus.Page.QueryParamHelper.prototype.fetchOptionsFromOrderedParams = function(queryParams, graphIndex) {
if (queryParams.length == 0) {
return [];
}
var prefixOfThisIndex = this.queryParamPrefix(graphIndex);
var numberOfParamsForThisGraph = queryParams.filter(function(paramTuple) {
return paramTuple.startsWith(prefixOfThisIndex);
}).length;
if (numberOfParamsForThisGraph == 0) {
return [];
}
var paramsForThisGraph = queryParams.splice(0, numberOfParamsForThisGraph);
paramsForThisGraph = paramsForThisGraph.map(function(paramTuple) {
return paramTuple.substring(prefixOfThisIndex.length);
});
var options = this.parseQueryParamsOfOneGraph(paramsForThisGraph);
var optionAccumulator = this.fetchOptionsFromOrderedParams(queryParams, graphIndex + 1);
optionAccumulator.unshift(options);
return optionAccumulator;
};
Prometheus.Page.QueryParamHelper.prototype.parseQueryParamsOfOneGraph = function(queryParams) {
var options = {};
queryParams.forEach(function(tuple) {
var optionNameAndValue = tuple.split('=');
var optionName = optionNameAndValue[0];
var optionValue = decodeURIComponent(optionNameAndValue[1]);
optionValue = optionValue.replace(/\+/g, " "); // $.param turns spaces into pluses
if (optionName == "tab") {
optionValue = parseInt(optionValue); // tab is integer
}
options[optionName] = optionValue;
});
return options;
};
Prometheus.Page.QueryParamHelper.prototype.queryParamPrefix = function(index) {
return "g" + index + ".";
};
Prometheus.Page.QueryParamHelper.prototype.generateQueryObject = function(graphOptions, index) {
var prefix = this.queryParamPrefix(index);
var queryObject = {};
Object.keys(graphOptions).forEach(function(key) {
queryObject[prefix + key] = graphOptions[key];
});
return queryObject;
};
function init() {
$.ajaxSetup({
cache: false
@ -681,14 +777,8 @@ function init() {
url: PATH_PREFIX + "/static/js/graph_template.handlebar",
success: function(data) {
graphTemplate = Handlebars.compile(data);
var options = parseGraphOptionsFromURL();
if (options.length === 0) {
options.push({});
}
for (var i = 0; i < options.length; i++) {
addGraph(options[i]);
}
$("#add_graph").click(function() { addGraph({}); });
var Page = new Prometheus.Page();
Page.init();
}
});
}