diff --git a/CHANGELOG.md b/CHANGELOG.md index 15bfe325b0c..c046d3364cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - [Issue #1525](https://github.com/grafana/grafana/issues/1525). InfluxDB: Full support for InfluxDB 0.9 with new adapted query editor - [Issue #2191](https://github.com/grafana/grafana/issues/2191). KariosDB: Grafana now ships with a KariosDB data source plugin, thx @masaori335 - [Issue #1177](https://github.com/grafana/grafana/issues/1177). OpenTSDB: Limit tags by metric, OpenTSDB config option tsd.core.meta.enable_realtime_ts must enabled for OpenTSDB lookup api +- [Issue #1250](https://github.com/grafana/grafana/issues/1250). OpenTSDB: Support for template variable values lookup queries **New dashboard features** - [Issue #1144](https://github.com/grafana/grafana/issues/1144). Templating: You can now select multiple template variables values at the same time. diff --git a/public/app/plugins/datasource/opentsdb/datasource.js b/public/app/plugins/datasource/opentsdb/datasource.js index d244b56436e..80d51ed01c2 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.js +++ b/public/app/plugins/datasource/opentsdb/datasource.js @@ -76,35 +76,20 @@ function (angular, _, kbn) { return backendSrv.datasourceRequest(options); }; - OpenTSDBDatasource.prototype.performSuggestQuery = function(query, type) { - var options = { - method: 'GET', - url: this.url + '/api/suggest', - params: { - type: type, - q: query - } - }; - return backendSrv.datasourceRequest(options).then(function(result) { + OpenTSDBDatasource.prototype._performSuggestQuery = function(query) { + return this._get('/api/suggest', {type: 'metrics', q: query}).then(function(result) { return result.data; }); }; - OpenTSDBDatasource.prototype.performMetricKeyValueLookup = function(metric, key) { + OpenTSDBDatasource.prototype._performMetricKeyValueLookup = function(metric, key) { if(!metric || !key) { return $q.when([]); } var m = metric + "{" + key + "=*}"; - var options = { - method: 'GET', - url: this.url + '/api/search/lookup', - params: { - m: m, - } - }; - return backendSrv.datasourceRequest(options).then(function(result) { + return this._get('/api/search/lookup', {m: m}).then(function(result) { result = result.data.results; var tagvs = []; _.each(result, function(r) { @@ -114,18 +99,10 @@ function (angular, _, kbn) { }); }; - OpenTSDBDatasource.prototype.performMetricKeyLookup = function(metric) { - if(metric === "") { - throw "Metric not set."; - } - var options = { - method: 'GET', - url: this.url + '/api/search/lookup', - params: { - m: metric, - } - }; - return backendSrv.datasourceRequest(options).then(function(result) { + OpenTSDBDatasource.prototype._performMetricKeyLookup = function(metric) { + if(!metric) { return $q.when([]); } + + return this._get('/api/search/lookup', {m: metric}).then(function(result) { result = result.data.results; var tagks = []; _.each(result, function(r) { @@ -139,6 +116,49 @@ function (angular, _, kbn) { }); }; + OpenTSDBDatasource.prototype._get = function(relativeUrl, params) { + return backendSrv.datasourceRequest({ + method: 'GET', + url: this.url + relativeUrl, + params: params, + }); + }; + + OpenTSDBDatasource.prototype.metricFindQuery = function(query) { + var interpolated; + try { + interpolated = templateSrv.replace(query); + } + catch (err) { + return $q.reject(err); + } + + var responseTransform = function(result) { + return _.map(result, function(value) { + return {text: value}; + }); + }; + + var metrics_regex = /metrics\((.*)\)/; + var tag_names_regex = /tag_names\((.*)\)/; + var tag_values_regex = /tag_values\((\w+),\s?(\w+)/; + + var metrics_query = interpolated.match(metrics_regex); + if (metrics_query) { + return this._performSuggestQuery(metrics_query[1]).then(responseTransform); + } + var tag_names_query = interpolated.match(tag_names_regex); + + if (tag_names_query) { + return this._performMetricKeyLookup(tag_names_query[1]).then(responseTransform); + } + + var tag_values_query = interpolated.match(tag_values_regex); + if (tag_values_query) { + return this._performMetricKeyValueLookup(tag_values_query[1], tag_values_query[2]).then(responseTransform); + } + }; + OpenTSDBDatasource.prototype.testDatasource = function() { return this.performSuggestQuery('cpu', 'metrics').then(function () { return { status: "success", message: "Data source is working", title: "Success" }; diff --git a/public/app/plugins/datasource/opentsdb/queryCtrl.js b/public/app/plugins/datasource/opentsdb/queryCtrl.js index 17a2f4bd640..0f6ad54eed3 100644 --- a/public/app/plugins/datasource/opentsdb/queryCtrl.js +++ b/public/app/plugins/datasource/opentsdb/queryCtrl.js @@ -42,21 +42,25 @@ function (angular, _, kbn) { $scope.panel.targets.push(clone); }; + $scope.getTextValues = function(metricFindResult) { + return _.map(metricFindResult, function(value) { return value.text; }); + }; + $scope.suggestMetrics = function(query, callback) { - $scope.datasource - .performSuggestQuery(query, 'metrics') + $scope.datasource.metricFindQuery('metrics()') + .then($scope.getTextValues) .then(callback); }; $scope.suggestTagKeys = function(query, callback) { - $scope.datasource - .performMetricKeyLookup($scope.target.metric) + $scope.datasource.metricFindQuery('tag_names(' + $scope.target.metric + ')') + .then($scope.getTextValues) .then(callback); }; $scope.suggestTagValues = function(query, callback) { - $scope.datasource - .performMetricKeyValueLookup($scope.target.metric, $scope.target.currentTagKey) + $scope.datasource.metricFindQuery('tag_names(' + $scope.target.metric + ',' + $scope.target.currentTagKey + ')') + .then($scope.getTextValues) .then(callback); }; diff --git a/public/test/specs/opentsdbDatasource-specs.js b/public/test/specs/opentsdbDatasource-specs.js new file mode 100644 index 00000000000..ace7e21292a --- /dev/null +++ b/public/test/specs/opentsdbDatasource-specs.js @@ -0,0 +1,52 @@ +define([ + 'helpers', + 'plugins/datasource/opentsdb/datasource' +], function(helpers) { + 'use strict'; + + describe('opentsdb', function() { + var ctx = new helpers.ServiceTestContext(); + + beforeEach(module('grafana.services')); + beforeEach(ctx.providePhase(['backendSrv'])); + + beforeEach(ctx.createService('OpenTSDBDatasource')); + beforeEach(function() { + ctx.ds = new ctx.service({ url: [''] }); + }); + + describe('When performing metricFindQuery', function() { + var results; + var requestOptions; + + beforeEach(function() { + ctx.backendSrv.datasourceRequest = function(options) { + requestOptions = options; + return ctx.$q.when({data: [{ target: 'prod1.count', datapoints: [[10, 1], [12,1]] }]}); + }; + }); + + it('metrics() should generate api suggest query', function() { + ctx.ds.metricFindQuery('metrics()').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/suggest'); + }); + + it('tag_names(cpu) should generate looku query', function() { + ctx.ds.metricFindQuery('tag_names(cpu)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/search/lookup'); + expect(requestOptions.params.m).to.be('cpu'); + }); + + it('tag_values(cpu, test) should generate looku query', function() { + ctx.ds.metricFindQuery('tag_values(cpu, hostname)').then(function(data) { results = data; }); + ctx.$rootScope.$apply(); + expect(requestOptions.url).to.be('/api/search/lookup'); + expect(requestOptions.params.m).to.be('cpu{hostname=*}'); + }); + + }); + }); +}); + diff --git a/public/test/test-main.js b/public/test/test-main.js index 5d761b8d3ea..e6e18512216 100644 --- a/public/test/test-main.js +++ b/public/test/test-main.js @@ -146,6 +146,7 @@ require([ 'specs/dynamicDashboardSrv-specs', 'specs/unsavedChangesSrv-specs', 'specs/valueSelectDropdown-specs', + 'specs/opentsdbDatasource-specs', ]; var pluginSpecs = (config.plugins.specs || []).map(function (spec) {