Prechádzať zdrojové kódy

feat: Elasticsearch change to how queries without date histogram are transformed into Grafana data stucture, now it is processed into a table structure instead of json structure

Torkel Ödegaard 8 rokov pred
rodič
commit
ede827f5c0

+ 9 - 0
public/app/core/table_model.ts

@@ -3,9 +3,11 @@ export default class TableModel {
   columns: any[];
   rows: any[];
   type: string;
+  columnMap: any;
 
   constructor() {
     this.columns = [];
+    this.columnMap = {};
     this.rows = [];
     this.type = 'table';
   }
@@ -36,4 +38,11 @@ export default class TableModel {
       this.columns[options.col].desc = false;
     }
   }
+
+  addColumn(col) {
+    if (!this.columnMap[col.text]) {
+      this.columns.push(col);
+      this.columnMap[col.text] = col;
+    }
+  }
 }

+ 37 - 23
public/app/plugins/datasource/elasticsearch/elastic_response.ts

@@ -2,6 +2,7 @@
 
 import  _ from 'lodash';
 import queryDef from "./query_def";
+import TableModel from 'app/core/table_model';
 
 export function ElasticResponse(targets, response) {
   this.targets = targets;
@@ -95,21 +96,35 @@ ElasticResponse.prototype.processMetrics = function(esAgg, target, seriesList, p
   }
 };
 
