Browse Source

Merge pull request #4460 from grafana/influxdb

[InfluxDB] Adds support for 0.11.0 tags
Carl Bergquist 9 years ago
parent
commit
ee92fee212

+ 60 - 59
public/app/plugins/datasource/influxdb/datasource.ts

@@ -6,35 +6,51 @@ import _ from 'lodash';
 import * as dateMath from 'app/core/utils/datemath';
 import InfluxSeries from './influx_series';
 import InfluxQuery from './influx_query';
+import ResponseParser from './response_parser';
+
+export default class InfluxDatasource {
+  type: string;
+  urls: any;
+  username: string;
+  password: string;
+  name: string;
+  database: any;
+  basicAuth: any;
+  interval: any;
+  supportAnnotations: boolean;
+  supportMetrics: boolean;
+  responseParser: any;
+
+  /** @ngInject */
+  constructor(instanceSettings, private $q, private backendSrv, private templateSrv) {
+    this.type = 'influxdb';
+    this.urls = _.map(instanceSettings.url.split(','), function(url) {
+      return url.trim();
+    });
+
+    this.username = instanceSettings.username;
+    this.password = instanceSettings.password;
+    this.name = instanceSettings.name;
+    this.database = instanceSettings.database;
+    this.basicAuth = instanceSettings.basicAuth;
+    this.interval = (instanceSettings.jsonData || {}).timeInterval;
+    this.supportAnnotations = true;
+    this.supportMetrics = true;
+    this.responseParser = new ResponseParser();
+  }
 
-/** @ngInject */
-export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) {
-  this.type = 'influxdb';
-  this.urls = _.map(instanceSettings.url.split(','), function(url) {
-    return url.trim();
-  });
-
-  this.username = instanceSettings.username;
-  this.password = instanceSettings.password;
-  this.name = instanceSettings.name;
-  this.database = instanceSettings.database;
-  this.basicAuth = instanceSettings.basicAuth;
-  this.interval = (instanceSettings.jsonData || {}).timeInterval;
-  this.supportAnnotations = true;
-  this.supportMetrics = true;
-
-  this.query = function(options) {
-    var timeFilter = getTimeFilter(options);
+  query(options) {
+    var timeFilter = this.getTimeFilter(options);
     var queryTargets = [];
     var i, y;
 
-    var allQueries = _.map(options.targets, function(target) {
+    var allQueries = _.map(options.targets, (target) => {
       if (target.hide) { return []; }
 
       queryTargets.push(target);
 
       // build query
-      var queryModel = new InfluxQuery(target, templateSrv, options.scopedVars);
+      var queryModel = new InfluxQuery(target, this.templateSrv, options.scopedVars);
       var query =  queryModel.render(true);
       query = query.replace(/\$interval/g, (target.interval || options.interval));
       return query;
@@ -45,9 +61,9 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
     allQueries = allQueries.replace(/\$timeFilter/g, timeFilter);
 
     // replace templated variables
-    allQueries = templateSrv.replace(allQueries, options.scopedVars);
+    allQueries = this.templateSrv.replace(allQueries, options.scopedVars);
 
-    return this._seriesQuery(allQueries).then(function(data): any {
+    return this._seriesQuery(allQueries).then((data): any => {
       if (!data || !data.results) {
         return [];
       }
@@ -60,7 +76,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
         var target = queryTargets[i];
         var alias = target.alias;
         if (alias) {
-          alias = templateSrv.replace(target.alias, options.scopedVars);
+          alias = this.templateSrv.replace(target.alias, options.scopedVars);
         }
 
         var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias });
@@ -84,16 +100,16 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
     });
   };
 
-  this.annotationQuery = function(options) {
+  annotationQuery(options) {
     if (!options.annotation.query) {
-      return $q.reject({message: 'Query missing in annotation definition'});
+      return this.$q.reject({message: 'Query missing in annotation definition'});
     }
 
-    var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw});
+    var timeFilter = this.getTimeFilter({rangeRaw: options.rangeRaw});
     var query = options.annotation.query.replace('$timeFilter', timeFilter);
-    query = templateSrv.replace(query);
+    query = this.templateSrv.replace(query);
 
-    return this._seriesQuery(query).then(function(data) {
+    return this._seriesQuery(query).then(data => {
       if (!data || !data.results || !data.results[0]) {
         throw { message: 'No results in response from InfluxDB' };
       }
@@ -101,44 +117,29 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
     });
   };
 
-  this.metricFindQuery = function (query) {
+  metricFindQuery(query) {
     var interpolated;
     try {
-      interpolated = templateSrv.replace(query, null, 'regex');
+      interpolated = this.templateSrv.replace(query, null, 'regex');
     } catch (err) {
-      return $q.reject(err);
+      return this.$q.reject(err);
     }
 
-    return this._seriesQuery(interpolated).then(function (results) {
-      if (!results || results.results.length === 0) { return []; }
-
-      var influxResults = results.results[0];
-      if (!influxResults.series) {
-        return [];
-      }
-
-      var series = influxResults.series[0];
-      return _.map(series.values, function(value) {
-        if (_.isArray(value)) {
-          return { text: value[0] };
-        } else {
-          return { text: value };
-        }
-      });
-    });
+    return this._seriesQuery(interpolated)
+      .then(_.curry(this.responseParser.parse)(query));
   };
 
-  this._seriesQuery = function(query) {
+  _seriesQuery(query) {
     return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'});
-  };
+  }
 
-  this.testDatasource = function() {
-    return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () {
+  testDatasource() {
+    return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(() => {
       return { status: "success", message: "Data source is working", title: "Success" };
     });
-  };
+  }
 
-  this._influxRequest = function(method, url, data) {
+  _influxRequest(method, url, data) {
     var self = this;
 
     var currentUrl = self.urls.shift();
@@ -172,7 +173,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
       options.headers.Authorization = self.basicAuth;
     }
 
-    return backendSrv.datasourceRequest(options).then(function(result) {
+    return this.backendSrv.datasourceRequest(options).then(result => {
       return result.data;
     }, function(err) {
       if (err.status !== 0 || err.status >= 300) {
@@ -185,9 +186,9 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
     });
   };
 
-  function getTimeFilter(options) {
-    var from = getInfluxTime(options.rangeRaw.from, false);
-    var until = getInfluxTime(options.rangeRaw.to, true);
+  getTimeFilter(options) {
+    var from = this.getInfluxTime(options.rangeRaw.from, false);
+    var until = this.getInfluxTime(options.rangeRaw.to, true);
     var fromIsAbsolute = from[from.length-1] === 's';
 
     if (until === 'now()' && !fromIsAbsolute) {
@@ -197,7 +198,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
     return 'time > ' + from + ' and time < ' + until;
   }
 
-  function getInfluxTime(date, roundUp) {
+  getInfluxTime(date, roundUp) {
     if (_.isString(date)) {
       if (date === 'now') {
         return 'now()';

+ 1 - 0
public/app/plugins/datasource/influxdb/influx_query.ts

@@ -11,6 +11,7 @@ export default class InfluxQuery {
   templateSrv: any;
   scopedVars: any;
 
+  /** @ngInject */
   constructor(target, templateSrv?, scopedVars?) {
     this.target = target;
     this.templateSrv = templateSrv;

+ 1 - 1
public/app/plugins/datasource/influxdb/module.ts

@@ -1,4 +1,4 @@
-import {InfluxDatasource} from './datasource';
+import InfluxDatasource from './datasource';
 import {InfluxQueryCtrl} from './query_ctrl';
 
 class InfluxConfigCtrl {

+ 28 - 0
public/app/plugins/datasource/influxdb/response_parser.ts

@@ -0,0 +1,28 @@
+///<reference path="../../../headers/common.d.ts" />
+
+import _ from 'lodash';
+
+export default class ResponseParser {
+
+  parse(query, results) {
+    if (!results || results.results.length === 0) { return []; }
+
+    var influxResults = results.results[0];
+    if (!influxResults.series) {
+      return [];
+    }
+
+    var series = influxResults.series[0];
+    return _.map(series.values, (value) => {
+      if (_.isArray(value)) {
+        if (query.indexOf('SHOW TAG VALUES') >= 0) {
+          return { text: (value[1] || value[0]) };
+        } else {
+          return { text: value[0] };
+        }
+      } else {
+        return { text: value };
+      }
+    });
+  }
+}

+ 133 - 0
public/app/plugins/datasource/influxdb/specs/response_parser_specs.ts

@@ -0,0 +1,133 @@
+import _ from 'lodash';
+import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
+import ResponseParser from '../response_parser';
+
+describe("influxdb response parser", () => {
+  this.parser = new ResponseParser();
+  describe("SHOW TAG response", () => {
+    var query = 'SHOW TAG KEYS FROM "cpu"';
+    var response = {
+      "results": [
+        {
+          "series": [
+            {
+              "name": "cpu",
+              "columns": ["tagKey"],
+              "values": [ ["datacenter"], ["hostname"], ["source"] ]
+            }
+          ]
+        }
+      ]
+    };
+
+    var result = this.parser.parse(query, response);
+
+    it("expects three results", () => {
+      expect(_.size(result)).to.be(3);
+    });
+  });
+
+  describe("SHOW TAG VALUES response", () => {
+    var query = 'SHOW TAG VALUES FROM "cpu" WITH KEY = "hostname"';
+
+    describe("response from 0.10.0", () => {
+      var response = {
+        "results": [
+          {
+            "series": [
+              {
+                "name": "hostnameTagValues",
+                "columns": ["hostname"],
+                "values": [ ["server1"], ["server2"] ]
+              }
+            ]
+          }
+        ]
+      };
+
+      var result = this.parser.parse(query, response);
+
+      it("should get two responses", () => {
+        expect(_.size(result)).to.be(2);
+        expect(result[0].text).to.be("server1");
+        expect(result[1].text).to.be("server2");
+      });
+    });
+
+    describe("response from 0.11.0", () => {
+      var response = {
+        "results": [
+           {
+             "series": [
+               {
+                 "name": "cpu",
+                 "columns": [ "key", "value"],
+                 "values": [ [ "source", "site" ], [ "source", "api" ] ]
+               }
+             ]
+           }
+        ]
+      };
+
+      var result = this.parser.parse(query, response);
+
+      it("should get two responses", () => {
+        expect(_.size(result)).to.be(2);
+        expect(result[0].text).to.be('site');
+        expect(result[1].text).to.be('api');
+      });
+    });
+
+
+
+
+  });
+
+  describe("SHOW FIELD response", () => {
+    var query = 'SHOW FIELD KEYS FROM "cpu"';
+    describe("response from 0.10.0", () => {
+      var response = {
+        "results": [
+          {
+            "series": [
+              {
+                "name": "measurements",
+                "columns": ["name"],
+                "values": [
+                  ["cpu"], ["derivative"], ["logins.count"], ["logs"], ["payment.ended"], ["payment.started"]
+                ]
+              }
+            ]
+          }
+        ]
+      };
+
+      var result = this.parser.parse(query, response);
+      it("should get two responses", () => {
+        expect(_.size(result)).to.be(6);
+      });
+    });
+
+    describe("response from 0.11.0", () => {
+      var response = {
+        "results": [
+          {
+            "series": [
+              {
+                "name": "cpu",
+                "columns": ["fieldKey"],
+                "values": [ [ "value"] ]
+              }
+            ]
+          }
+        ]
+      };
+
+      var result = this.parser.parse(query, response);
+
+      it("should get two responses", () => {
+        expect(_.size(result)).to.be(1);
+      });
+    });
+  });
+});