mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'moving_avg_es_support' of https://github.com/bergquist/grafana into bergquist-moving_avg_es_support
This commit is contained in:
@@ -76,8 +76,12 @@ function (_, queryDef) {
|
||||
newSeries = { datapoints: [], metric: metric.type, field: metric.field, props: props};
|
||||
for (i = 0; i < esAgg.buckets.length; i++) {
|
||||
bucket = esAgg.buckets[i];
|
||||
value = bucket[metric.id].value;
|
||||
newSeries.datapoints.push([value, bucket.key]);
|
||||
|
||||
value = bucket[metric.id];
|
||||
if (value !== undefined) {
|
||||
newSeries.datapoints.push([value.value, bucket.key]);
|
||||
}
|
||||
|
||||
}
|
||||
seriesList.push(newSeries);
|
||||
break;
|
||||
@@ -193,7 +197,14 @@ function (_, queryDef) {
|
||||
});
|
||||
}
|
||||
|
||||
if (series.field) {
|
||||
if (series.field && series.metric === 'moving_avg') {
|
||||
var appliedAgg = _.findWhere(target.metrics, { id: series.field });
|
||||
if (appliedAgg) {
|
||||
metricName += ' ' + queryDef.describeMetric(appliedAgg);
|
||||
} else {
|
||||
metricName = 'Unset';
|
||||
}
|
||||
} else if (series.field) {
|
||||
metricName += ' ' + series.field;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,14 +13,21 @@ function (angular, _, queryDef) {
|
||||
|
||||
$scope.metricAggTypes = queryDef.metricAggTypes;
|
||||
$scope.extendedStats = queryDef.extendedStats;
|
||||
$scope.mavgOptions = [];
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.agg = metricAggs[$scope.index];
|
||||
$scope.validateModel();
|
||||
$scope.updateMavgOptions();
|
||||
};
|
||||
|
||||
$scope.updateMavgOptions = function() {
|
||||
$scope.mavgOptions = queryDef.getMovingAverageOptions($scope.target);
|
||||
};
|
||||
|
||||
$rootScope.onAppEvent('elastic-query-updated', function() {
|
||||
$scope.index = _.indexOf(metricAggs, $scope.agg);
|
||||
$scope.updateMavgOptions();
|
||||
$scope.validateModel();
|
||||
}, $scope);
|
||||
|
||||
@@ -35,6 +42,12 @@ function (angular, _, queryDef) {
|
||||
}
|
||||
|
||||
switch($scope.agg.type) {
|
||||
case 'moving_avg': {
|
||||
$scope.agg.pipelineAgg = $scope.agg.pipelineAgg || 'Metric to apply moving average';
|
||||
$scope.settingsLinkText = 'Moving average options';
|
||||
$scope.agg.field = $scope.agg.pipelineAgg;
|
||||
break;
|
||||
}
|
||||
case 'percentiles': {
|
||||
$scope.agg.settings.percents = $scope.agg.settings.percents || [25,50,75,95,99];
|
||||
$scope.settingsLinkText = 'values: ' + $scope.agg.settings.percents.join(',');
|
||||
@@ -65,6 +78,11 @@ function (angular, _, queryDef) {
|
||||
|
||||
$scope.toggleOptions = function() {
|
||||
$scope.showOptions = !$scope.showOptions;
|
||||
$scope.updateMavgOptions();
|
||||
};
|
||||
|
||||
$scope.onChangeInternal = function() {
|
||||
$scope.onChange();
|
||||
};
|
||||
|
||||
$scope.onTypeChange = function() {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<metric-segment-model property="agg.type" options="metricAggTypes" on-change="onTypeChange()" custom="false" css-class="tight-form-item-large"></metric-segment-model>
|
||||
</li>
|
||||
<li ng-if="aggDef.requiresField">
|
||||
<metric-segment-model property="agg.field" get-options="getFieldsInternal()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment>
|
||||
<metric-segment-model property="agg.field" get-options="getFieldsInternal()" on-change="onChange()" css-class="tight-form-item-xxlarge"></metric-segment-model>
|
||||
</li>
|
||||
<li class="tight-form-item last" ng-if="settingsLinkText">
|
||||
<a ng-click="toggleOptions()">{{settingsLinkText}}</a>
|
||||
@@ -27,6 +27,17 @@
|
||||
|
||||
<div class="tight-form" ng-if="showOptions">
|
||||
<div class="tight-form-inner-box">
|
||||
<div class="tight-form last" ng-if="agg.type === 'moving_avg'">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
Based on
|
||||
</li>
|
||||
<li>
|
||||
<metric-segment-model property="agg.pipelineAgg" options="mavgOptions" on-change="onChangeInternal()" css-class="last"></metric-segment-model>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div class="tight-form last" ng-if="agg.type === 'percentiles'">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
|
||||
@@ -167,14 +167,25 @@ function () {
|
||||
continue;
|
||||
}
|
||||
|
||||
var metricAgg = {field: metric.field};
|
||||
var aggField = {};
|
||||
var metricAgg = null;
|
||||
|
||||
if (metric.type === 'moving_avg') {
|
||||
if (metric.pipelineAgg && /^\d*$/.test(metric.pipelineAgg)) {
|
||||
metricAgg = { buckets_path: metric.pipelineAgg };
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
metricAgg = {field: metric.field};
|
||||
}
|
||||
|
||||
for (var prop in metric.settings) {
|
||||
if (metric.settings.hasOwnProperty(prop) && metric.settings[prop] !== null) {
|
||||
metricAgg[prop] = metric.settings[prop];
|
||||
}
|
||||
}
|
||||
|
||||
var aggField = {};
|
||||
aggField[metric.type] = metricAgg;
|
||||
nestedAggs.aggs[metric.id] = aggField;
|
||||
}
|
||||
@@ -217,5 +228,4 @@ function () {
|
||||
};
|
||||
|
||||
return ElasticQueryBuilder;
|
||||
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ function (_) {
|
||||
{text: "Min", value: 'min', requiresField: true},
|
||||
{text: "Extended Stats", value: 'extended_stats', requiresField: true},
|
||||
{text: "Percentiles", value: 'percentiles', requiresField: true},
|
||||
{text: "Moving Average", value: 'moving_avg', requiresField: false },
|
||||
{text: "Unique Count", value: "cardinality", requiresField: true},
|
||||
{text: "Raw Document", value: "raw_document", requiresField: false}
|
||||
],
|
||||
@@ -66,6 +67,28 @@ function (_) {
|
||||
{text: '1d', value: '1d'},
|
||||
],
|
||||
|
||||
pipelineAggs: ['moving_avg'],
|
||||
|
||||
isPipelineAgg: function(metric) {
|
||||
if (metric.type) {
|
||||
return this.pipelineAggs.indexOf(metric.type) > -1;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
getMovingAverageOptions: function(targets) {
|
||||
var self = this;
|
||||
var result = [];
|
||||
_.each(targets.metrics, function(metric) {
|
||||
if (metric.type !== 'moving_avg') {
|
||||
result.push({text: self.describeMetric(metric), value: metric.id });
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
getOrderByOptions: function(target) {
|
||||
var self = this;
|
||||
var metricRefs = [];
|
||||
|
||||
@@ -155,4 +155,64 @@ describe('ElasticQueryBuilder', function() {
|
||||
expect(query.size).to.be(500);
|
||||
});
|
||||
|
||||
it('with moving average', function() {
|
||||
var query = builder.build({
|
||||
metrics: [
|
||||
{
|
||||
id: '3',
|
||||
type: 'sum',
|
||||
field: '@value'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'moving_avg',
|
||||
field: '3',
|
||||
pipelineAgg: '3'
|
||||
}
|
||||
],
|
||||
bucketAggs: [
|
||||
{type: 'date_histogram', field: '@timestamp', id: '3'}
|
||||
],
|
||||
});
|
||||
|
||||
var firstLevel = query.aggs["3"];
|
||||
|
||||
expect(firstLevel.aggs["2"]).not.to.be(undefined);
|
||||
expect(firstLevel.aggs["2"].moving_avg).not.to.be(undefined);
|
||||
expect(firstLevel.aggs["2"].moving_avg.buckets_path).to.be("3");
|
||||
});
|
||||
|
||||
it('with broken moving average', function() {
|
||||
var query = builder.build({
|
||||
metrics: [
|
||||
{
|
||||
id: '3',
|
||||
type: 'sum',
|
||||
field: '@value'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'moving_avg',
|
||||
field: '3',
|
||||
pipelineAgg: '3'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'moving_avg',
|
||||
field: '3',
|
||||
pipelineAgg: 'Metric to apply moving average'
|
||||
}
|
||||
],
|
||||
bucketAggs: [
|
||||
{ type: 'date_histogram', field: '@timestamp', id: '3' }
|
||||
],
|
||||
});
|
||||
|
||||
var firstLevel = query.aggs["3"];
|
||||
|
||||
expect(firstLevel.aggs["2"]).not.to.be(undefined);
|
||||
expect(firstLevel.aggs["2"].moving_avg).not.to.be(undefined);
|
||||
expect(firstLevel.aggs["2"].moving_avg.buckets_path).to.be("3");
|
||||
expect(firstLevel.aggs["4"]).to.be(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
///<amd-dependency path="../query_def" name="QueryDef" />
|
||||
///<amd-dependency path="test/specs/helpers" name="helpers" />
|
||||
|
||||
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
|
||||
|
||||
declare var helpers: any;
|
||||
declare var QueryDef: any;
|
||||
|
||||
describe('ElasticQueryDef', function() {
|
||||
|
||||
describe('getMovingAverageOptions', function() {
|
||||
describe('with zero targets', function() {
|
||||
var response = QueryDef.getMovingAverageOptions([]);
|
||||
|
||||
it('should return zero', function() {
|
||||
expect(response.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with count and sum targets', function() {
|
||||
var targets = {
|
||||
metrics: [
|
||||
{ type: 'count', field: '@value' },
|
||||
{ type: 'sum', field: '@value' }
|
||||
]
|
||||
};
|
||||
|
||||
var response = QueryDef.getMovingAverageOptions(targets);
|
||||
|
||||
it('should return zero', function() {
|
||||
expect(response.length).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with count and moving average targets', function() {
|
||||
var targets = {
|
||||
metrics: [
|
||||
{ type: 'count', field: '@value' },
|
||||
{ type: 'moving_avg', field: '@value' }
|
||||
]
|
||||
};
|
||||
|
||||
var response = QueryDef.getMovingAverageOptions(targets);
|
||||
|
||||
it('should return zero', function() {
|
||||
expect(response.length).to.be(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPipelineMetric', function() {
|
||||
describe('moving_avg', function() {
|
||||
var result = QueryDef.isPipelineAgg({ type: 'moving_avg' });
|
||||
|
||||
it('is pipe line metric', function() {
|
||||
expect(result).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('count', function() {
|
||||
var result = QueryDef.isPipelineAgg({ type: 'count' });
|
||||
|
||||
it('is not pipe line metric', function() {
|
||||
expect(result).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user