Kaynağa Gözat

feat(elasticsearch): more polish to editor, made interval configurable per query, #1034

Torkel Ödegaard 10 yıl önce
ebeveyn
işleme
f361f324da

+ 34 - 17
public/app/plugins/datasource/elasticsearch/bucketAgg.js

@@ -15,6 +15,7 @@ function (angular, _, queryDef) {
     $scope.bucketAggTypes = queryDef.bucketAggTypes;
     $scope.bucketAggTypes = queryDef.bucketAggTypes;
     $scope.orderOptions = queryDef.orderOptions;
     $scope.orderOptions = queryDef.orderOptions;
     $scope.sizeOptions = queryDef.sizeOptions;
     $scope.sizeOptions = queryDef.sizeOptions;
+    $scope.intervalOptions = queryDef.intervalOptions;
 
 
     $rootScope.onAppEvent('elastic-query-updated', function() {
     $rootScope.onAppEvent('elastic-query-updated', function() {
       $scope.validateModel();
       $scope.validateModel();
@@ -27,36 +28,52 @@ function (angular, _, queryDef) {
     };
     };
 
 
     $scope.onChangeInternal = function() {
     $scope.onChangeInternal = function() {
-      if ($scope.validateModel()) {
-        $scope.onChange();
-      }
+      $scope.onChange();
+    };
+
+    $scope.onTypeChanged = function() {
+      $scope.agg.settings = {};
+      $scope.showOptions = false;
+
+      $scope.validateModel();
+      $scope.onChange();
     };
     };
 
 
     $scope.validateModel = function() {
     $scope.validateModel = function() {
       $scope.index = _.indexOf(bucketAggs, $scope.agg);
       $scope.index = _.indexOf(bucketAggs, $scope.agg);
-
       $scope.isFirst = $scope.index === 0;
       $scope.isFirst = $scope.index === 0;
       $scope.isLast = $scope.index === bucketAggs.length - 1;
       $scope.isLast = $scope.index === bucketAggs.length - 1;
-      $scope.settingsLinkText = "";
 
 
-      if ($scope.agg.type === "terms") {
-        $scope.agg.order = $scope.agg.order || "asc";
-        $scope.agg.size = $scope.agg.size || "0";
-        $scope.agg.orderBy = $scope.agg.orderBy || "_term";
+      var settingsLinkText = "";
+      var settings = $scope.agg.settings || {};
 
 
-        if ($scope.agg.size !== '0') {
-          $scope.settingsLinkText = queryDef.describeOrder($scope.agg.order) + ' ' + $scope.agg.size + ', ';
-        }
+      switch($scope.agg.type) {
+        case 'terms': {
+          settings.order = settings.order || "asc";
+          settings.size = settings.size || "0";
+          settings.orderBy = settings.orderBy || "_term";
 
 
-        $scope.settingsLinkText += 'Order by: ' + queryDef.describeOrderBy($scope.agg.orderBy, $scope.target);
+          if (settings.size !== '0') {
+            settingsLinkText = queryDef.describeOrder(settings.order) + ' ' + settings.size + ', ';
+          }
 
 
-        if ($scope.agg.size === '0') {
-          $scope.settingsLinkText += ' (' + $scope.agg.order + ')';
+          settingsLinkText += 'Order by: ' + queryDef.describeOrderBy(settings.orderBy, $scope.target);
+
+          if (settings.size === '0') {
+            settingsLinkText += ' (' + settings.order + ')';
+          }
+
+          break;
+        }
+        case 'date_histogram': {
+          settings.interval = settings.interval || 'auto';
+          $scope.agg.field = $scope.target.timeField;
+          settingsLinkText = 'Interval: ' + settings.interval;
         }
         }
-      } else if ($scope.agg.type === 'date_histogram') {
-        $scope.agg.field = $scope.target.timeField;
       }
       }
 
 
+      $scope.settingsLinkText = settingsLinkText;
+      $scope.agg.settings = settings;
       return true;
       return true;
     };
     };
 
 

+ 18 - 5
public/app/plugins/datasource/elasticsearch/partials/bucketAgg.html

@@ -5,10 +5,10 @@
 			<span ng-hide="isFirst">Then by</span>
 			<span ng-hide="isFirst">Then by</span>
 		</li>
 		</li>
 		<li>
 		<li>
-			<metric-segment-model property="agg.type" options="bucketAggTypes" on-change="onChangeInternal()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
+			<metric-segment-model property="agg.type" options="bucketAggTypes" on-change="onTypeChanged()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
 		</li>
 		</li>
 		<li>
 		<li>
-			<metric-segment-model property="agg.field" get-options="getFields()" on-change="onChangeInternal()" css-class="tight-form-item-xxlarge"></metric-segment>
+			<metric-segment-model property="agg.field" get-options="getFields()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment>
 		</li>
 		</li>
 		<li class="tight-form-item last" ng-if="settingsLinkText">
 		<li class="tight-form-item last" ng-if="settingsLinkText">
 			<a ng-click="toggleOptions()">{{settingsLinkText}}</a>
 			<a ng-click="toggleOptions()">{{settingsLinkText}}</a>
@@ -27,6 +27,19 @@
 </div>
 </div>
 
 
 <div class="tight-form" ng-if="showOptions">
 <div class="tight-form" ng-if="showOptions">
+	<div class="tight-form-inner-box" ng-if="agg.type === 'date_histogram'">
+		<div class="tight-form last">
+			<ul class="tight-form-list">
+				<li class="tight-form-item" style="width: 60px">
+					Interval
+				</li>
+				<li>
+					<metric-segment-model property="agg.settings.interval" options="intervalOptions" on-change="onChangeInternal()" css-class="last" custom="true"></metric-segment-model>
+				</li>
+			</ul>
+			<div class="clearfix"></div>
+		</div>
+	</div>
 	<div class="tight-form-inner-box" ng-if="agg.type === 'terms'">
 	<div class="tight-form-inner-box" ng-if="agg.type === 'terms'">
 		<div class="tight-form">
 		<div class="tight-form">
 			<ul class="tight-form-list">
 			<ul class="tight-form-list">
@@ -34,7 +47,7 @@
 					Order
 					Order
 				</li>
 				</li>
 				<li>
 				<li>
-					<metric-segment-model property="agg.order" options="orderOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
+					<metric-segment-model property="agg.settings.order" options="orderOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
 				</li>
 				</li>
 			</ul>
 			</ul>
 			<div class="clearfix"></div>
 			<div class="clearfix"></div>
@@ -45,7 +58,7 @@
 					Size
 					Size
 				</li>
 				</li>
 				<li>
 				<li>
-					<metric-segment-model property="agg.size" options="sizeOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
+					<metric-segment-model property="agg.settings.size" options="sizeOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
 				</li>
 				</li>
 			</ul>
 			</ul>
 			<div class="clearfix"></div>
 			<div class="clearfix"></div>
@@ -56,7 +69,7 @@
 					Order By
 					Order By
 				</li>
 				</li>
 				<li>
 				<li>
-					<metric-segment-model property="agg.orderBy" options="orderByOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
+					<metric-segment-model property="agg.settings.orderBy" options="orderByOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
 				</li>
 				</li>
 			</ul>
 			</ul>
 			<div class="clearfix"></div>
 			<div class="clearfix"></div>

+ 0 - 59
public/app/plugins/datasource/elasticsearch/partials/query.editor.html

@@ -74,63 +74,4 @@
 		</elastic-bucket-agg>
 		</elastic-bucket-agg>
 	</div>
 	</div>
 
 
-	<!-- 	<div class="tight&#45;form"> -->
-	<!-- 	<ul class="tight&#45;form&#45;list"> -->
-	<!-- 		<li class="tight&#45;form&#45;item query&#45;keyword tight&#45;form&#45;align" style="width: 75px;"> -->
-	<!-- 			<span ng&#45;show="$first">Group by</span> -->
-	<!-- 			<span ng&#45;show="!$first">Then by</span> -->
-	<!-- 		</li> -->
-	<!-- 		<li> -->
-	<!-- 			<elastic&#45;query&#45;component model="agg" get&#45;fields="getFields()" on&#45;change="queryUpdated()"></elastic&#45;query&#45;component> -->
-	<!-- 		</li> -->
-	<!-- 	</ul> -->
-  <!--  -->
-	<!-- 	<ul class="tight&#45;form&#45;list pull&#45;right"> -->
-	<!-- 		<li class="tight&#45;form&#45;item" ng&#45;if="$index === 0"> -->
-	<!-- 			<a class="pointer" ng&#45;click="addBucketAgg()"><i class="fa fa&#45;plus"></i></a> -->
-	<!-- 		</li> -->
-	<!-- 		<li class="tight&#45;form&#45;item" ng&#45;if="!$last"> -->
-	<!-- 			<a class="pointer" ng&#45;click="removeBucketAgg($index)"><i class="fa fa&#45;minus"></i></a> -->
-	<!-- 		</li> -->
-	<!-- 	</ul> -->
-	<!-- 	<div class="clearfix"></div> -->
-	<!-- </div> -->
-  <!--  -->
-	<!-- <div class="tight&#45;form" ng&#45;if="agg.showOptions"> -->
-	<!-- 	<div style="margin: 20px 0 20px 148px;display: inline&#45;block"> -->
-	<!-- 		<div class="tight&#45;form"> -->
-	<!-- 			<ul class="tight&#45;form&#45;list"> -->
-	<!-- 				<li class="tight&#45;form&#45;item" style="width: 60px"> -->
-	<!-- 					Order -->
-	<!-- 				</li> -->
-	<!-- 				<li> -->
-	<!-- 					<metric&#45;segment segment="" get&#45;alt&#45;segments="getFields()" on&#45;value&#45;changed="timeFieldChanged()"></metric&#45;segment> -->
-	<!-- 				</li> -->
-	<!-- 			</ul> -->
-	<!-- 			<div class="clearfix"></div> -->
-	<!-- 		</div> -->
-	<!-- 		<div class="tight&#45;form"> -->
-	<!-- 			<ul class="tight&#45;form&#45;list"> -->
-	<!-- 				<li class="tight&#45;form&#45;item" style="width: 60px"> -->
-	<!-- 					Size -->
-	<!-- 				</li> -->
-	<!-- 				<li> -->
-	<!-- 					<input type="text" class="input&#45;mini tight&#45;form&#45;input" ng&#45;model="agg.options.size" spellcheck='false' placeholder="0" ng&#45;blur="get_data()"> -->
-	<!-- 				</li> -->
-	<!-- 			</ul> -->
-	<!-- 			<div class="clearfix"></div> -->
-	<!-- 		</div> -->
-	<!-- 		<div class="tight&#45;form last"> -->
-	<!-- 			<ul class="tight&#45;form&#45;list"> -->
-	<!-- 				<li class="tight&#45;form&#45;item" style="width: 60px"> -->
-	<!-- 					Order by -->
-	<!-- 				</li> -->
-	<!-- 				<li> -->
-	<!-- 					<metric&#45;segment segment="timeSegment" get&#45;alt&#45;segments="getFields()" on&#45;value&#45;changed="timeFieldChanged()"></metric&#45;segment> -->
-	<!-- 				</li> -->
-	<!-- 			</ul> -->
-	<!-- 			<div class="clearfix"></div> -->
-	<!-- 		</div> -->
-	<!-- 	</div> -->
-
 </div>
 </div>

+ 1 - 54
public/app/plugins/datasource/elasticsearch/partials/query.options.html

@@ -1,24 +1,5 @@
 <section class="grafana-metric-options">
 <section class="grafana-metric-options">
-	<div class="tight-form">
-		<ul class="tight-form-list">
-			<li class="tight-form-item tight-form-item-icon">
-				<i class="fa fa-wrench"></i>
-			</li>
-			<li class="tight-form-item">
-				 Group by time interval
-			</li>
-			<li>
-				<input type="text" class="input-medium tight-form-input" ng-model="panel.interval" ng-blur="get_data();"
-				spellcheck='false' placeholder="example: >10s">
-			</li>
-			<li class="tight-form-item">
-				<i class="fa fa-question-circle" bs-tooltip="'Set a low limit by having a greater sign: example: >60s'" data-placement="right"></i>
-			</li>
-		</ul>
-		<div class="clearfix"></div>
-	</div>
-
-	<div class="tight-form">
+	<div class="tight-form last">
 		<ul class="tight-form-list">
 		<ul class="tight-form-list">
 			<li class="tight-form-item tight-form-item-icon">
 			<li class="tight-form-item tight-form-item-icon">
 				<i class="fa fa-info-circle"></i>
 				<i class="fa fa-info-circle"></i>
@@ -28,16 +9,6 @@
 					alias patterns
 					alias patterns
 				</a>
 				</a>
 			</li>
 			</li>
-			<li class="tight-form-item">
-				<a ng-click="toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
-					stacking &amp; and fill
-				</a>
-			</li>
-			<li class="tight-form-item">
-				<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
-					group by time
-				</a>
-			</li>
 		</ul>
 		</ul>
 		<div class="clearfix"></div>
 		<div class="clearfix"></div>
 	</div>
 	</div>
@@ -56,30 +27,6 @@
 			</ul>
 			</ul>
 		</div>
 		</div>
 
 
-		<div class="grafana-info-box span6" ng-if="editorHelpIndex === 2">
-			<h5>Stacking and fill</h5>
-			<ul>
-				<li>When stacking is enabled it important that points align</li>
-				<li>If there are missing points for one series it can cause gaps or missing bars</li>
-				<li>You must use fill(0), and select a group by time low limit</li>
-				<li>Use the group by time option below your queries and specify for example &gt;10s if your metrics are written every 10 seconds</li>
-				<li>This will insert zeros for series that are missing measurements and will make stacking work properly</li>
-			</ul>
-		</div>
-
-		<div class="grafana-info-box span6" ng-if="editorHelpIndex === 3">
-			<h5>Group by time</h5>
-			<ul>
-				<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
-				<li>Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph</li>
-				<li>If you use fill(0) or fill(null) set a low limit for the auto group by time interval</li>
-				<li>The low limit can only be set in the group by time option below your queries</li>
-				<li>You set a low limit by adding a greater sign before the interval</li>
-				<li>Example: &gt;60s if you write metrics to ElasticDB every 60 seconds</li>
-			</ul>
-		</div>
-
-
 	</div>
 	</div>
 </div>
 </div>
 
 

+ 18 - 7
public/app/plugins/datasource/elasticsearch/queryBuilder.js

@@ -16,21 +16,24 @@ function (angular) {
 
 
   ElasticQueryBuilder.prototype.buildTermsAgg = function(aggDef, queryNode, target) {
   ElasticQueryBuilder.prototype.buildTermsAgg = function(aggDef, queryNode, target) {
     var metricRef, metric, size, y;
     var metricRef, metric, size, y;
-
     queryNode.terms = { "field": aggDef.field };
     queryNode.terms = { "field": aggDef.field };
-    size = parseInt(aggDef.size, 10);
 
 
+    if (!aggDef.settings) {
+      return queryNode;
+    }
+
+    size = parseInt(aggDef.settings.size, 10);
     if (size > 0) { queryNode.terms.size = size; }
     if (size > 0) { queryNode.terms.size = size; }
-    if (aggDef.orderBy !== void 0) {
+    if (aggDef.settings.orderBy !== void 0) {
       queryNode.terms.order = {};
       queryNode.terms.order = {};
-      queryNode.terms.order[aggDef.orderBy] = aggDef.order;
+      queryNode.terms.order[aggDef.settings.orderBy] = aggDef.settings.order;
 
 
       // if metric ref, look it up and add it to this agg level
       // if metric ref, look it up and add it to this agg level
-      metricRef = parseInt(aggDef.orderBy, 10);
+      metricRef = parseInt(aggDef.settings.orderBy, 10);
       if (!isNaN(metricRef)) {
       if (!isNaN(metricRef)) {
         for (y = 0; y < target.metrics.length; y++) {
         for (y = 0; y < target.metrics.length; y++) {
           metric = target.metrics[y];
           metric = target.metrics[y];
-          if (metric.id === aggDef.orderBy) {
+          if (metric.id === aggDef.settings.orderBy) {
             queryNode.aggs = {};
             queryNode.aggs = {};
             queryNode.aggs[metric.id] = {};
             queryNode.aggs[metric.id] = {};
             queryNode.aggs[metric.id][metric.type] = {field: metric.field};
             queryNode.aggs[metric.id][metric.type] = {field: metric.field};
@@ -43,6 +46,14 @@ function (angular) {
     return queryNode;
     return queryNode;
   };
   };
 
 
+  ElasticQueryBuilder.prototype.getInterval = function(agg) {
+    if (agg.settings && agg.settings.interval !== 'auto') {
+      return agg.settings.interval;
+    } else {
+      return '$interval';
+    }
+  };
+
   ElasticQueryBuilder.prototype.build = function(target) {
   ElasticQueryBuilder.prototype.build = function(target) {
     if (target.rawQuery) {
     if (target.rawQuery) {
       return angular.fromJson(target.rawQuery);
       return angular.fromJson(target.rawQuery);
@@ -77,7 +88,7 @@ function (angular) {
       switch(aggDef.type) {
       switch(aggDef.type) {
         case 'date_histogram': {
         case 'date_histogram': {
           esAgg["date_histogram"] = {
           esAgg["date_histogram"] = {
-            "interval": target.interval || "$interval",
+            "interval": this.getInterval(aggDef),
             "field": this.timeField,
             "field": this.timeField,
             "min_doc_count": 1,
             "min_doc_count": 1,
             "extended_bounds": { "min": "$timeFrom", "max": "$timeTo" }
             "extended_bounds": { "min": "$timeFrom", "max": "$timeTo" }

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

@@ -14,7 +14,7 @@ function (angular, _) {
       if (!target) { return; }
       if (!target) { return; }
 
 
       target.metrics = target.metrics || [{ type: 'count', id: '1' }];
       target.metrics = target.metrics || [{ type: 'count', id: '1' }];
-      target.bucketAggs = target.bucketAggs || [{ type: 'date_histogram', id: '2'}];
+      target.bucketAggs = target.bucketAggs || [{type: 'date_histogram', id: '2', settings: {interval: 'auto'}}];
       target.timeField =  $scope.datasource.timeField;
       target.timeField =  $scope.datasource.timeField;
     };
     };
 
 

+ 11 - 0
public/app/plugins/datasource/elasticsearch/queryDef.js

@@ -53,6 +53,17 @@ function (_) {
       {text: 'Std Dev Lower', value: 'std_deviation_bounds_lower'},
       {text: 'Std Dev Lower', value: 'std_deviation_bounds_lower'},
     ],
     ],
 
 
+    intervalOptions: [
+      {text: 'auto', value: 'auto'},
+      {text: '10s', value: '10s'},
+      {text: '1m', value: '1m'},
+      {text: '5m', value: '5m'},
+      {text: '10m', value: '10m'},
+      {text: '20m', value: '20m'},
+      {text: '1h', value: '1h'},
+      {text: '1d', value: '1d'},
+    ],
+
     getOrderByOptions: function(target) {
     getOrderByOptions: function(target) {
       var self = this;
       var self = this;
       var metricRefs = [];
       var metricRefs = [];

+ 5 - 2
public/test/specs/elasticsearch-querybuilder-specs.js

@@ -48,9 +48,12 @@ define([
 
 
     it('with term agg and order by metric agg', function() {
     it('with term agg and order by metric agg', function() {
       var query = builder.build({
       var query = builder.build({
-        metrics: [{type: 'count', id: '1'}, {type: 'avg', field: '@value', id: '5'}],
+        metrics: [
+          {type: 'count', id: '1'},
+          {type: 'avg', field: '@value', id: '5'}
+        ],
         bucketAggs: [
         bucketAggs: [
-          {type: 'terms', field: '@host', size: 5, order: 'asc', orderBy: '5', id: '2' },
+          {type: 'terms', field: '@host', settings: {size: 5, order: 'asc', orderBy: '5'}, id: '2' },
           {type: 'date_histogram', field: '@timestamp', id: '3'}
           {type: 'date_histogram', field: '@timestamp', id: '3'}
         ],
         ],
       }, 100, 1000);
       }, 100, 1000);