Просмотр исходного кода

feat(prometheus): restore old prometheus query editor, revert this commit in prometheus query editor v2 branch

Torkel Ödegaard 9 лет назад
Родитель
Сommit
b8aa8b3079

+ 8 - 17
public/app/plugins/datasource/prometheus/datasource.ts

@@ -256,23 +256,14 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
     return this.renderTemplate(options.legendFormat, labelData) || '{}';
   };
 
-  this.renderTemplate = function(format, data) {
-    var originalSettings = _.templateSettings;
-    _.templateSettings = {
-      interpolate: /\{\{(.+?)\}\}/g
-    };
-
-    var template = _.template(templateSrv.replace(format));
-    var result;
-    try {
-      result = template(data);
-    } catch (e) {
-      result = null;
-    }
-
-    _.templateSettings = originalSettings;
-
-    return result;
+  this.renderTemplate = function(aliasPattern, aliasData) {
+    var aliasRegex = /\{\{\s*(.+?)\s*\}\}/g;
+    return aliasPattern.replace(aliasRegex, function(match, g1) {
+      if (aliasData[g1]) {
+        return aliasData[g1];
+      }
+      return g1;
+    });
   };
 
   this.getOriginalMetricName = function(labelData) {

+ 50 - 82
public/app/plugins/datasource/prometheus/metric_find_query.js

@@ -11,33 +11,27 @@ function (_) {
   }
 
   PrometheusMetricFindQuery.prototype.process = function() {
-    var labelValuesRegex  = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]+)\)$/;
-    var metricNamesRegex = /^metrics\((.+)\)$/;
-    var labelsRegex = /^labels\((.+)\)$/;
-    var queryResultRegex = /^query_result\((.+)\)$/;
-
-    var labelsQuery = this.query.match(labelsRegex);
-    if (labelsQuery) {
-      return this.labelsQuery(labelsQuery[1]);
-    }
-
-    var labelValuesQuery = this.query.match(labelValuesRegex);
-    if (labelValuesQuery) {
-      if (labelValuesQuery[1]) {
-        return this.labelValuesQuery(labelValuesQuery[2], labelValuesQuery[1]);
+    var label_values_regex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]+)\)$/;
+    var metric_names_regex = /^metrics\((.+)\)$/;
+    var query_result_regex = /^query_result\((.+)\)$/;
+
+    var label_values_query = this.query.match(label_values_regex);
+    if (label_values_query) {
+      if (label_values_query[1]) {
+        return this.labelValuesQuery(label_values_query[2], label_values_query[1]);
       } else {
-        return this.labelValuesQuery(labelValuesQuery[2], null);
+        return this.labelValuesQuery(label_values_query[2], null);
       }
     }
 
