2014-02-15 20:46:36 +08:00
|
|
|
define([
|
|
|
|
'angular',
|
2014-08-07 20:35:19 +08:00
|
|
|
'lodash',
|
2014-02-15 20:46:36 +08:00
|
|
|
'jquery',
|
|
|
|
'config',
|
|
|
|
'kbn',
|
2014-12-31 03:49:04 +08:00
|
|
|
'moment',
|
|
|
|
'./queryCtrl',
|
2014-12-31 04:08:48 +08:00
|
|
|
'./funcEditor',
|
|
|
|
'./addGraphiteFunc',
|
2014-02-15 20:46:36 +08:00
|
|
|
],
|
|
|
|
function (angular, _, $, config, kbn, moment) {
|
|
|
|
'use strict';
|
|
|
|
|
2014-07-29 00:11:52 +08:00
|
|
|
var module = angular.module('grafana.services');
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-08-27 23:58:49 +08:00
|
|
|
module.factory('GraphiteDatasource', function($q, $http, templateSrv) {
|
2014-02-26 00:48:01 +08:00
|
|
|
|
2014-02-26 04:31:30 +08:00
|
|
|
function GraphiteDatasource(datasource) {
|
2014-02-26 00:48:01 +08:00
|
|
|
this.type = 'graphite';
|
|
|
|
this.basicAuth = datasource.basicAuth;
|
2014-02-26 15:49:53 +08:00
|
|
|
this.url = datasource.url;
|
2014-03-02 17:41:16 +08:00
|
|
|
this.name = datasource.name;
|
2014-12-31 04:08:48 +08:00
|
|
|
this.cacheTimeout = datasource.cacheTimeout;
|
|
|
|
this.withCredentials = datasource.withCredentials;
|
2014-04-24 23:52:12 +08:00
|
|
|
this.render_method = datasource.render_method || 'POST';
|
2014-12-31 04:08:48 +08:00
|
|
|
|
2014-07-13 21:01:20 +08:00
|
|
|
this.supportAnnotations = true;
|
2014-07-30 14:34:58 +08:00
|
|
|
this.supportMetrics = true;
|
2014-12-31 04:08:48 +08:00
|
|
|
this.editorSrc = 'app/features/graphite/partials/query.editor.html';
|
2014-12-31 04:24:55 +08:00
|
|
|
this.annotationEditorSrc = 'app/features/graphite/partials/annotations.editor.html';
|
2014-02-15 20:46:36 +08:00
|
|
|
}
|
|
|
|
|
2014-08-27 22:29:48 +08:00
|
|
|
GraphiteDatasource.prototype.query = function(options) {
|
2014-02-26 00:48:01 +08:00
|
|
|
try {
|
|
|
|
var graphOptions = {
|
2014-07-22 00:49:30 +08:00
|
|
|
from: this.translateTime(options.range.from, 'round-down'),
|
|
|
|
until: this.translateTime(options.range.to, 'round-up'),
|
2014-02-26 00:48:01 +08:00
|
|
|
targets: options.targets,
|
|
|
|
format: options.format,
|
2014-07-28 23:54:32 +08:00
|
|
|
cacheTimeout: options.cacheTimeout || this.cacheTimeout,
|
2014-02-26 00:48:01 +08:00
|
|
|
maxDataPoints: options.maxDataPoints,
|
|
|
|
};
|
|
|
|
|
2014-08-27 22:29:48 +08:00
|
|
|
var params = this.buildGraphiteParams(graphOptions);
|
2014-02-26 00:48:01 +08:00
|
|
|
|
|
|
|
if (options.format === 'png') {
|
2014-02-26 04:31:30 +08:00
|
|
|
return $q.when(this.url + '/render' + '?' + params.join('&'));
|
2014-02-26 00:48:01 +08:00
|
|
|
}
|
|
|
|
|
2014-04-24 23:52:12 +08:00
|
|
|
var httpOptions = { method: this.render_method, url: '/render' };
|
|
|
|
|
|
|
|
if (httpOptions.method === 'GET') {
|
|
|
|
httpOptions.url = httpOptions.url + '?' + params.join('&');
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
httpOptions.data = params.join('&');
|
|
|
|
httpOptions.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
|
|
|
}
|
|
|
|
|
2014-11-12 15:39:04 +08:00
|
|
|
return this.doGraphiteRequest(httpOptions).then(this.convertDataPointsToMs);
|
2014-02-26 00:48:01 +08:00
|
|
|
}
|
|
|
|
catch(err) {
|
2014-02-26 04:31:30 +08:00
|
|
|
return $q.reject(err);
|
2014-02-21 06:00:32 +08:00
|
|
|
}
|
2014-02-26 00:48:01 +08:00
|
|
|
};
|
2014-02-21 06:00:32 +08:00
|
|
|
|
2014-11-12 15:39:04 +08:00
|
|
|
GraphiteDatasource.prototype.convertDataPointsToMs = function(result) {
|
|
|
|
if (!result || !result.data) { return []; }
|
|
|
|
for (var i = 0; i < result.data.length; i++) {
|
|
|
|
var series = result.data[i];
|
|
|
|
for (var y = 0; y < series.datapoints.length; y++) {
|
|
|
|
series.datapoints[y][1] *= 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
};
|
|
|
|
|
2014-08-27 22:29:48 +08:00
|
|
|
GraphiteDatasource.prototype.annotationQuery = function(annotation, rangeUnparsed) {
|
2014-07-19 19:16:47 +08:00
|
|
|
// Graphite metric as annotation
|
|
|
|
if (annotation.target) {
|
2014-08-27 23:58:49 +08:00
|
|
|
var target = templateSrv.replace(annotation.target);
|
2014-07-19 19:16:47 +08:00
|
|
|
var graphiteQuery = {
|
|
|
|
range: rangeUnparsed,
|
2014-07-30 19:09:23 +08:00
|
|
|
targets: [{ target: target }],
|
2014-07-19 19:16:47 +08:00
|
|
|
format: 'json',
|
|
|
|
maxDataPoints: 100
|
|
|
|
};
|
|
|
|
|
2014-08-27 23:58:49 +08:00
|
|
|
return this.query(graphiteQuery)
|
2014-07-19 19:16:47 +08:00
|
|
|
.then(function(result) {
|
|
|
|
var list = [];
|
2014-07-15 00:19:41 +08:00
|
|
|
|
2014-07-19 19:16:47 +08:00
|
|
|
for (var i = 0; i < result.data.length; i++) {
|
|
|
|
var target = result.data[i];
|
2014-07-15 00:19:41 +08:00
|
|
|
|
2014-07-19 19:16:47 +08:00
|
|
|
for (var y = 0; y < target.datapoints.length; y++) {
|
|
|
|
var datapoint = target.datapoints[y];
|
|
|
|
if (!datapoint[0]) { continue; }
|
2014-07-15 00:19:41 +08:00
|
|
|
|
2014-07-19 19:16:47 +08:00
|
|
|
list.push({
|
|
|
|
annotation: annotation,
|
2014-11-14 15:19:49 +08:00
|
|
|
time: datapoint[1],
|
2014-07-19 19:16:47 +08:00
|
|
|
title: target.target
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2014-07-15 00:19:41 +08:00
|
|
|
|
2014-07-19 19:16:47 +08:00
|
|
|
return list;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// Graphite event as annotation
|
2014-07-30 19:09:23 +08:00
|
|
|
else {
|
2014-08-27 23:58:49 +08:00
|
|
|
var tags = templateSrv.replace(annotation.tags);
|
2014-07-30 19:09:23 +08:00
|
|
|
return this.events({ range: rangeUnparsed, tags: tags })
|
2014-07-19 19:16:47 +08:00
|
|
|
.then(function(results) {
|
|
|
|
var list = [];
|
2014-07-30 19:09:23 +08:00
|
|
|
for (var i = 0; i < results.data.length; i++) {
|
|
|
|
var e = results.data[i];
|
2014-07-15 00:19:41 +08:00
|
|
|
list.push({
|
|
|
|
annotation: annotation,
|
2014-07-30 19:09:23 +08:00
|
|
|
time: e.when * 1000,
|
|
|
|
title: e.what,
|
|
|
|
tags: e.tags,
|
|
|
|
text: e.data
|
2014-07-15 00:19:41 +08:00
|
|
|
});
|
|
|
|
}
|
2014-07-19 19:16:47 +08:00
|
|
|
return list;
|
|
|
|
});
|
|
|
|
}
|
2014-07-15 00:19:41 +08:00
|
|
|
};
|
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
GraphiteDatasource.prototype.events = function(options) {
|
|
|
|
try {
|
|
|
|
var tags = '';
|
|
|
|
if (options.tags) {
|
|
|
|
tags = '&tags=' + options.tags;
|
|
|
|
}
|
2014-02-21 06:00:32 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
return this.doGraphiteRequest({
|
|
|
|
method: 'GET',
|
|
|
|
url: '/events/get_data?from=' + this.translateTime(options.range.from) + '&until=' + this.translateTime(options.range.to) + tags,
|
|
|
|
});
|
2014-02-15 20:46:36 +08:00
|
|
|
}
|
2014-02-26 00:48:01 +08:00
|
|
|
catch(err) {
|
2014-02-26 04:31:30 +08:00
|
|
|
return $q.reject(err);
|
2014-02-15 20:46:36 +08:00
|
|
|
}
|
2014-02-26 00:48:01 +08:00
|
|
|
};
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-07-22 00:49:30 +08:00
|
|
|
GraphiteDatasource.prototype.translateTime = function(date, rounding) {
|
2014-02-26 00:48:01 +08:00
|
|
|
if (_.isString(date)) {
|
|
|
|
if (date === 'now') {
|
|
|
|
return 'now';
|
|
|
|
}
|
|
|
|
else if (date.indexOf('now') >= 0) {
|
|
|
|
date = date.substring(3);
|
|
|
|
date = date.replace('m', 'min');
|
|
|
|
date = date.replace('M', 'mon');
|
|
|
|
return date;
|
|
|
|
}
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
date = kbn.parseDate(date);
|
|
|
|
}
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
date = moment.utc(date);
|
|
|
|
|
2014-04-18 22:06:21 +08:00
|
|
|
if (rounding === 'round-up') {
|
|
|
|
if (date.get('s')) {
|
2014-08-21 04:34:51 +08:00
|
|
|
date.add(1, 'm');
|
2014-04-18 22:06:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (rounding === 'round-down') {
|
|
|
|
// graphite' s from filter is exclusive
|
|
|
|
// here we step back one minute in order
|
|
|
|
// to guarantee that we get all the data that
|
|
|
|
// exists for the specified range
|
|
|
|
if (date.get('s')) {
|
2014-08-21 04:34:51 +08:00
|
|
|
date.subtract(1, 'm');
|
2014-04-18 22:06:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 22:09:19 +08:00
|
|
|
return date.unix();
|
2014-02-26 00:48:01 +08:00
|
|
|
};
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-08-27 22:29:48 +08:00
|
|
|
GraphiteDatasource.prototype.metricFindQuery = function(query) {
|
2014-02-26 00:48:01 +08:00
|
|
|
var interpolated;
|
|
|
|
try {
|
2014-08-27 23:58:49 +08:00
|
|
|
interpolated = encodeURIComponent(templateSrv.replace(query));
|
2014-02-26 00:48:01 +08:00
|
|
|
}
|
|
|
|
catch(err) {
|
2014-02-26 04:31:30 +08:00
|
|
|
return $q.reject(err);
|
2014-02-26 00:48:01 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return this.doGraphiteRequest({method: 'GET', url: '/metrics/find/?query=' + interpolated })
|
|
|
|
.then(function(results) {
|
|
|
|
return _.map(results.data, function(metric) {
|
|
|
|
return {
|
|
|
|
text: metric.text,
|
|
|
|
expandable: metric.expandable ? true : false
|
|
|
|
};
|
|
|
|
});
|
2014-02-15 20:46:36 +08:00
|
|
|
});
|
2014-02-26 00:48:01 +08:00
|
|
|
};
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
GraphiteDatasource.prototype.listDashboards = function(query) {
|
|
|
|
return this.doGraphiteRequest({ method: 'GET', url: '/dashboard/find/', params: {query: query || ''} })
|
|
|
|
.then(function(results) {
|
|
|
|
return results.data.dashboards;
|
|
|
|
});
|
|
|
|
};
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
GraphiteDatasource.prototype.loadDashboard = function(dashName) {
|
|
|
|
return this.doGraphiteRequest({method: 'GET', url: '/dashboard/load/' + encodeURIComponent(dashName) });
|
|
|
|
};
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
GraphiteDatasource.prototype.doGraphiteRequest = function(options) {
|
2014-12-08 22:35:55 +08:00
|
|
|
if (this.basicAuth || this.withCredentials) {
|
2014-02-26 00:48:01 +08:00
|
|
|
options.withCredentials = true;
|
2014-12-08 22:35:55 +08:00
|
|
|
}
|
|
|
|
if (this.basicAuth) {
|
2014-02-26 00:48:01 +08:00
|
|
|
options.headers = options.headers || {};
|
2014-03-01 03:16:24 +08:00
|
|
|
options.headers.Authorization = 'Basic ' + this.basicAuth;
|
2014-02-26 00:48:01 +08:00
|
|
|
}
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
options.url = this.url + options.url;
|
2014-08-10 20:03:10 +08:00
|
|
|
options.inspect = { type: 'graphite' };
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 04:31:30 +08:00
|
|
|
return $http(options);
|
2014-02-26 00:48:01 +08:00
|
|
|
};
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-09-03 02:59:54 +08:00
|
|
|
GraphiteDatasource.prototype._seriesRefLetters = [
|
|
|
|
'#A', '#B', '#C', '#D',
|
|
|
|
'#E', '#F', '#G', '#H',
|
|
|
|
'#I', '#J', '#K', '#L',
|
2015-01-05 17:02:03 +08:00
|
|
|
'#M', '#N', '#O', '#P',
|
|
|
|
'#Q', '#R', '#S', '#T',
|
|
|
|
'#U', '#V', '#W', '#X',
|
|
|
|
'#Y', '#Z'
|
2014-09-03 02:59:54 +08:00
|
|
|
];
|
|
|
|
|
2014-08-27 22:29:48 +08:00
|
|
|
GraphiteDatasource.prototype.buildGraphiteParams = function(options) {
|
2014-09-03 02:59:54 +08:00
|
|
|
var graphite_options = ['from', 'until', 'rawData', 'format', 'maxDataPoints', 'cacheTimeout'];
|
|
|
|
var clean_options = [], targets = {};
|
|
|
|
var target, targetValue, i;
|
|
|
|
var regex = /(\#[A-Z])/g;
|
2014-09-05 19:31:34 +08:00
|
|
|
var intervalFormatFixRegex = /'(\d+)m'/gi;
|
2014-02-26 00:48:01 +08:00
|
|
|
|
|
|
|
if (options.format !== 'png') {
|
|
|
|
options['format'] = 'json';
|
2014-02-15 20:46:36 +08:00
|
|
|
}
|
|
|
|
|
2014-09-05 19:31:34 +08:00
|
|
|
function fixIntervalFormat(match) {
|
|
|
|
return match.replace('m', 'min').replace('M', 'mon');
|
|
|
|
}
|
|
|
|
|
2014-09-03 02:59:54 +08:00
|
|
|
for (i = 0; i < options.targets.length; i++) {
|
|
|
|
target = options.targets[i];
|
2014-09-05 19:31:34 +08:00
|
|
|
if (!target.target) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-03 02:59:54 +08:00
|
|
|
targetValue = templateSrv.replace(target.target);
|
2014-09-05 19:31:34 +08:00
|
|
|
targetValue = targetValue.replace(intervalFormatFixRegex, fixIntervalFormat);
|
2014-09-03 02:59:54 +08:00
|
|
|
targets[this._seriesRefLetters[i]] = targetValue;
|
|
|
|
}
|
2014-02-26 00:48:01 +08:00
|
|
|
|
2014-09-03 02:59:54 +08:00
|
|
|
function nestedSeriesRegexReplacer(match) {
|
|
|
|
return targets[match];
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < options.targets.length; i++) {
|
|
|
|
target = options.targets[i];
|
|
|
|
if (!target.target || target.hide) {
|
|
|
|
continue;
|
2014-02-26 00:48:01 +08:00
|
|
|
}
|
2014-09-03 02:59:54 +08:00
|
|
|
|
|
|
|
targetValue = targets[this._seriesRefLetters[i]];
|
|
|
|
targetValue = targetValue.replace(regex, nestedSeriesRegexReplacer);
|
2015-01-23 17:29:54 +08:00
|
|
|
targets[this._seriesRefLetters[i]] = targetValue;
|
2014-09-03 02:59:54 +08:00
|
|
|
|
|
|
|
clean_options.push("target=" + encodeURIComponent(targetValue));
|
|
|
|
}
|
|
|
|
|
|
|
|
_.each(options, function (value, key) {
|
|
|
|
if ($.inArray(key, graphite_options) === -1) { return; }
|
2014-09-03 22:48:48 +08:00
|
|
|
if (value) {
|
|
|
|
clean_options.push(key + "=" + encodeURIComponent(value));
|
|
|
|
}
|
2014-09-03 02:59:54 +08:00
|
|
|
});
|
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
return clean_options;
|
|
|
|
};
|
|
|
|
|
|
|
|
return GraphiteDatasource;
|
2014-02-15 20:46:36 +08:00
|
|
|
|
2014-02-26 00:48:01 +08:00
|
|
|
});
|
2014-02-15 20:46:36 +08:00
|
|
|
|
|
|
|
});
|