Browse Source

When converting Prometheus results to table, handle the case where the returned series have non-uniform sets of labels. (#8826)

Alin Sinpalean 8 years ago
parent
commit
5bffdfe9a4

+ 28 - 14
public/app/plugins/datasource/prometheus/datasource.ts

@@ -275,32 +275,46 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
     return { target: metricLabel, datapoints: dps };
   };
 
-  this.transformMetricDataToTable = function(series) {
+  this.transformMetricDataToTable = function(md) {
     var table = new TableModel();
-    var self = this;
     var i, j;
+    var metricLabels = {};
 
-    if (series.length === 0) {
+    if (md.length === 0) {
       return table;
     }
 
-    _.each(series, function(series, seriesIndex) {
-      if (seriesIndex === 0) {
-        table.columns.push({text: 'Time', type: 'time'});
-        _.each(_.keys(series.metric), function(key) {
-          table.columns.push({text: key});
-        });
-        table.columns.push({text: 'Value'});
+    // Collect all labels across all metrics
+    _.each(md, function(series) {
+      for (var label in series.metric) {
+        if (!metricLabels.hasOwnProperty(label)) {
+          metricLabels[label] = 1;
+        }
       }
+    });
+
+    // Sort metric labels, create columns for them and record their index
+    var sortedLabels = _.keys(metricLabels).sort();
+    table.columns.push({text: 'Time', type: 'time'});
+    _.each(sortedLabels, function(label, labelIndex) {
+      metricLabels[label] = labelIndex + 1;
+      table.columns.push({text: label});
+    });
+    table.columns.push({text: 'Value'});
 
+    // Populate rows, set value to empty string when label not present.
+    _.each(md, function(series) {
       if (series.values) {
         for (i = 0; i < series.values.length; i++) {
           var values = series.values[i];
-          var reordered = [values[0] * 1000];
+          var reordered: any = [values[0] * 1000];
           if (series.metric) {
-            for (var key in series.metric) {
-              if (series.metric.hasOwnProperty(key)) {
-                reordered.push(series.metric[key]);
+            for (j = 0; j < sortedLabels.length; j++) {
+              var label = sortedLabels[j];
+              if (series.metric.hasOwnProperty(label)) {
+                reordered.push(series.metric[label]);
+              } else {
+                reordered.push('');
               }
             }
           }

+ 16 - 5
public/app/plugins/datasource/prometheus/specs/datasource_specs.ts

@@ -165,19 +165,30 @@ describe('PrometheusDatasource', function() {
       status: "success",
       data: {
         resultType: "matrix",
-        result: [{
-          metric: {"__name__": "test", job: "testjob"},
-          values: [[1443454528, "3846"]]
-        }]
+        result: [
+          {
+            metric: {"__name__": "test", job: "testjob"},
+            values: [[1443454528, "3846"]]
+          },
+          {
+            metric: {"__name__": "test", instance: "localhost:8080", job: "otherjob"},
+            values: [[1443454529, "3847"]]
+          },
+        ]
       }
     };
     it('should return table model', function() {
       var table = ctx.ds.transformMetricDataToTable(response.data.result);
       expect(table.type).to.be('table');
-      expect(table.rows).to.eql([ [ 1443454528000, 'test', 'testjob', 3846 ] ]);
+      expect(table.rows).to.eql(
+        [
+          [ 1443454528000, 'test', '', 'testjob', 3846],
+          [ 1443454529000, 'test', 'localhost:8080', "otherjob", 3847],
+        ]);
       expect(table.columns).to.eql(
         [ { text: 'Time', type: 'time' },
           { text: '__name__' },
+          { text: 'instance' },
           { text: 'job' },
           { text: 'Value' }
         ]