mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-11 08:04:04 -08:00
a081c9436b
Main changes: - Switched to using `go-bindata` in place of `scripts/embed-static.sh`. - Support for building Prometheus without a `Makefile`. - Minor typo fix to make Prometheus build on Windows (without Makefiles). Please note that this does not mean that prometheus will work on Windows. There are still failing tests!
611 lines
20 KiB
JavaScript
611 lines
20 KiB
JavaScript
/*
|
|
* Functions to make it easier to write prometheus consoles, such
|
|
* as graphs.
|
|
*
|
|
*/
|
|
|
|
PromConsole = {};
|
|
|
|
PromConsole.NumberFormatter = {};
|
|
PromConsole.NumberFormatter.prefixesBig = ["k", "M", "G", "T", "P", "E", "Z", "Y"];
|
|
PromConsole.NumberFormatter.prefixesBig1024 = ["ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi"];
|
|
PromConsole.NumberFormatter.prefixesSmall = ["m", "u", "n", "p", "f", "a", "z", "y"];
|
|
|
|
PromConsole._stripTrailingZero = function(x) {
|
|
if (x.indexOf("e") == -1) {
|
|
// It's not safe to strip if it's scientific notation.
|
|
return x.replace(/\.?0*$/, '');
|
|
}
|
|
return x;
|
|
}
|
|
|
|
// Humanize a number.
|
|
PromConsole.NumberFormatter.humanize = function(x) {
|
|
var ret = PromConsole.NumberFormatter._humanize(
|
|
x, PromConsole.NumberFormatter.prefixesBig,
|
|
PromConsole.NumberFormatter.prefixesSmall, 1000);
|
|
x = ret[0];
|
|
var prefix = ret[1];
|
|
if (Math.abs(x) < 1) {
|
|
return x.toExponential(3) + prefix;
|
|
}
|
|
return PromConsole._stripTrailingZero(x.toFixed(3)) + prefix;
|
|
}
|
|
|
|
// Humanize a number, don't use milli/micro/etc. prefixes.
|
|
PromConsole.NumberFormatter.humanizeNoSmallPrefix = function(x) {
|
|
if (Math.abs(x) < 1) {
|
|
return PromConsole._stripTrailingZero(x.toPrecision(3));
|
|
}
|
|
var ret = PromConsole.NumberFormatter._humanize(
|
|
x, PromConsole.NumberFormatter.prefixesBig,
|
|
[], 1000);
|
|
x = ret[0];
|
|
var prefix = ret[1];
|
|
return PromConsole._stripTrailingZero(x.toFixed(3)) + prefix;
|
|
}
|
|
|
|
// Humanize a number with 1024 as the base, rather than 1000.
|
|
PromConsole.NumberFormatter.humanize1024 = function(x) {
|
|
var ret = PromConsole.NumberFormatter._humanize(
|
|
x, PromConsole.NumberFormatter.prefixesBig1024,
|
|
[], 1024);
|
|
x = ret[0];
|
|
var prefix = ret[1];
|
|
if (Math.abs(x) < 1) {
|
|
return x.toExponential(3) + prefix;
|
|
}
|
|
return PromConsole._stripTrailingZero(x.toFixed(3)) + prefix;
|
|
}
|
|
|
|
// Humanize a number, returning an exact representation.
|
|
PromConsole.NumberFormatter.humanizeExact = function(x) {
|
|
var ret = PromConsole.NumberFormatter._humanize(
|
|
x, PromConsole.NumberFormatter.prefixesBig,
|
|
PromConsole.NumberFormatter.prefixesSmall, 1000);
|
|
return ret[0] + ret[1];
|
|
}
|
|
|
|
PromConsole.NumberFormatter._humanize = function(x, prefixesBig, prefixesSmall, factor) {
|
|
var prefix = ""
|
|
if (x == 0) {
|
|
/* Do nothing. */
|
|
} else if (Math.abs(x) >= 1) {
|
|
for (var i=0; i < prefixesBig.length && Math.abs(x) >= factor; ++i) {
|
|
x /= factor;
|
|
prefix = prefixesBig[i];
|
|
}
|
|
} else {
|
|
for (var i=0; i < prefixesSmall.length && Math.abs(x) < 1; ++i) {
|
|
x *= factor;
|
|
prefix = prefixesSmall[i];
|
|
}
|
|
}
|
|
return [x, prefix];
|
|
};
|
|
|
|
|
|
PromConsole.TimeControl = function() {
|
|
document.getElementById("prom_graph_duration_shrink").onclick = this.decreaseDuration.bind(this);
|
|
document.getElementById("prom_graph_duration_grow").onclick = this.increaseDuration.bind(this);
|
|
document.getElementById("prom_graph_time_back").onclick = this.decreaseEnd.bind(this);
|
|
document.getElementById("prom_graph_time_forward").onclick = this.increaseEnd.bind(this);
|
|
document.getElementById("prom_graph_refresh_button").onclick = this.refresh.bind(this);
|
|
this.durationElement = document.getElementById("prom_graph_duration");
|
|
this.endElement = document.getElementById("prom_graph_time_end");
|
|
this.durationElement.oninput = this.dispatch.bind(this);
|
|
this.endElement.oninput = this.dispatch.bind(this);
|
|
this.endElement.oninput = this.dispatch.bind(this);
|
|
this.refreshValueElement = document.getElementById("prom_graph_refresh_button_value");
|
|
|
|
var refreshList = document.getElementById("prom_graph_refresh_intervals");
|
|
var refreshIntervals = ["Off", "1m", "5m", "15m", "1h"];
|
|
for (var i=0; i < refreshIntervals.length; ++i) {
|
|
var li = document.createElement("li");
|
|
li.onclick = this.setRefresh.bind(this, refreshIntervals[i]);
|
|
li.textContent = refreshIntervals[i];
|
|
refreshList.appendChild(li);
|
|
}
|
|
|
|
this.durationElement.value = PromConsole.TimeControl.prototype.getHumanDuration(
|
|
PromConsole.TimeControl._initialValues.duration);
|
|
if (PromConsole.TimeControl._initialValues.endTimeNow === undefined) {
|
|
this.endElement.value = PromConsole.TimeControl.prototype.getHumanDate(
|
|
new Date(PromConsole.TimeControl._initialValues.endTime * 1000));
|
|
}
|
|
}
|
|
|
|
PromConsole.TimeControl.timeFactors = {
|
|
"y": 60 * 60 * 24 * 365,
|
|
"w": 60 * 60 * 24 * 7,
|
|
"d": 60 * 60 * 24,
|
|
"h": 60 * 60,
|
|
"m": 60,
|
|
"s": 1
|
|
};
|
|
|
|
PromConsole.TimeControl.stepValues = [
|
|
"10s", "1m", "5m", "15m", "30m", "1h", "2h", "6h", "12h", "1d", "2d",
|
|
"1w", "2w", "4w", "8w", "1y", "2y"
|
|
];
|
|
|
|
PromConsole.TimeControl.prototype._setHash = function() {
|
|
var duration = this.parseDuration(this.durationElement.value);
|
|
var endTime = this.getEndDate() / 1000;
|
|
window.location.hash = "#pctc" + encodeURIComponent(JSON.stringify(
|
|
{duration: duration, endTime: endTime}));
|
|
}
|
|
|
|
PromConsole.TimeControl._initialValues = function() {
|
|
var hash = window.location.hash;
|
|
if (hash.indexOf('#pctc') == 0) {
|
|
return JSON.parse(decodeURIComponent(hash.substring(5)));
|
|
}
|
|
return {duration: 3600, endTime: new Date().getTime() / 1000, endTimeNow: true};
|
|
}();
|
|
|
|
PromConsole.TimeControl.prototype.parseDuration = function(durationText) {
|
|
var durationRE = new RegExp("^([0-9]+)([ywdhms]?)$");
|
|
var matches = durationText.match(durationRE);
|
|
if (!matches) { return 3600; }
|
|
var value = parseInt(matches[1]);
|
|
var unit = matches[2] || 's';
|
|
return value * PromConsole.TimeControl.timeFactors[unit];
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.getHumanDuration = function(duration) {
|
|
var units = [];
|
|
for (var key in PromConsole.TimeControl.timeFactors) {
|
|
units.push([PromConsole.TimeControl.timeFactors[key], key]);
|
|
}
|
|
units.sort(function(a, b) { return b[0] - a[0] });
|
|
for (var i = 0; i < units.length; ++i) {
|
|
if (duration % units[i][0] == 0) {
|
|
return (duration / units[i][0]) + units[i][1];
|
|
}
|
|
}
|
|
return duration;
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.increaseDuration = function() {
|
|
var durationSeconds = this.parseDuration(this.durationElement.value);
|
|
for (var i = 0; i < PromConsole.TimeControl.stepValues.length; i++) {
|
|
if (durationSeconds < this.parseDuration(PromConsole.TimeControl.stepValues[i])) {
|
|
this.setDuration(PromConsole.TimeControl.stepValues[i]);
|
|
this.dispatch();
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.decreaseDuration = function() {
|
|
var durationSeconds = this.parseDuration(this.durationElement.value);
|
|
for (var i = PromConsole.TimeControl.stepValues.length - 1; i >= 0; i--) {
|
|
if (durationSeconds > this.parseDuration(PromConsole.TimeControl.stepValues[i])) {
|
|
this.setDuration(PromConsole.TimeControl.stepValues[i]);
|
|
this.dispatch();
|
|
return;
|
|
}
|
|
}
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.setDuration = function(duration) {
|
|
this.durationElement.value = duration;
|
|
this._setHash();
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.getEndDate = function() {
|
|
if (this.endElement.value == '') {
|
|
return null;
|
|
}
|
|
return new Date(this.endElement.value).getTime();
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.getOrSetEndDate = function() {
|
|
var date = this.getEndDate();
|
|
if (date) {
|
|
return date;
|
|
}
|
|
date = new Date();
|
|
this.setEndDate(date);
|
|
return date;
|
|
}
|
|
|
|
PromConsole.TimeControl.prototype.getHumanDate = function(date) {
|
|
var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours();
|
|
var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes();
|
|
return date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate() + " " +
|
|
hours + ":" + minutes;
|
|
}
|
|
|
|
PromConsole.TimeControl.prototype.setEndDate = function(date) {
|
|
this.setRefresh("Off");
|
|
this.endElement.value = this.getHumanDate(date);
|
|
this._setHash();
|
|
};
|
|
|
|
|
|
PromConsole.TimeControl.prototype.increaseEnd = function() {
|
|
// Increase duration 25% range & convert ms to s.
|
|
this.setEndDate(new Date(this.getOrSetEndDate() + this.parseDuration(this.durationElement.value) * 1000/4 ));
|
|
this.dispatch();
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.decreaseEnd = function() {
|
|
this.setEndDate(new Date(this.getOrSetEndDate() - this.parseDuration(this.durationElement.value) * 1000/4 ));
|
|
this.dispatch();
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype.refresh = function() {
|
|
this.endElement.value = '';
|
|
this._setHash();
|
|
this.dispatch();
|
|
}
|
|
|
|
PromConsole.TimeControl.prototype.dispatch = function() {
|
|
var durationSeconds = this.parseDuration(this.durationElement.value);
|
|
var end = this.getEndDate();
|
|
if (end === null) {
|
|
end = new Date().getTime();
|
|
}
|
|
for (var i = 0; i< PromConsole._graph_registry.length; i++) {
|
|
var graph = PromConsole._graph_registry[i];
|
|
graph.params.duration = durationSeconds;
|
|
graph.params.endTime = end / 1000;
|
|
graph.dispatch();
|
|
}
|
|
};
|
|
|
|
PromConsole.TimeControl.prototype._refreshInterval = null;
|
|
|
|
PromConsole.TimeControl.prototype.setRefresh = function(duration) {
|
|
if (this._refreshInterval !== null) {
|
|
window.clearInterval(this._refreshInterval);
|
|
this._refreshInterval = null;
|
|
}
|
|
if (duration != "Off") {
|
|
if (this.endElement.value != '') {
|
|
this.refresh();
|
|
}
|
|
var durationSeconds = this.parseDuration(duration);
|
|
this._refreshInterval = window.setInterval(this.dispatch.bind(this), durationSeconds * 1000);
|
|
}
|
|
this.refreshValueElement.textContent = duration;
|
|
};
|
|
|
|
|
|
|
|
// List of all graphs, used by time controls.
|
|
PromConsole._graph_registry = [];
|
|
|
|
PromConsole.graphDefaults = {
|
|
expr: null, // Expression to graph. Can be a list of strings.
|
|
node: null, // DOM node to place graph under.
|
|
// How long the graph is over, in seconds.
|
|
duration: PromConsole.TimeControl._initialValues.duration,
|
|
// The unixtime the graph ends at.
|
|
endTime: PromConsole.TimeControl._initialValues.endTime,
|
|
width: null, // Height of the graph div, excluding titles and legends.
|
|
// Defaults to auto-detection.
|
|
height: 200, // Height of the graph div, excluding titles and legends.
|
|
min: "auto", // Minimum Y-axis value, defaults to lowest data value.
|
|
max: undefined, // Maximum Y-axis value, defaults to highest data value.
|
|
renderer: 'line', // Type of graphs, options are 'line' and 'area'.
|
|
name: null, // What to call plots, defaults to trying to do
|
|
// something reasonable.
|
|
// If a string, it'll use that. [[ label ]] will be substituted.
|
|
// If a function it'll be called with a map of keys to values,
|
|
// and should return the name to use.
|
|
xTitle: "Time", // The title of the x axis.
|
|
yUnits: "", // The units of the y axis.
|
|
yTitle: "", // The title of the y axis.
|
|
// Number formatter for y axis.
|
|
yAxisFormatter: PromConsole.NumberFormatter.humanize,
|
|
// Number formatter for y values hover detail.
|
|
yHoverFormatter: PromConsole.NumberFormatter.humanizeExact,
|
|
};
|
|
|
|
PromConsole.Graph = function(params) {
|
|
for (var k in PromConsole.graphDefaults) {
|
|
if (!(k in params)) {
|
|
params[k] = PromConsole.graphDefaults[k];
|
|
}
|
|
}
|
|
if (typeof params.expr == "string") {
|
|
params.expr = [params.expr]
|
|
}
|
|
|
|
this.params = params;
|
|
this.rendered_data = null;
|
|
PromConsole._graph_registry.push(this);
|
|
|
|
/*
|
|
* Table layout:
|
|
* | yTitle | Graph |
|
|
* | | xTitle |
|
|
* | /graph | Legend |
|
|
*/
|
|
var table = document.createElement("table");
|
|
table.className = "prom_graph_table";
|
|
params.node.appendChild(table);
|
|
var tr = document.createElement("tr");
|
|
table.appendChild(tr);
|
|
var yTitleTd = document.createElement("td");
|
|
tr.appendChild(yTitleTd);
|
|
var yTitleDiv = document.createElement("td");
|
|
yTitleTd.appendChild(yTitleDiv);
|
|
yTitleDiv.className = "prom_graph_ytitle";
|
|
yTitleDiv.textContent = params.yTitle + (params.yUnits ? " (" + params.yUnits.trim() + ")" : "");
|
|
|
|
this.graphTd = document.createElement("td");
|
|
tr.appendChild(this.graphTd);
|
|
this.graphTd.className = "rickshaw_graph";
|
|
this.graphTd.width = params.width;
|
|
this.graphTd.height = params.height;
|
|
|
|
tr = document.createElement("tr");
|
|
table.appendChild(tr);
|
|
tr.appendChild(document.createElement("td"));
|
|
var xTitleTd = document.createElement("td");
|
|
tr.appendChild(xTitleTd);
|
|
xTitleTd.className = "prom_graph_xtitle";
|
|
xTitleTd.textContent = params.xTitle;
|
|
|
|
tr = document.createElement("tr");
|
|
table.appendChild(tr);
|
|
var graphLinkTd = document.createElement("td");
|
|
tr.appendChild(graphLinkTd);
|
|
var graphLinkA = document.createElement("a");
|
|
graphLinkTd.appendChild(graphLinkA);
|
|
graphLinkA.className = "prom_graph_link";
|
|
graphLinkA.textContent = "+";
|
|
graphLinkA.href = PromConsole._graphsToSlashGraphURL(params.expr);
|
|
var legendTd = document.createElement("td");
|
|
tr.appendChild(legendTd);
|
|
this.legendDiv = document.createElement("div");
|
|
legendTd.width = params.width;
|
|
legendTd.appendChild(this.legendDiv);
|
|
|
|
window.addEventListener('resize', function() {
|
|
if(this.rendered_data !== null) {
|
|
this._render(this.rendered_data);
|
|
}
|
|
}.bind(this))
|
|
|
|
this.dispatch();
|
|
|
|
};
|
|
|
|
PromConsole.Graph.prototype._parseValue = function(value) {
|
|
var val = parseFloat(value);
|
|
if (isNaN(val)) {
|
|
// "+Inf", "-Inf", "+Inf" will be parsed into NaN by parseFloat(). The
|
|
// can't be graphed, so show them as gaps (null).
|
|
return null
|
|
}
|
|
return val;
|
|
}
|
|
|
|
PromConsole.Graph.prototype._escapeHTML = function(string) {
|
|
var entityMap = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': '"',
|
|
"'": ''',
|
|
"/": '/'
|
|
};
|
|
|
|
return string.replace(/[&<>"'\/]/g, function (s) {
|
|
return entityMap[s];
|
|
});
|
|
}
|
|
|
|
PromConsole.Graph.prototype._render = function(data) {
|
|
var self = this;
|
|
var palette = new Rickshaw.Color.Palette();
|
|
var series = [];
|
|
|
|
// This will be used on resize.
|
|
this.rendered_data = data;
|
|
|
|
var nameFunc;
|
|
if (this.params.name === null) {
|
|
nameFunc = PromConsole._chooseNameFunction(data);
|
|
} else if (typeof this.params.name == "string") {
|
|
nameFunc = function(metric) {
|
|
return PromConsole._interpolateName(this.params.name, metric);
|
|
}.bind(this);
|
|
} else {
|
|
nameFunc = this.params.name;
|
|
}
|
|
|
|
// Get the data into the right format.
|
|
var seriesLen = 0;
|
|
for (var e = 0; e < data.length; e++) {
|
|
for (var i = 0; i < data[e].value.length; i++) {
|
|
series[seriesLen++] = {
|
|
data: data[e].value[i].values.map(function(s) {return {x: s[0], y: self._parseValue(s[1])} }),
|
|
color: palette.color(),
|
|
name: self._escapeHTML(nameFunc(data[e].value[i].metric)),
|
|
};
|
|
}
|
|
}
|
|
this._clearGraph();
|
|
if (!series.length) {
|
|
var errorText = document.createElement("div");
|
|
errorText.className = 'prom_graph_error';
|
|
errorText.textContent = 'No timeseries returned';
|
|
this.graphTd.appendChild(errorText);
|
|
return;
|
|
}
|
|
// Render.
|
|
var graph = new Rickshaw.Graph({
|
|
interpolation: "linear",
|
|
width: this.graphTd.offsetWidth,
|
|
height: this.params.height,
|
|
element: this.graphTd,
|
|
renderer: this.params.renderer,
|
|
max: this.params.max,
|
|
min: this.params.min,
|
|
series: series
|
|
});
|
|
var hoverDetail = new Rickshaw.Graph.HoverDetail({
|
|
graph: graph,
|
|
onRender: function() {
|
|
var xLabel = this.element.getElementsByClassName("x_label")[0];
|
|
var item = this.element.getElementsByClassName("item")[0];
|
|
if (xLabel.offsetWidth + xLabel.offsetLeft + this.element.offsetLeft > graph.element.offsetWidth
|
|
|| item.offsetWidth + item.offsetLeft + this.element.offsetLeft > graph.element.offsetWidth) {
|
|
xLabel.classList.add("prom_graph_hover_flipped");
|
|
item.classList.add("prom_graph_hover_flipped");
|
|
} else {
|
|
xLabel.classList.remove("prom_graph_hover_flipped");
|
|
item.classList.remove("prom_graph_hover_flipped");
|
|
}
|
|
},
|
|
yFormatter: function(y) {return this.params.yHoverFormatter(y) + this.params.yUnits}.bind(this)
|
|
});
|
|
var yAxis = new Rickshaw.Graph.Axis.Y({
|
|
graph: graph,
|
|
tickFormat: this.params.yAxisFormatter
|
|
});
|
|
var xAxis = new Rickshaw.Graph.Axis.Time({
|
|
graph: graph,
|
|
});
|
|
var legend = new Rickshaw.Graph.Legend({
|
|
graph: graph,
|
|
element: this.legendDiv
|
|
});
|
|
xAxis.render();
|
|
yAxis.render();
|
|
graph.render();
|
|
};
|
|
|
|
PromConsole.Graph.prototype._clearGraph = function() {
|
|
while (this.graphTd.lastChild) {
|
|
this.graphTd.removeChild(this.graphTd.lastChild);
|
|
}
|
|
while (this.legendDiv.lastChild) {
|
|
this.legendDiv.removeChild(this.legendDiv.lastChild);
|
|
}
|
|
}
|
|
|
|
PromConsole.Graph.prototype._xhrs = []
|
|
|
|
PromConsole.Graph.prototype.dispatch = function() {
|
|
for (var j = 0; j < this._xhrs.length; j++) {
|
|
this._xhrs[j].abort();
|
|
}
|
|
var all_data = new Array(this.params.expr.length);
|
|
this._xhrs = new Array(this.params.expr.length);
|
|
var pending_requests = this.params.expr.length;
|
|
for (var i = 0; i < this.params.expr.length; ++i) {
|
|
var endTime = this.params.endTime;
|
|
var url = PATH_PREFIX + "/api/query_range?expr=" + encodeURIComponent(this.params.expr[i])
|
|
+ "&step=" + this.params.duration / this.graphTd.offsetWidth
|
|
+ "&range=" + this.params.duration + "&end=" + endTime;
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('get', url, true);
|
|
xhr.responseType = 'json';
|
|
xhr.onerror = function(xhr, i) {
|
|
this._clearGraph();
|
|
var errorText = document.createElement("div");
|
|
errorText.className = 'prom_graph_error';
|
|
errorText.textContent = 'Error loading data';
|
|
this.graphTd.appendChild(errorText);
|
|
console.log('Error loading data for ' + this.params.expr[i]);
|
|
pending_requests = 0;
|
|
// onabort gets any aborts.
|
|
for (var j = 0; j < pending_requests; j++) {
|
|
this._xhrs[j].abort();
|
|
}
|
|
}.bind(this, xhr, i)
|
|
xhr.onload = function(xhr, i) {
|
|
if (pending_requests == 0) {
|
|
// Got an error before this success.
|
|
return;
|
|
}
|
|
var data = xhr.response;
|
|
pending_requests -= 1;
|
|
all_data[i] = data;
|
|
if (pending_requests == 0) {
|
|
this._xhrs = [];
|
|
this._render(all_data);
|
|
}
|
|
}.bind(this, xhr, i)
|
|
xhr.send();
|
|
this._xhrs[i] = xhr;
|
|
}
|
|
|
|
var loadingImg = document.createElement("img");
|
|
loadingImg.src = PATH_PREFIX + '/static/img/ajax-loader.gif';
|
|
loadingImg.alt = 'Loading...';
|
|
loadingImg.className = 'prom_graph_loading';
|
|
this.graphTd.appendChild(loadingImg);
|
|
};
|
|
|
|
// Substitute the value of 'label' for [[ label ]].
|
|
PromConsole._interpolateName = function(name, metric) {
|
|
var re = /(.*?)\[\[\s*(\w+)+\s*\]\](.*?)/g;
|
|
var result = '';
|
|
while (match = re.exec(name)) {
|
|
result = result + match[1] + metric[match[2]] + match[3]
|
|
}
|
|
if (!result) {
|
|
return name;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Given the data returned by the API, return an appropriate function
|
|
// to return plot names.
|
|
PromConsole._chooseNameFunction = function(data) {
|
|
// By default, use the full metric name.
|
|
var nameFunc = function (metric) {
|
|
name = metric.__name__ + "{";
|
|
for (var label in metric) {
|
|
if (label.substring(0,2) == "__") {
|
|
continue;
|
|
}
|
|
name += label + "='" + metric[label] + "',";
|
|
}
|
|
return name + "}";
|
|
}
|
|
// If only one label varies, use that value.
|
|
var labelValues = {};
|
|
for (var e = 0; e < data.length; e++) {
|
|
for (var i = 0; i < data[e].value.length; i++) {
|
|
for (var label in data[e].value[i].metric) {
|
|
if (!(label in labelValues)) {
|
|
labelValues[label] = {};
|
|
}
|
|
labelValues[label][data[e].value[i].metric[label]] = 1;
|
|
}
|
|
}
|
|
}
|
|
var multiValueLabels = [];
|
|
for (var label in labelValues) {
|
|
if (Object.keys(labelValues[label]).length > 1) {
|
|
multiValueLabels.push(label);
|
|
}
|
|
}
|
|
if (multiValueLabels.length == 1) {
|
|
nameFunc = function(metric) {
|
|
return metric[multiValueLabels[0]];
|
|
}
|
|
}
|
|
return nameFunc;
|
|
}
|
|
|
|
|
|
// Given a list of expressions, produce the /graph url for them.
|
|
PromConsole._graphsToSlashGraphURL = function(exprs) {
|
|
var data = [];
|
|
for (var i = 0; i < exprs.length; ++i) {
|
|
data.push({'expr': exprs[i], 'tab': 0});
|
|
}
|
|
return PATH_PREFIX + '/graph#' + encodeURIComponent(JSON.stringify(data));
|
|
|
|
};
|