mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(elasticsearch): more polish to editor, made interval configurable per query, #1034
This commit is contained in:
@@ -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") {
|
var settingsLinkText = "";
|
||||||
$scope.agg.order = $scope.agg.order || "asc";
|
var settings = $scope.agg.settings || {};
|
||||||
$scope.agg.size = $scope.agg.size || "0";
|
|
||||||
$scope.agg.orderBy = $scope.agg.orderBy || "_term";
|
|
||||||
|
|
||||||
if ($scope.agg.size !== '0') {
|
switch($scope.agg.type) {
|
||||||
$scope.settingsLinkText = queryDef.describeOrder($scope.agg.order) + ' ' + $scope.agg.size + ', ';
|
case 'terms': {
|
||||||
|
settings.order = settings.order || "asc";
|
||||||
|
settings.size = settings.size || "0";
|
||||||
|
settings.orderBy = settings.orderBy || "_term";
|
||||||
|
|
||||||
|
if (settings.size !== '0') {
|
||||||
|
settingsLinkText = queryDef.describeOrder(settings.order) + ' ' + settings.size + ', ';
|
||||||
|
}
|
||||||
|
|
||||||
|
settingsLinkText += 'Order by: ' + queryDef.describeOrderBy(settings.orderBy, $scope.target);
|
||||||
|
|
||||||
|
if (settings.size === '0') {
|
||||||
|
settingsLinkText += ' (' + settings.order + ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case 'date_histogram': {
|
||||||
$scope.settingsLinkText += 'Order by: ' + queryDef.describeOrderBy($scope.agg.orderBy, $scope.target);
|
settings.interval = settings.interval || 'auto';
|
||||||
|
$scope.agg.field = $scope.target.timeField;
|
||||||
if ($scope.agg.size === '0') {
|
settingsLinkText = 'Interval: ' + settings.interval;
|
||||||
$scope.settingsLinkText += ' (' + $scope.agg.order + ')';
|
|
||||||
}
|
}
|
||||||
} else if ($scope.agg.type === 'date_histogram') {
|
|
||||||
$scope.agg.field = $scope.target.timeField;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$scope.settingsLinkText = settingsLinkText;
|
||||||
|
$scope.agg.settings = settings;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -74,63 +74,4 @@
|
|||||||
</elastic-bucket-agg>
|
</elastic-bucket-agg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="tight-form"> -->
|
|
||||||
<!-- <ul class="tight-form-list"> -->
|
|
||||||
<!-- <li class="tight-form-item query-keyword tight-form-align" style="width: 75px;"> -->
|
|
||||||
<!-- <span ng-show="$first">Group by</span> -->
|
|
||||||
<!-- <span ng-show="!$first">Then by</span> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- <li> -->
|
|
||||||
<!-- <elastic-query-component model="agg" get-fields="getFields()" on-change="queryUpdated()"></elastic-query-component> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- </ul> -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <ul class="tight-form-list pull-right"> -->
|
|
||||||
<!-- <li class="tight-form-item" ng-if="$index === 0"> -->
|
|
||||||
<!-- <a class="pointer" ng-click="addBucketAgg()"><i class="fa fa-plus"></i></a> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- <li class="tight-form-item" ng-if="!$last"> -->
|
|
||||||
<!-- <a class="pointer" ng-click="removeBucketAgg($index)"><i class="fa fa-minus"></i></a> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- </ul> -->
|
|
||||||
<!-- <div class="clearfix"></div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
<!-- -->
|
|
||||||
<!-- <div class="tight-form" ng-if="agg.showOptions"> -->
|
|
||||||
<!-- <div style="margin: 20px 0 20px 148px;display: inline-block"> -->
|
|
||||||
<!-- <div class="tight-form"> -->
|
|
||||||
<!-- <ul class="tight-form-list"> -->
|
|
||||||
<!-- <li class="tight-form-item" style="width: 60px"> -->
|
|
||||||
<!-- Order -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- <li> -->
|
|
||||||
<!-- <metric-segment segment="" get-alt-segments="getFields()" on-value-changed="timeFieldChanged()"></metric-segment> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- </ul> -->
|
|
||||||
<!-- <div class="clearfix"></div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
<!-- <div class="tight-form"> -->
|
|
||||||
<!-- <ul class="tight-form-list"> -->
|
|
||||||
<!-- <li class="tight-form-item" style="width: 60px"> -->
|
|
||||||
<!-- Size -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- <li> -->
|
|
||||||
<!-- <input type="text" class="input-mini tight-form-input" ng-model="agg.options.size" spellcheck='false' placeholder="0" ng-blur="get_data()"> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- </ul> -->
|
|
||||||
<!-- <div class="clearfix"></div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
<!-- <div class="tight-form last"> -->
|
|
||||||
<!-- <ul class="tight-form-list"> -->
|
|
||||||
<!-- <li class="tight-form-item" style="width: 60px"> -->
|
|
||||||
<!-- Order by -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- <li> -->
|
|
||||||
<!-- <metric-segment segment="timeSegment" get-alt-segments="getFields()" on-value-changed="timeFieldChanged()"></metric-segment> -->
|
|
||||||
<!-- </li> -->
|
|
||||||
<!-- </ul> -->
|
|
||||||
<!-- <div class="clearfix"></div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
<!-- </div> -->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,24 +1,5 @@
|
|||||||
<section class="grafana-metric-options">
|
<section class="grafana-metric-options">
|
||||||
<div class="tight-form">
|
<div class="tight-form last">
|
||||||
<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">
|
|
||||||
<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 & 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 >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: >60s if you write metrics to ElasticDB every 60 seconds</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -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" }
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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 = [];
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user