-    var metricNamesQuery = this.query.match(metricNamesRegex);
-    if (metricNamesQuery) {
-      return this.metricNameQuery(metricNamesQuery[1]);
+    var metric_names_query = this.query.match(metric_names_regex);
+    if (metric_names_query) {
+      return this.metricNameQuery(metric_names_query[1]);
     }
 
-    var queryResultQuery = this.query.match(queryResultRegex);
-    if (queryResultQuery) {
-      return this.queryResultQuery(queryResultQuery[1]);
+    var query_result_query = this.query.match(query_result_regex);
+    if (query_result_query) {
+      return this.queryResultQuery(query_result_query[1]);
     }
 
     // if query contains full metric name, return metric name and label list
@@ -73,71 +67,45 @@ function (_) {
     }
   };
 
-  PrometheusMetricFindQuery.prototype.labelsQuery = function(metric) {
-    var url;
-
-    url = '/api/v1/series?match[]=' + encodeURIComponent(metric)
-      + '&start=' + (this.range.from.valueOf() / 1000)
-      + '&end=' + (this.range.to.valueOf() / 1000);
-
-    return this.datasource._request('GET', url)
-      .then(function(result) {
-        var tags = {};
-        _.each(result.data.data, function(metric) {
-          _.each(metric, function(value, key) {
-            if (key === "__name__") {
-              return;
-            }
-
-            tags[key] = key;
-          });
-        });
-
-        return _.map(tags, function(value) {
-          return {text: value, value: value};
-        });
-      });
-  };
-
   PrometheusMetricFindQuery.prototype.metricNameQuery = function(metricFilterPattern) {
     var url = '/api/v1/label/__name__/values';
 
     return this.datasource._request('GET', url)
-      .then(function(result) {
-        return _.chain(result.data.data)
-          .filter(function(metricName) {
-            var r = new RegExp(metricFilterPattern);
-            return r.test(metricName);
-          })
-        .map(function(matchedMetricName) {
-          return {
-            text: matchedMetricName,
-            expandable: true
-          };
-        })
-        .value();
-      });
+    .then(function(result) {
+      return _.chain(result.data.data)
+      .filter(function(metricName) {
+        var r = new RegExp(metricFilterPattern);
+        return r.test(metricName);
+      })
+      .map(function(matchedMetricName) {
+        return {
+          text: matchedMetricName,
+          expandable: true
+        };
+      })
+      .value();
+    });
   };
 
   PrometheusMetricFindQuery.prototype.queryResultQuery = function(query) {
     var url = '/api/v1/query?query=' + encodeURIComponent(query) + '&time=' + (this.range.to.valueOf() / 1000);
 
     return this.datasource._request('GET', url)
-      .then(function(result) {
-        return _.map(result.data.data.result, function(metricData) {
-          var text = metricData.metric.__name__ || '';
-          delete metricData.metric.__name__;
-          text += '{' +
-            _.map(metricData.metric, function(v, k) { return k + '="' + v + '"'; }).join(',') +
-            '}';
-          text += ' ' + metricData.value[1] + ' ' + metricData.value[0] * 1000;
-
-          return {
-            text: text,
-            expandable: true
-          };
-        });
+    .then(function(result) {
+      return _.map(result.data.data.result, function(metricData) {
+        var text = metricData.metric.__name__ || '';
+        delete metricData.metric.__name__;
+        text += '{' +
+                _.map(metricData.metric, function(v, k) { return k + '="' + v + '"'; }).join(',') +
+                '}';
+        text += ' ' + metricData.value[1] + ' ' + metricData.value[0] * 1000;
+
+        return {
+          text: text,
+          expandable: true
+        };
       });
+    });
   };
 
   PrometheusMetricFindQuery.prototype.metricNameAndLabelsQuery = function(query) {
@@ -147,14 +115,14 @@ function (_) {
 
     var self = this;
     return this.datasource._request('GET', url)
-      .then(function(result) {
-        return _.map(result.data.data, function(metric) {
-          return {
-            text: self.datasource.getOriginalMetricName(metric),
-            expandable: true
-          };
-        });
+    .then(function(result) {
+      return _.map(result.data.data, function(metric) {
+        return {
+          text: self.datasource.getOriginalMetricName(metric),
+          expandable: true
+        };
       });
+    });
   };
 
   return PrometheusMetricFindQuery;

+ 9 - 30
public/app/plugins/datasource/prometheus/partials/query.editor.html

@@ -1,39 +1,18 @@
-<query-editor-row query-ctrl="ctrl" can-collapse="false" has-text-edit-mode="true">
-
-  <div class="gf-form" ng-if="!ctrl.target.editorMode">
-    <input type="text" class="gf-form-input" ng-model="ctrl.target.expr" spellcheck="false" ng-blur="ctrl.refresh()"></input>
-	</div>
-
-	<div class="gf-form-inline" ng-if="ctrl.target.editorMode">
-		<div class="gf-form">
-			<label class="gf-form-label width-8 query-keyword">Query</label>
-			<metric-segment segment="ctrl.metricSegment" get-options="ctrl.getMetricOptions()" on-change="ctrl.queryChanged()"></metric-segment>
-		</div>
-
-		<div class="gf-form" ng-repeat="part in ctrl.query.functions">
-				<query-part-editor class="gf-form-label query-part"
-													part="part"
-													remove-action="ctrl.removePart(query.functions, part)"
-													part-updated="ctrl.partUpdated(query.functions, part)"
-													get-options="ctrl.getPartOptions(part)">
-				</query-part-editor>
-		</div>
-
-		<div class="gf-form">
-			<label class="dropdown"
-							dropdown-typeahead="ctrl.addQueryPartMenu"
-							dropdown-typeahead-on-select="ctrl.addQueryPart($item, $subItem)">
-			</label>
-		</div>
-
+<query-editor-row query-ctrl="ctrl" can-collapse="false">
+	<div class="gf-form-inline">
 		<div class="gf-form gf-form--grow">
-			<div class="gf-form-label gf-form-label--grow"></div>
+			<label class="gf-form-label width-8">Query</label>
+			<input type="text" class="gf-form-input" ng-model="ctrl.target.expr" spellcheck='false' placeholder="query expression" data-min-length=0 data-items=100 ng-model-onblur ng-change="ctrl.refreshMetricData()">
+		</div>
+		<div class="gf-form max-width-22">
+			<label class="gf-form-label">Metric lookup</label>
+			<input type="text" class="gf-form-input" ng-model="ctrl.target.metric" spellcheck='false' bs-typeahead="ctrl.suggestMetrics" placeholder="metric name" data-min-length=0 data-items=100>
 		</div>
 	</div>
 
 	<div class="gf-form-inline">
 		<div class="gf-form max-width-26">
-			<label class="gf-form-label width-8 query-keyword">Legend format</label>
+			<label class="gf-form-label width-8">Legend format</label>
 			<input type="text" class="gf-form-input" ng-model="ctrl.target.legendFormat"
 			spellcheck='false' placeholder="legend format" data-min-length=0 data-items=1000
 			ng-model-onblur ng-change="ctrl.refreshMetricData()">

+ 0 - 119
public/app/plugins/datasource/prometheus/prom_query.ts

@@ -1,119 +0,0 @@
-import {
-  QueryPartDef,
-  QueryPart,
-  functionRenderer,
-  identityRenderer,
-  quotedIdentityRenderer,
-} from 'app/core/components/query_part/query_part';
-
-import _ from 'lodash';
-
-var index = [];
-var categories = {
-  Functions: [],
-  GroupBy: [],
-};
-
-export class PromQuery {
-  target: any;
-  metric: string;
-  range: string;
-  filters: any[];
-  functions: any[];
-  templateSrv: any;
-  scopedVars: any;
-
-  constructor(target, templateSrv?, scopedVars?) {
-    this.target = target;
-
-    this.target.expr = this.target.expr || '';
-    this.target.intervalFactor = this.target.intervalFactor || 2;
-    this.target.functions = this.target.functions || [];
-    this.target.editorMode = this.target.editorMode || true;
-
-    this.templateSrv = templateSrv;
-    this.scopedVars = scopedVars;
-
-    this.updateProjection();
-  }
-
-  updateProjection() {
-    this.functions = _.map(this.target.functions, function(func: any) {
-      return createPart(func);
-    });
-  }
-
-  render() {
-    var query = this.target.metric;
-    if (this.target.range) {
-      query += '[' + this.target.range + ']';
-    }
-
-    for (let func of this.functions) {
-      query = func.render(query);
-    }
-
-    return query;
-  }
-
-  addQueryPart(category, item) {
-    var partModel = createPart({type: item.text});
-    partModel.def.addStrategy(this, partModel);
-  }
-}
-
-export function createPart(part): any {
-  var def = index[part.type];
-  if (!def) {
-    throw {message: 'Could not find query part ' + part.type};
-  }
-
-  return new QueryPart(part, def);
-}
-
-function register(options: any) {
-  index[options.type] = new QueryPartDef(options);
-  options.category.push(index[options.type]);
-}
-
-function addFunctionStrategy(model, partModel) {
-  model.functions.push(partModel);
-  model.target.functions.push(partModel.part);
-}
-
-function groupByLabelRenderer(part, innerExpr) {
-  return innerExpr + ' by(' + part.params.join(',')  + ')';
-}
-
-register({
-  type: 'rate',
-  addStrategy: addFunctionStrategy,
-  category: categories.Functions,
-  params: [],
-  defaultParams: [],
-  renderer: functionRenderer,
-});
-
-register({
-  type: 'sum',
-  addStrategy: addFunctionStrategy,
-  category: categories.Functions,
-  params: [],
-  defaultParams: [],
-  renderer: functionRenderer,
-});
-
-register({
-  type: 'by',
-  addStrategy: addFunctionStrategy,
-  category: categories.Functions,
-  params: [
-    {name: "label", type: "string", dynamicLookup: true}
-  ],
-  defaultParams: [],
-  renderer: groupByLabelRenderer,
-});
-
-export function getQueryPartCategories() {
-  return categories;
-}

+ 22 - 80
public/app/plugins/datasource/prometheus/query_ctrl.ts

@@ -6,108 +6,46 @@ import moment from 'moment';
 
 import * as dateMath from 'app/core/utils/datemath';
 import {QueryCtrl} from 'app/plugins/sdk';
-import {PromQuery, getQueryPartCategories} from './prom_query';
 
 class PrometheusQueryCtrl extends QueryCtrl {
   static templateUrl = 'partials/query.editor.html';
 
-  query: any;
-  metricSegment: any;
-  addQueryPartMenu: any[];
+  metric: any;
   resolutions: any;
   oldTarget: any;
   suggestMetrics: any;
   linkToPrometheus: any;
 
   /** @ngInject */
-  constructor($scope, $injector, private templateSrv, private uiSegmentSrv, private $rootScope) {
+  constructor($scope, $injector, private templateSrv) {
     super($scope, $injector);
 
-    this.query = new PromQuery(this.target, templateSrv);
-
-    if (this.target.metric) {
-      this.metricSegment = uiSegmentSrv.newSegment(this.target.metric);
-    } else {
-      this.metricSegment = uiSegmentSrv.newSegment({value: 'select metric', fake: true});
-    }
+    var target = this.target;
+    target.expr = target.expr || '';
+    target.intervalFactor = target.intervalFactor || 2;
 
+    this.metric = '';
     this.resolutions = _.map([1,2,3,4,5,10], function(f) {
       return {factor: f, label: '1/' + f};
     });
 
-    this.updateLink();
-    this.buildQueryPartMenu();
-  }
-
-  buildQueryPartMenu() {
-    var categories = getQueryPartCategories();
-    this.addQueryPartMenu = _.reduce(categories, function(memo, cat, key) {
-      var menu = {
-        text: key,
-        submenu: cat.map(item => {
-         return {text: item.type, value: item.type};
-        }),
-      };
-      memo.push(menu);
-      return memo;
-    }, []);
-  }
-
-  addQueryPart(item, subItem) {
-    this.query.addQueryPart(item, subItem);
-    this.panelCtrl.refresh();
-  }
-
-  getPartOptions(part) {
-    if (part.def.type === 'by') {
-      return this.datasource.metricFindQuery('labels(' + this.target.metric + ')')
-      .then(this.transformToSegments(true))
-      .catch(this.handleQueryError.bind(true));
-    }
-  }
+    $scope.$on('typeahead-updated', () => {
+      this.$scope.$apply(() => {
 
-  partUpdated(part) {
-    this.target.expr = this.query.render();
-    this.panelCtrl.refresh();
-  }
-
-  handleQueryError(err) {
-    this.$rootScope.appEvent('alert-error', ['Query failed', err.message]);
-  }
-
-  transformToSegments(addTemplateVars) {
-    return (results) => {
-      var segments = _.map(results, segment => {
-        return this.uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable });
-      });
-
-      if (addTemplateVars) {
-        for (let variable of this.templateSrv.variables) {
-          segments.unshift(this.uiSegmentSrv.newSegment({ type: 'template', value: '/^$' + variable.name + '$/', expandable: true }));
-        }
-      }
-
-      return segments;
-    };
-  }
-
-  getMetricOptions() {
-    return this.datasource.performSuggestQuery('').then(res => {
-      return _.map(res, metric => {
-        return this.uiSegmentSrv.newSegment(metric);
+        this.target.expr += this.target.metric;
+        this.metric = '';
+        this.refreshMetricData();
       });
     });
-  }
 
-  queryChanged() {
-    this.target.metric = this.metricSegment.value;
-    this.target.expr = this.query.render();
-    this.refresh();
-  }
+    // called from typeahead so need this
+    // here in order to ensure this ref
+    this.suggestMetrics = (query, callback) => {
+      console.log(this);
+      this.datasource.performSuggestQuery(query).then(callback);
+    };
 
-  toggleEditorMode() {
-    this.target.expr = this.query.render(false);
-    this.target.editorMode = !this.target.editorMode;
+    this.updateLink();
   }
 
   refreshMetricData() {
@@ -120,6 +58,10 @@ class PrometheusQueryCtrl extends QueryCtrl {
 
   updateLink() {
     var range = this.panelCtrl.range;
+    if (!range) {
+      return;
+    }
+
     var rangeDiff = Math.ceil((range.to.valueOf() - range.from.valueOf()) / 1000);
     var endTime = range.to.utc().format('YYYY-MM-DD HH:mm');
     var expr = {

+ 0 - 37
public/app/plugins/datasource/prometheus/specs/metric_find_query_specs.ts

@@ -22,22 +22,18 @@ describe('PrometheusMetricFindQuery', function() {
   describe('When performing metricFindQuery', function() {
     var results;
     var response;
-
     it('label_values(resource) should generate label search query', function() {
       response = {
         status: "success",
         data: ["value1", "value2", "value3"]
       };
-
       ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/resource/values').respond(response);
       var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(resource)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
-
       expect(results.length).to.be(3);
     });
-
     it('label_values(metric, resource) should generate series query', function() {
       response = {
         status: "success",
@@ -47,16 +43,13 @@ describe('PrometheusMetricFindQuery', function() {
           {__name__: "metric", resource: "value3"}
         ]
       };
-
       ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
       var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
-
       expect(results.length).to.be(3);
     });
-
     it('label_values(metric, resource) should pass correct time', function() {
       ctx.timeSrv.setTime({ from: moment.utc('2011-01-01'), to: moment.utc('2015-01-01') });
       ctx.$httpBackend.expect('GET',
@@ -66,7 +59,6 @@ describe('PrometheusMetricFindQuery', function() {
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
     });
-
     it('label_values(metric{label1="foo", label2="bar", label3="baz"}, resource) should generate series query', function() {
       response = {
         status: "success",
@@ -76,7 +68,6 @@ describe('PrometheusMetricFindQuery', function() {
           {__name__: "metric", resource: "value3"}
         ]
       };
-
       ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
       var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
@@ -84,22 +75,18 @@ describe('PrometheusMetricFindQuery', function() {
       ctx.$rootScope.$apply();
       expect(results.length).to.be(3);
     });
-
     it('metrics(metric.*) should generate metric name query', function() {
       response = {
         status: "success",
         data: ["metric1","metric2","metric3","nomatch"]
       };
-
       ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/__name__/values').respond(response);
       var pm = new PrometheusMetricFindQuery(ctx.ds, 'metrics(metric.*)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
-
       expect(results.length).to.be(3);
     });
-
     it('query_result(metric) should generate metric name query', function() {
       response = {
         status: "success",
@@ -111,7 +98,6 @@ describe('PrometheusMetricFindQuery', function() {
           }]
         }
       };
-
       ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/query\?query=metric&time=.*/).respond(response);
       var pm = new PrometheusMetricFindQuery(ctx.ds, 'query_result(metric)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
@@ -120,28 +106,5 @@ describe('PrometheusMetricFindQuery', function() {
       expect(results.length).to.be(1);
       expect(results[0].text).to.be('metric{job="testjob"} 3846 1443454528000');
     });
-
-    it('labels(metric) should generate series query', function() {
-      response = {
-        status: "success",
-        data: [
-          {__name__: "metric", resource: "value1", app: "app1"},
-          {__name__: "metric", resource: "value2", app: "app2"},
-          {__name__: "metric", resource: "value3", server: "server1"}
-        ]
-      };
-
-      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'labels(metric)', ctx.timeSrv);
-      pm.process().then(function(data) { results = data; });
-      ctx.$httpBackend.flush();
-      ctx.$rootScope.$apply();
-
-      expect(results.length).to.be(3);
-      expect(results[0].text).to.be('resource');
-      expect(results[1].text).to.be('app');
-      expect(results[2].text).to.be('server');
-    });
-
   });
 });

+ 0 - 38
public/app/plugins/datasource/prometheus/specs/query_specs.ts

@@ -1,38 +0,0 @@
-import {describe, beforeEach, it, sinon, expect} from 'test/lib/common';
-
-import {PromQuery} from '../prom_query';
-
-describe('PromQuery', function() {
-  var templateSrv = {replace: val => val};
-
-  describe('render series with mesurement only', function() {
-    it('should generate correct query', function() {
-      var query = new PromQuery({
-        metric: 'cpu',
-        range: '5m',
-        functions: [
-          {type: 'rate', params: []}
-        ]
-      }, templateSrv, {});
-
-      var queryText = query.render();
-      expect(queryText).to.be('rate(cpu[5m])');
-    });
-  });
-
-  describe('render series with group by label', function() {
-    it('should generate correct query', function() {
-      var query = new PromQuery({
-        metric: 'cpu',
-        functions: [
-          {type: 'sum', params: []},
-          {type: 'by', params: ['app']},
-        ]
-      }, templateSrv, {});
-
-      var queryText = query.render();
-      expect(queryText).to.be('sum(cpu) by(app)');
-    });
-  });
-
-});