Sfoglia il codice sorgente

feat(influxdb): support for table queries, closes #3409, #3219

Torkel Ödegaard 10 anni fa
parent
commit
cf1f43dc9d

+ 5 - 18
public/app/panels/table/table_model.ts → public/app/core/table_model.ts

@@ -1,12 +1,13 @@
-import {transformers} from './transformers';
 
 
-export class TableModel {
+class TableModel {
   columns: any[];
   columns: any[];
   rows: any[];
   rows: any[];
+  type: string;
 
 
   constructor() {
   constructor() {
     this.columns = [];
     this.columns = [];
     this.rows = [];
     this.rows = [];
+    this.type = 'table';
   }
   }
 
 
   sort(options) {
   sort(options) {
@@ -33,20 +34,6 @@ export class TableModel {
       this.columns[options.col].desc = true;
       this.columns[options.col].desc = true;
     }
     }
   }
   }
-
-  static transform(data, panel) {
-    var model = new TableModel();
-
-    if (!data || data.length === 0) {
-      return model;
-    }
-
-    var transformer = transformers[panel.transform];
-    if (!transformer) {
-      throw {message: 'Transformer ' + panel.transformer + ' not found'};
-    }
-
-    transformer.transform(data, panel, model);
-    return model;
-  }
 }
 }
+
+export = TableModel;

+ 18 - 2
public/app/panels/table/controller.ts

@@ -5,7 +5,7 @@ import _ = require('lodash');
 import moment = require('moment');
 import moment = require('moment');
 import PanelMeta = require('app/features/panel/panel_meta');
 import PanelMeta = require('app/features/panel/panel_meta');
 
 
-import {TableModel} from './table_model';
+import {transformDataToTable} from './transformers';
 
 
 export class TablePanelCtrl {
 export class TablePanelCtrl {
 
 
@@ -104,7 +104,23 @@ export class TablePanelCtrl {
     };
     };
 
 
     $scope.render = function() {
     $scope.render = function() {
-      $scope.table = TableModel.transform($scope.dataRaw, $scope.panel);
+      // automatically correct transform mode
+      // based on data
+      if ($scope.dataRaw && $scope.dataRaw.length) {
+        if ($scope.dataRaw[0].type === 'table') {
+          $scope.panel.transform = 'table';
+        } else {
+          if ($scope.dataRaw[0].type === 'docs') {
+            $scope.panel.transform = 'json';
+          } else {
+            if ($scope.panel.transform === 'table' || $scope.panel.transform === 'json') {
+              $scope.panel.transform = 'timeseries_to_rows';
+            }
+          }
+        }
+      }
+
+      $scope.table = transformDataToTable($scope.dataRaw, $scope.panel);
       $scope.table.sort($scope.panel.sort);
       $scope.table.sort($scope.panel.sort);
       panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw);
       panelHelper.broadcastRender($scope, $scope.table, $scope.dataRaw);
     };
     };

+ 1 - 1
public/app/panels/table/specs/renderer_specs.ts

@@ -1,6 +1,6 @@
 import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
 import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
 
 