-ElasticResponse.prototype.processAggregationDocs = function(esAgg, aggDef, target, docs, props) {
-  var metric, y, i, bucket, metricName, doc;
+ElasticResponse.prototype.processAggregationDocs = function(esAgg, aggDef, target, table, props) {
+  // add columns
+  if (table.columns.length === 0) {
+    for (let propKey of _.keys(props)) {
+      table.addColumn({text: propKey});
+    }
+    table.addColumn({text: aggDef.field});
+  }
+
+  // helper func to add values to value array
+  let addMetricValue = (values, metricName, value) => {
+    table.addColumn({text: metricName});
+    values.push(value);
+  };
 
-  for (i = 0; i < esAgg.buckets.length; i++) {
-    bucket = esAgg.buckets[i];
-    doc = _.defaults({}, props);
-    doc[aggDef.field] = bucket.key;
+  for (let bucket of esAgg.buckets) {
+    let values = [];
+
+    for (let propValues of _.values(props)) {
+      values.push(propValues);
+    }
 
-    for (y = 0; y < target.metrics.length; y++) {
-      metric = target.metrics[y];
+    // add bucket key (value)
+    values.push(bucket.key);
 
+    for (let metric of target.metrics) {
       switch (metric.type) {
         case "count": {
-          metricName = this._getMetricName(metric.type);
-          doc[metricName] = bucket.doc_count;
+          addMetricValue(values, this._getMetricName(metric.type), bucket.doc_count);
           break;
         }
         case 'extended_stats': {
@@ -123,33 +138,32 @@ ElasticResponse.prototype.processAggregationDocs = function(esAgg, aggDef, targe
             stats.std_deviation_bounds_upper = stats.std_deviation_bounds.upper;
             stats.std_deviation_bounds_lower = stats.std_deviation_bounds.lower;
 
-            metricName = this._getMetricName(statName);
-            doc[metricName] = stats[statName];
+            addMetricValue(values, this._getMetricName(statName), stats[statName]);
           }
           break;
         }
         default:  {
-          metricName = this._getMetricName(metric.type);
-          var otherMetrics = _.filter(target.metrics, {type: metric.type});
+          let metricName = this._getMetricName(metric.type);
+          let otherMetrics = _.filter(target.metrics, {type: metric.type});
 
           // if more of the same metric type include field field name in property
           if (otherMetrics.length > 1) {
             metricName += ' ' + metric.field;
           }
 
-          doc[metricName] = bucket[metric.id].value;
+          addMetricValue(values, metricName, bucket[metric.id].value);
           break;
         }
       }
     }
 
-    docs.push(doc);
+    table.rows.push(values);
   }
 };
 
 // This is quite complex
 // neeed to recurise down the nested buckets to build series
-ElasticResponse.prototype.processBuckets = function(aggs, target, seriesList, docs, props, depth) {
+ElasticResponse.prototype.processBuckets = function(aggs, target, seriesList, table, props, depth) {
   var bucket, aggDef, esAgg, aggId;
   var maxDepth = target.bucketAggs.length-1;
 
@@ -165,7 +179,7 @@ ElasticResponse.prototype.processBuckets = function(aggs, target, seriesList, do
       if (aggDef.type === 'date_histogram')  {
         this.processMetrics(esAgg, target, seriesList, props);
       } else {
-        this.processAggregationDocs(esAgg, aggDef, target, docs, props);
+        this.processAggregationDocs(esAgg, aggDef, target, table, props);
       }
     } else {
       for (var nameIndex in esAgg.buckets) {
@@ -179,7 +193,7 @@ ElasticResponse.prototype.processBuckets = function(aggs, target, seriesList, do
         if (bucket.key_as_string) {
           props[aggDef.field] = bucket.key_as_string;
         }
-        this.processBuckets(bucket, target, seriesList, docs, props, depth+1);
+        this.processBuckets(bucket, target, seriesList, table, props, depth+1);
       }
     }
   }
@@ -325,9 +339,9 @@ ElasticResponse.prototype.getTimeSeries = function() {
       var aggregations = response.aggregations;
       var target = this.targets[i];
       var tmpSeriesList = [];
-      var docs = [];
+      var table = new TableModel();
 
-      this.processBuckets(aggregations, target, tmpSeriesList, docs, {}, 0);
+      this.processBuckets(aggregations, target, tmpSeriesList, table, {}, 0);
       this.trimDatapoints(tmpSeriesList, target);
       this.nameSeries(tmpSeriesList, target);
 
@@ -335,8 +349,8 @@ ElasticResponse.prototype.getTimeSeries = function() {
         seriesList.push(tmpSeriesList[y]);
       }
 
-      if (seriesList.length === 0 && docs.length > 0) {
-        seriesList.push({target: 'docs', type: 'docs', datapoints: docs});
+      if (table.rows.length > 0) {
+        seriesList.push(table);
       }
     }
   }

+ 14 - 16
public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts

@@ -387,10 +387,9 @@ describe('ElasticResponse', function() {
       result = new ElasticResponse(targets, response).getTimeSeries();
     });
 
-    it('should return docs with byte and count', function() {
-      expect(result.data[0].datapoints.length).to.be(3);
-      expect(result.data[0].datapoints[0].Count).to.be(1);
-      expect(result.data[0].datapoints[0].bytes).to.be(1000);
+    it('should return table with byte and count', function() {
+      expect(result.data[0].rows.length).to.be(3);
+      expect(result.data[0].columns).to.eql([{text: 'bytes'}, {text: 'Count'}]);
     });
   });
 
@@ -530,14 +529,14 @@ describe('ElasticResponse', function() {
 
     it('should return table', function() {
       expect(result.data.length).to.be(1);
-      expect(result.data[0].type).to.be('docs');
-      expect(result.data[0].datapoints.length).to.be(2);
-      expect(result.data[0].datapoints[0].host).to.be("server-1");
-      expect(result.data[0].datapoints[0].Average).to.be(1000);
-      expect(result.data[0].datapoints[0].Count).to.be(369);
-
-      expect(result.data[0].datapoints[1].host).to.be("server-2");
-      expect(result.data[0].datapoints[1].Average).to.be(2000);
+      expect(result.data[0].type).to.be('table');
+      expect(result.data[0].rows.length).to.be(2);
+      expect(result.data[0].rows[0][0]).to.be("server-1");
+      expect(result.data[0].rows[0][1]).to.be(1000);
+      expect(result.data[0].rows[0][2]).to.be(369);
+
+      expect(result.data[0].rows[1][0]).to.be("server-2");
+      expect(result.data[0].rows[1][1]).to.be(2000);
     });
   });
 
@@ -573,10 +572,9 @@ describe('ElasticResponse', function() {
     });
 
     it('should include field in metric name', function() {
-      expect(result.data[0].type).to.be('docs');
-      expect(result.data[0].datapoints[0].Average).to.be(undefined);
-      expect(result.data[0].datapoints[0]['Average test']).to.be(1000);
-      expect(result.data[0].datapoints[0]['Average test2']).to.be(3000);
+      expect(result.data[0].type).to.be('table');
+      expect(result.data[0].rows[0][1]).to.be(1000);
+      expect(result.data[0].rows[0][2]).to.be(3000);
     });
   });