Browse Source

feat(elasticsearch): began work on elasticsearch datasource, based on work in pr #2293, will need a lot more work

Torkel Ödegaard 10 years ago
parent
commit
e48754c73c

+ 0 - 167
public/app/plugins/datasource/elasticsearch/datasource.js

@@ -127,173 +127,6 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
       });
     };
 
-    ElasticDatasource.prototype._getDashboardWithSlug = function(id) {
-      return this._get('/dashboard/' + kbn.slugifyForUrl(id))
-        .then(function(result) {
-          return angular.fromJson(result._source.dashboard);
-        }, function() {
-          throw "Dashboard not found";
-        });
-    };
-
-    ElasticDatasource.prototype.getDashboard = function(id, isTemp) {
-      var url = '/dashboard/' + id;
-      if (isTemp) { url = '/temp/' + id; }
-
-      var self = this;
-      return this._get(url)
-        .then(function(result) {
-          return angular.fromJson(result._source.dashboard);
-        }, function(data) {
-          if(data.status === 0) {
-            throw "Could not contact Elasticsearch. Please ensure that Elasticsearch is reachable from your browser.";
-          } else {
-            // backward compatible fallback
-            return self._getDashboardWithSlug(id);
-          }
-        });
-    };
-
-    ElasticDatasource.prototype.saveDashboard = function(dashboard) {
-      var title = dashboard.title;
-      var temp = dashboard.temp;
-      if (temp) { delete dashboard.temp; }
-
-      var data = {
-        user: 'guest',
-        group: 'guest',
-        title: title,
-        tags: dashboard.tags,
-        dashboard: angular.toJson(dashboard)
-      };
-
-      if (temp) {
-        return this._saveTempDashboard(data);
-      }
-      else {
-
-        var id = encodeURIComponent(kbn.slugifyForUrl(title));
-        var self = this;
-
-        return this._request('PUT', '/dashboard/' + id, this.index, data)
-          .then(function(results) {
-            self._removeUnslugifiedDashboard(results, title, id);
-            return { title: title, url: '/dashboard/db/' + id };
-          }, function() {
-            throw 'Failed to save to elasticsearch';
-          });
-      }
-    };
-
-    ElasticDatasource.prototype._removeUnslugifiedDashboard = function(saveResult, title, id) {
-      if (saveResult.statusText !== 'Created') { return; }
-      if (title === id) { return; }
-
-      var self = this;
-      this._get('/dashboard/' + title).then(function() {
-        self.deleteDashboard(title);
-      });
-    };
-
-    ElasticDatasource.prototype._saveTempDashboard = function(data) {
-      return this._request('POST', '/temp/?ttl=' + this.saveTempTTL, this.index, data)
-        .then(function(result) {
-
-          var baseUrl = window.location.href.replace(window.location.hash,'');
-          var url = baseUrl + "#dashboard/temp/" + result.data._id;
-
-          return { title: data.title, url: url };
-
-        }, function(err) {
-          throw "Failed to save to temp dashboard to elasticsearch " + err.data;
-        });
-    };
-
-    ElasticDatasource.prototype.deleteDashboard = function(id) {
-      return this._request('DELETE', '/dashboard/' + id, this.index)
-        .then(function(result) {
-          return result.data._id;
-        }, function(err) {
-          throw err.data;
-        });
-    };
-
-    ElasticDatasource.prototype.searchDashboards = function(queryString) {
-      var endsInOpen = function(string, opener, closer) {
-        var character;
-        var count = 0;
-        for (var i = 0, len = string.length; i < len; i++) {
-          character = string[i];
-
-          if (character === opener) {
-            count++;
-          } else if (character === closer) {
-            count--;
-          }
-        }
-
-        return count > 0;
-      };
-
-      var tagsOnly = queryString.indexOf('tags!:') === 0;
-      if (tagsOnly) {
-        var tagsQuery = queryString.substring(6, queryString.length);
-        queryString = 'tags:' + tagsQuery + '*';
-      }
-      else {
-        if (queryString.length === 0) {
-          queryString = 'title:';
-        }
-
-        // make this a partial search if we're not in some reserved portion of the language,  comments on conditionals, in order:
-        // 1. ends in reserved character, boosting, boolean operator ( -foo)
-        // 2. typing a reserved word like AND, OR, NOT
-        // 3. open parens (groupiing)
-        // 4. open " (term phrase)
-        // 5. open [ (range)
-        // 6. open { (range)
-        // see http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax
-        if (!queryString.match(/(\*|\]|}|~|\)|"|^\d+|\s[\-+]\w+)$/) &&
-            !queryString.match(/[A-Z]$/) &&
-            !endsInOpen(queryString, '(', ')') &&
-            !endsInOpen(queryString, '"', '"') &&
-            !endsInOpen(queryString, '[', ']') && !endsInOpen(queryString, '[', '}') &&
-            !endsInOpen(queryString, '{', ']') && !endsInOpen(queryString, '{', '}')
-        ){
-          queryString += '*';
-        }
-      }
-
-      var query = {
-        query: { query_string: { query: queryString } },
-        facets: { tags: { terms: { field: "tags", order: "term", size: 50 } } },
-        size: 10000,
-        sort: ["_uid"],
-      };
-
-      return this._post('/dashboard/_search', query)
-        .then(function(results) {
-          if(_.isUndefined(results.hits)) {
-            return { dashboards: [], tags: [] };
-          }
-
-          var resultsHits = results.hits.hits;
-          var displayHits = { dashboards: [], tags: results.facets.tags.terms || [] };
-
-          for (var i = 0, len = resultsHits.length; i < len; i++) {
-            var hit = resultsHits[i];
-            displayHits.dashboards.push({
-              id: hit._id,
-              title: hit._source.title,
-              tags: hit._source.tags
-            });
-          }
-
-          displayHits.tagsOnly = tagsOnly;
-          return displayHits;
-        });
-    };
-
     ElasticDatasource.prototype.testDatasource = function() {
       var query = JSON.stringify();
       return this._post('/_search?search_type=count', query).then(function() {

+ 127 - 149
public/app/plugins/datasource/elasticsearch/partials/query.editor.html

@@ -1,151 +1,129 @@
-<div class="editor-row">
-
-	<div ng-repeat="target in panel.targets" ng-controller="ElasticQueryCtrl" ng-init="init()" ng-class="{'tight-form-disabled': target.hide}" class="tight-form-container-no-item-borders" style="margin-bottom: 10px">
-		<div  class="tight-form">
-			<ul class="tight-form-list pull-right">
-				<li ng-show="parserError" class="tight-form-item">
-					<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
-						<i class="fa fa-warning"></i>
-					</a>
-				</li>
-				<li class="tight-form-item">
-					<a class="pointer" tabindex="1" ng-click="toggleQueryMode()">
-						<i class="fa fa-pencil"></i>
-					</a>
-				</li>
-				<li class="tight-form-item">
-					<div class="dropdown">
-						<a  class="pointer dropdown-toggle"
-							data-toggle="dropdown"
-							tabindex="1">
-							<i class="fa fa-bars"></i>
-						</a>
-						<ul class="dropdown-menu pull-right" role="menu">
-							<li role="menuitem">
-								<a  tabindex="1"
-									ng-click="duplicate()">
-									Duplicate
-								</a>
-							</li>
-							<li role="menuitem">
-								<a  tabindex="1"
-									ng-click="moveMetricQuery($index, $index-1)">
-									Move up
-								</a>
-							</li>
-							<li role="menuitem">
-								<a  tabindex="1"
-									ng-click="moveMetricQuery($index, $index+1)">
-									Move down
-								</a>
-							</li>
-						</ul>
-					</div>
-				</li>
-				<li class="tight-form-item last">
-					<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
-						<i class="fa fa-remove"></i>
-					</a>
-				</li>
-			</ul>
-
-			<ul class="tight-form-list">
-				<li>
-					<a  class="tight-form-item"
-						ng-click="target.hide = !target.hide; get_data();"
-						role="menuitem">
-						<i class="fa fa-eye"></i>
-					</a>
-				</li>
-			</ul>
-
-			<input type="text" class="tight-form-clear-input" style="width: 80%" ng-model="target.query" focus-me="target.rawQuery" spellcheck='false' ng-model-onblur ng-change="get_data()" ng-show="target.rawQuery"/>
-
-			<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
-				<li class="tight-form-item query-keyword" style="width: 75px;">
-					Function
-				</li>
-				<li class="dropdown tight-form-item">
-					<a gf-dropdown="functionMenu" class="dropdown-toggle" data-toggle="dropdown">
-						{{target.function}}<span>(value)</span>
-					</a>
-				</li>
-			</ul>
-
-			<div class="clearfix"></div>
-		</div>
-
-		<div class="tight-form" ng-hide="target.rawQuery">
-			<ul class="tight-form-list">
-				<li class="tight-form-item">
-					<i class="fa fa-eye invisible"></i>
-				</li>
-				<li class="tight-form-item query-keyword" style="width: 75px;">
-					Key Field
-				</li>
-				<li>
-					<metric-segment segment="keyFieldSegment" on-value-changed="keyFieldChanged()"></metric-segment>
-				</li>
-			</ul>
-
-			<div class="clearfix"></div>
-		</div>
-
-		<div class="tight-form" ng-hide="target.rawQuery">
-			<ul class="tight-form-list">
-				<li class="tight-form-item">
-					<i class="fa fa-eye invisible"></i>
-				</li>
-				<li class="tight-form-item query-keyword" style="width: 75px;">
-					Value Field
-				</li>
-				<li>
-					<metric-segment segment="valueFieldSegment" on-value-changed="valueFieldChanged()"></metric-segment>
-				</li>
-			</ul>
-
-			<div class="clearfix"></div>
-		</div>
-
-		<div class="tight-form" ng-hide="target.rawQuery">
-			<ul class="tight-form-list">
-				<li class="tight-form-item">
-					<i class="fa fa-eye invisible"></i>
-				</li>
-
-				<li class="tight-form-item query-keyword" style="width: 75px;">
-					Term
-				</li>
-
-				<li>
-					<metric-segment segment="termKeySegment" on-value-changed="termKeySegmentChanged()"></metric-segment>
-				</li>
-
-				<li>
-					<span class="tight-form-item">:</span>
-				</li>
-
-				<li>
-					<metric-segment segment="termValueSegment" on-value-changed="termValueSegmentChanged()"></metric-segment>
-				</li>
-			</ul>
-			<div class="clearfix"></div>
-		</div>
-
-		<div class="tight-form" ng-hide="target.rawQuery">
-			<ul class="tight-form-list">
-				<li class="tight-form-item">
-					<i class="fa fa-eye invisible"></i>
-				</li>
-				<li class="tight-form-item query-keyword" style="width: 75px;">
-					Group By
-				</li>
-				<li>
-					<metric-segment segment="groupByFieldSegment" on-value-changed="groupByFieldChanged()"></metric-segment>
-				</li>
-			</ul>
-
-			<div class="clearfix"></div>
-		</div>
+<div  class="tight-form">
+	<ul class="tight-form-list pull-right">
+		<li ng-show="parserError" class="tight-form-item">
+			<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
+				<i class="fa fa-warning"></i>
+			</a>
+		</li>
+		<li class="tight-form-item">
+			<div class="dropdown">
+				<a  class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
+					<i class="fa fa-bars"></i>
+				</a>
+				<ul class="dropdown-menu pull-right" role="menu">
+					<li role="menuitem"><a tabindex="1" ng-click="toggleQueryMode()">Switch editor mode</a></li>
+					<li role="menuitem"><a tabindex="1" ng-click="duplicateDataQuery(target)">Duplicate</a></li>
+					<li role="menuitem"><a tabindex="1" ng-click="moveDataQuery($index, $index-1)">Move up</a></li>
+					<li role="menuitem"><a tabindex="1" ng-click="moveDataQuery($index, $index+1)">Move down</a></li>
+				</ul>
+			</div>
+		</li>
+
+		<li class="tight-form-item last">
+			<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
+				<i class="fa fa-remove"></i>
+			</a>
+		</li>
+	</ul>
+
+	<ul class="tight-form-list">
+		<li class="tight-form-item" style="min-width: 15px; text-align: center">
+			{{target.refId}}
+		</li>
+		<li>
+			<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem">
+				<i class="fa fa-eye"></i>
+			</a>
+		</li>
+	</ul>
+
+	<input type="text" class="tight-form-clear-input" style="width: 80%" ng-model="target.query" focus-me="target.rawQuery" spellcheck='false' ng-model-onblur ng-change="get_data()" ng-show="target.rawQuery"/>
+
+	<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
+		<li class="tight-form-item query-keyword" style="width: 75px;">
+			Function
+		</li>
+		<li class="dropdown tight-form-item">
+			<a gf-dropdown="functionMenu" class="dropdown-toggle" data-toggle="dropdown">
+				{{target.function}}<span>(value)</span>
+			</a>
+		</li>
+	</ul>
+
+	<div class="clearfix"></div>
+</div>
+
+<div class="tight-form" ng-hide="target.rawQuery">
+	<ul class="tight-form-list">
+		<li class="tight-form-item">
+			<i class="fa fa-eye invisible"></i>
+		</li>
+		<li class="tight-form-item query-keyword" style="width: 75px;">
+			Key Field
+		</li>
+		<li>
+			<metric-segment segment="keyFieldSegment" on-value-changed="keyFieldChanged()"></metric-segment>
+		</li>
+	</ul>
+
+	<div class="clearfix"></div>
+</div>
+
+<div class="tight-form" ng-hide="target.rawQuery">
+	<ul class="tight-form-list">
+		<li class="tight-form-item">
+			<i class="fa fa-eye invisible"></i>
+		</li>
+		<li class="tight-form-item query-keyword" style="width: 75px;">
+			Value Field
+		</li>
+		<li>
+			<metric-segment segment="valueFieldSegment" on-value-changed="valueFieldChanged()"></metric-segment>
+		</li>
+	</ul>
+
+	<div class="clearfix"></div>
+</div>
+
+<div class="tight-form" ng-hide="target.rawQuery">
+	<ul class="tight-form-list">
+		<li class="tight-form-item">
+			<i class="fa fa-eye invisible"></i>
+		</li>
+
+		<li class="tight-form-item query-keyword" style="width: 75px;">
+			Term
+		</li>
+
+		<li>
+			<metric-segment segment="termKeySegment" on-value-changed="termKeySegmentChanged()"></metric-segment>
+		</li>
+
+		<li>
+			<span class="tight-form-item">:</span>
+		</li>
+
+		<li>
+			<metric-segment segment="termValueSegment" on-value-changed="termValueSegmentChanged()"></metric-segment>
+		</li>
+	</ul>
+	<div class="clearfix"></div>
+</div>
+
+<div class="tight-form" ng-hide="target.rawQuery">
+	<ul class="tight-form-list">
+		<li class="tight-form-item">
+			<i class="fa fa-eye invisible"></i>
+		</li>
+		<li class="tight-form-item query-keyword" style="width: 75px;">
+			Group By
+		</li>
+		<li>
+			<metric-segment segment="groupByFieldSegment" on-value-changed="groupByFieldChanged()"></metric-segment>
+		</li>
+	</ul>
+
+	<div class="clearfix"></div>
+</div>
 	</div>
 </div>

+ 2 - 1
public/app/plugins/datasource/elasticsearch/plugin.json

@@ -12,5 +12,6 @@
     "annotations": "app/plugins/datasource/elasticsearch/partials/annotations.editor.html"
   },
 
-  "annotations": true
+  "annotations": true,
+  "metrics": true
 }

+ 1 - 172
public/app/plugins/datasource/elasticsearch/queryCtrl.js

@@ -19,8 +19,6 @@ function (angular, _, ElasticQueryBuilder) {
     $scope.init = function() {
       var target = $scope.target;
       target.function = target.function || 'mean';
-      target.tags = target.tags || [];
-      target.groupByTags = target.groupByTags || [];
 
       $scope.queryBuilder = new ElasticQueryBuilder(target);
 
@@ -145,23 +143,6 @@ function (angular, _, ElasticQueryBuilder) {
       $scope.target.rawQuery = !$scope.target.rawQuery;
     };
 
-    $scope.moveMetricQuery = function(fromIndex, toIndex) {
-      _.move($scope.panel.targets, fromIndex, toIndex);
-    };
-
-    $scope.duplicate = function() {
-      var clone = angular.copy($scope.target);
-      $scope.panel.targets.push(clone);
-    };
-
-    $scope.getMeasurements = function () {
-      var query = $scope.queryBuilder.buildExploreQuery('MEASUREMENTS');
-      return $scope.datasource.metricFindQuery(query)
-      .then($scope.transformToSegments)
-      .then($scope.addTemplateVariableSegments)
-      .then(null, $scope.handleQueryError);
-    };
-
     $scope.handleQueryError = function(err) {
       $scope.parserError = err.message || 'Failed to issue metric query';
       return [];
@@ -180,159 +161,7 @@ function (angular, _, ElasticQueryBuilder) {
       return segments;
     };
 
-    $scope.getTagsOrValues = function(segment, index) {
-      var query;
-
-      if (segment.type === 'key' || segment.type === 'plus-button') {
-        query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
-      } else if (segment.type === 'value')  {
-        query = $scope.queryBuilder.buildExploreQuery('TAG_VALUES', $scope.tagSegments[index-2].value);
-      } else if (segment.type === 'condition') {
-        return $q.when([new MetricSegment('AND'), new MetricSegment('OR')]);
-      }
-      else  {
-        return $q.when([]);
-      }
-
-      return $scope.datasource.metricFindQuery(query)
-      .then($scope.transformToSegments)
-      .then($scope.addTemplateVariableSegments)
-      .then(function(results) {
-        if (segment.type === 'key') {
-          results.splice(0, 0, angular.copy($scope.removeTagFilterSegment));
-        }
-        return results;
-      })
-      .then(null, $scope.handleQueryError);
-    };
-
-    $scope.getGroupByTagSegments = function(segment) {
-      var query = $scope.queryBuilder.buildExploreQuery('TAG_KEYS');
-
-      return $scope.datasource.metricFindQuery(query)
-      .then($scope.transformToSegments)
-      .then($scope.addTemplateVariableSegments)
-      .then(function(results) {
-        if (segment.type !== 'plus-button') {
-          results.splice(0, 0, angular.copy($scope.removeGroupBySegment));
-        }
-        return results;
-      })
-      .then(null, $scope.handleQueryError);
-    };
-
-    $scope.tagSegmentUpdated = function(segment, index) {
-      $scope.tagSegments[index] = segment;
-
-      // handle remove tag condition
-      if (segment.value === $scope.removeTagFilterSegment.value) {
-        $scope.tagSegments.splice(index, 3);
-        if ($scope.tagSegments.length === 0) {
-          $scope.tagSegments.push(MetricSegment.newPlusButton());
-        } else if ($scope.tagSegments.length > 2) {
-          $scope.tagSegments.splice(Math.max(index-1, 0), 1);
-          if ($scope.tagSegments[$scope.tagSegments.length-1].type !== 'plus-button') {
-            $scope.tagSegments.push(MetricSegment.newPlusButton());
-          }
-        }
-      }
-      else {
-        if (segment.type === 'plus-button') {
-          if (index > 2) {
-            $scope.tagSegments.splice(index, 0, MetricSegment.newCondition('AND'));
-          }
-          $scope.tagSegments.push(MetricSegment.newOperator('='));
-          $scope.tagSegments.push(MetricSegment.newFake('select tag value', 'value', 'query-segment-value'));
-          segment.type = 'key';
-          segment.cssClass = 'query-segment-key';
-        }
-
-        if ((index+1) === $scope.tagSegments.length) {
-          $scope.tagSegments.push(MetricSegment.newPlusButton());
-        }
-      }
-
-      $scope.rebuildTargetTagConditions();
-    };
-
-    $scope.rebuildTargetTagConditions = function() {
-      var tags = [];
-      var tagIndex = 0;
-      _.each($scope.tagSegments, function(segment2, index) {
-        if (segment2.type === 'key') {
-          if (tags.length === 0) {
-            tags.push({});
-          }
-          tags[tagIndex].key = segment2.value;
-        }
-        else if (segment2.type === 'value') {
-          tags[tagIndex].value = segment2.value;
-          $scope.tagSegments[index-1] = $scope.getTagValueOperator(segment2.value);
-        }
-        else if (segment2.type === 'condition') {
-          tags.push({ condition: segment2.value });
-          tagIndex += 1;
-        }
-      });
-
-      $scope.target.tags = tags;
-      $scope.$parent.get_data();
-    };
-
-    $scope.getTagValueOperator = function(tagValue) {
-      if (tagValue[0] === '/' && tagValue[tagValue.length - 1] === '/') {
-        return MetricSegment.newOperator('=~');
-      }
-
-      return MetricSegment.newOperator('=');
-    };
-
-    function MetricSegment(options) {
-      if (options === '*' || options.value === '*') {
-        this.value = '*';
-        this.html = $sce.trustAsHtml('<i class="fa fa-asterisk"><i>');
-        this.expandable = true;
-        return;
-      }
-
-      if (_.isString(options)) {
-        this.value = options;
-        this.html = $sce.trustAsHtml(this.value);
-        return;
-      }
-
-      this.cssClass = options.cssClass;
-      this.type = options.type;
-      this.fake = options.fake;
-      this.value = options.value;
-      this.type = options.type;
-      this.expandable = options.expandable;
-      this.html = options.html || $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
-    }
-
-    MetricSegment.newSelectMeasurement = function() {
-      return new MetricSegment({value: 'select measurement', fake: true});
-    };
-
-    MetricSegment.newFake = function(text, type, cssClass) {
-      return new MetricSegment({value: text, fake: true, type: type, cssClass: cssClass});
-    };
-
-    MetricSegment.newCondition = function(condition) {
-      return new MetricSegment({value: condition, type: 'condition', cssClass: 'query-keyword' });
-    };
-
-    MetricSegment.newOperator = function(op) {
-      return new MetricSegment({value: op, type: 'operator', cssClass: 'query-segment-operator' });
-    };
-
-    MetricSegment.newPlusButton = function() {
-      return new MetricSegment({fake: true, html: '<i class="fa fa-plus "></i>', type: 'plus-button' });
-    };
-
-    MetricSegment.newSelectTagValue = function() {
-      return new MetricSegment({value: 'select tag value', fake: true});
-    };
+    $scope.init();
 
   });