-import {TableModel} from '../table_model';
+import TableModel = require('app/core/table_model');
 import {TableRenderer} from '../renderer';
 import {TableRenderer} from '../renderer';
 
 
 describe('when rendering table', () => {
 describe('when rendering table', () => {

+ 6 - 7
public/app/panels/table/specs/transformers_specs.ts

@@ -1,7 +1,6 @@
 import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
 import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
 
 
-import {TableModel} from '../table_model';
-import {transformers} from '../transformers';
+import {transformers, transformDataToTable} from '../transformers';
 
 
 describe('when transforming time series table', () => {
 describe('when transforming time series table', () => {
   var table;
   var table;
@@ -26,7 +25,7 @@ describe('when transforming time series table', () => {
       };
       };
 
 
       beforeEach(() => {
       beforeEach(() => {
-        table = TableModel.transform(timeSeries, panel);
+        table = transformDataToTable(timeSeries, panel);
       });
       });
 
 
       it('should return 3 rows', () => {
       it('should return 3 rows', () => {
@@ -51,7 +50,7 @@ describe('when transforming time series table', () => {
       };
       };
 
 
       beforeEach(() => {
       beforeEach(() => {
-        table = TableModel.transform(timeSeries, panel);
+        table = transformDataToTable(timeSeries, panel);
       });
       });
 
 
       it ('should return 3 columns', () => {
       it ('should return 3 columns', () => {
@@ -80,7 +79,7 @@ describe('when transforming time series table', () => {
       };
       };
 
 
       beforeEach(() => {
       beforeEach(() => {
-        table = TableModel.transform(timeSeries, panel);
+        table = transformDataToTable(timeSeries, panel);
       });
       });
 
 
       it('should return 2 rows', () => {
       it('should return 2 rows', () => {
@@ -133,7 +132,7 @@ describe('when transforming time series table', () => {
 
 
       describe('transform', function() {
       describe('transform', function() {
         beforeEach(() => {
         beforeEach(() => {
-          table = TableModel.transform(rawData, panel);
+          table = transformDataToTable(rawData, panel);
         });
         });
 
 
         it ('should return 2 columns', () => {
         it ('should return 2 columns', () => {
@@ -164,7 +163,7 @@ describe('when transforming time series table', () => {
       ];
       ];
 
 
       beforeEach(() => {
       beforeEach(() => {
-        table = TableModel.transform(rawData, panel);
+        table = transformDataToTable(rawData, panel);
       });
       });
 
 
       it ('should return 4 columns', () => {
       it ('should return 4 columns', () => {

+ 39 - 1
public/app/panels/table/transformers.ts

@@ -4,6 +4,7 @@ import moment = require('moment');
 import _ = require('lodash');
 import _ = require('lodash');
 import flatten = require('app/core/utils/flatten');
 import flatten = require('app/core/utils/flatten');
 import TimeSeries = require('app/core/time_series');
 import TimeSeries = require('app/core/time_series');
+import TableModel = require('app/core/table_model');
 
 
 var transformers = {};
 var transformers = {};
 
 
@@ -136,6 +137,27 @@ transformers['annotations'] = {
   }
   }
 };
 };
 
 
+transformers['table'] = {
+  description: 'Table',
+  getColumns: function(data) {
+    if (!data || data.length === 0) {
+      return [];
+    }
+  },
+  transform: function(data, panel, model) {
+    if (!data || data.length === 0) {
+      return;
+    }
+
+    if (data[0].type !== 'table') {
+      throw {message: 'Query result is not in table format, try using another transform.'};
+    }
+
+    model.columns = data[0].columns;
+    model.rows = data[0].rows;
+  }
+};
+
 transformers['json'] = {
 transformers['json'] = {
   description: 'JSON Data',
   description: 'JSON Data',
   getColumns: function(data) {
   getColumns: function(data) {
@@ -197,4 +219,20 @@ transformers['json'] = {
   }
   }
 };
 };
 
 
-export {transformers}
+function transformDataToTable(data, panel) {
+  var model = new TableModel();
+
+  if (!data || data.length === 0) {
+    return model;
+  }
+
+  var transformer = transformers[panel.transform];
+  if (!transformer) {
+    throw {message: 'Transformer ' + panel.transformer + ' not found'};
+  }
+
+  transformer.transform(data, panel, model);
+  return model;
+}
+
+export {transformers, transformDataToTable}

+ 19 - 5
public/app/plugins/datasource/influxdb/datasource.js

@@ -53,6 +53,7 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) {
 
 
       // replace templated variables
       // replace templated variables
       allQueries = templateSrv.replace(allQueries, options.scopedVars);
       allQueries = templateSrv.replace(allQueries, options.scopedVars);
+
       return this._seriesQuery(allQueries).then(function(data) {
       return this._seriesQuery(allQueries).then(function(data) {
         if (!data || !data.results) {
         if (!data || !data.results) {
           return [];
           return [];
@@ -63,13 +64,26 @@ function (angular, _, dateMath, InfluxSeries, InfluxQuery) {
           var result = data.results[i];
           var result = data.results[i];
           if (!result || !result.series) { continue; }
           if (!result || !result.series) { continue; }
 
 
-          var alias = (queryTargets[i] || {}).alias;
+          var target = queryTargets[i];
+          var alias = target.alias;
           if (alias) {
           if (alias) {
-            alias = templateSrv.replace(alias, options.scopedVars);
+            alias = templateSrv.replace(target.alias, options.scopedVars);
           }
           }
-          var targetSeries = new InfluxSeries({ series: data.results[i].series, alias: alias }).getTimeSeries();
-          for (y = 0; y < targetSeries.length; y++) {
-            seriesList.push(targetSeries[y]);
+
+          var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias });
+
+          switch(target.resultFormat) {
+            case 'table': {
+              seriesList.push(influxSeries.getTable());
+              break;
+            }
+            default: {
+              var timeSeries = influxSeries.getTimeSeries();
+              for (y = 0; y < timeSeries.length; y++) {
+                seriesList.push(timeSeries[y]);
+              }
+              break;
+            }
           }
           }
         }
         }
 
 

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

@@ -12,6 +12,8 @@ class InfluxQuery {
   constructor(target) {
   constructor(target) {
     this.target = target;
     this.target = target;
 
 
+    target.dsType = 'influxdb';
+    target.resultFormat = target.resultFormat || 'time_series';
     target.tags = target.tags || [];
     target.tags = target.tags || [];
     target.groupBy = target.groupBy || [
     target.groupBy = target.groupBy || [
       {type: 'time', params: ['$interval']},
       {type: 'time', params: ['$interval']},

+ 41 - 1
public/app/plugins/datasource/influxdb/influx_series.js

@@ -1,7 +1,8 @@
 define([
 define([
   'lodash',
   'lodash',
+  'app/core/table_model',
 ],
 ],
-function (_) {
+function (_, TableModel) {
   'use strict';
   'use strict';
 
 
   function InfluxSeries(options) {
   function InfluxSeries(options) {
@@ -108,5 +109,44 @@ function (_) {
     return list;
     return list;
   };
   };
 
 
+  p.getTable = function() {
+    var table = new TableModel();
+    var self = this;
+    var i, j;
+
+    if (self.series.length === 0) {
+      return table;
+    }
+
+    _.each(self.series, function(series, seriesIndex) {
+
+      if (seriesIndex === 0) {
+        table.columns.push({text: 'Time', type: 'time'});
+        _.each(_.keys(series.tags), function(key) {
+          table.columns.push({text: key});
+        });
+        for (j = 1; j < series.columns.length; j++) {
+          table.columns.push({text: series.columns[j]});
+        }
+      }
+
+      if (series.values) {
+        for (i = 0; i < series.values.length; i++) {
+          var values = series.values[i];
+          if (series.tags) {
+            for (var key in series.tags) {
+              if (series.tags.hasOwnProperty(key)) {
+                values.splice(1, 0, series.tags[key]);
+              }
+            }
+          }
+          table.rows.push(values);
+        }
+      }
+    });
+
+    return table;
+  };
+
   return InfluxSeries;
   return InfluxSeries;
 });
 });

+ 6 - 0
public/app/plugins/datasource/influxdb/partials/query.editor.html

@@ -103,6 +103,12 @@
 			<li>
 			<li>
 				<input type="text" class="tight-form-clear-input input-xlarge" ng-model="target.alias" spellcheck='false' placeholder="Naming pattern" ng-blur="get_data()">
 				<input type="text" class="tight-form-clear-input input-xlarge" ng-model="target.alias" spellcheck='false' placeholder="Naming pattern" ng-blur="get_data()">
 			</li>
 			</li>
+			<li class="tight-form-item">
+				Format as
+			</li>
+			<li>
+				<select class="input-small tight-form-input" style="width: 104px" ng-model="target.resultFormat" ng-options="f.value as f.text for f in resultFormats" ng-change="get_data()"></select>
+			</li>
 		</ul>
 		</ul>
 		<div class="clearfix"></div>
 		<div class="clearfix"></div>
 	</div>
 	</div>

+ 5 - 0
public/app/plugins/datasource/influxdb/query_ctrl.js

@@ -20,6 +20,11 @@ function (angular, _, InfluxQueryBuilder, InfluxQuery, queryPart) {
       $scope.queryModel = new InfluxQuery($scope.target);
       $scope.queryModel = new InfluxQuery($scope.target);
       $scope.queryBuilder = new InfluxQueryBuilder($scope.target);
       $scope.queryBuilder = new InfluxQueryBuilder($scope.target);
       $scope.groupBySegment = uiSegmentSrv.newPlusButton();
       $scope.groupBySegment = uiSegmentSrv.newPlusButton();
+      $scope.resultFormats = [
+         {text: 'Time series', value: 'time_series'},
+         {text: 'Table', value: 'table'},
+         {text: 'JSON field', value: 'json_field'},
+      ];
 
 
       if (!$scope.target.measurement) {
       if (!$scope.target.measurement) {
         $scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();
         $scope.measurementSegment = uiSegmentSrv.newSelectMeasurement();

+ 23 - 0
public/app/plugins/datasource/influxdb/specs/influx_series_specs.ts

@@ -186,5 +186,28 @@ describe('when generating timeseries from influxdb response', function() {
     });
     });
   });
   });
 
 
+  describe('given table response', function() {
+    var options = {
+      alias: '',
+      series: [
+        {
+          name: 'app.prod.server1.count',
+          tags:  {},
+          columns: ['time', 'datacenter', 'value'],
+          values: [[1431946625000, 'America', 10], [1431946626000, 'EU', 12]]
+        }
+      ]
+    };
+
+    it('should return table', function() {
+      var series = new InfluxSeries(options);
+      var table = series.getTable();
+
+      expect(table.type).to.be('table');
+      expect(table.columns.length).to.be(3);
+      expect(table.rows[0]).to.eql([1431946625000, 'America', 10]);;
+    });
+  });
+
 });
 });
 
 

+ 1 - 1
public/app/panels/table/specs/table_model_specs.ts → public/test/core/table_model_specs.ts

@@ -1,6 +1,6 @@
 import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
 import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
 
 
-import {TableModel} from '../table_model';
+import TableModel = require('app/core/table_model');
 
 
 describe('when sorting table desc', () => {
 describe('when sorting table desc', () => {
   var table;
   var table;