mirror of
https://github.com/grafana/grafana.git
synced 2025-01-10 08:03:58 -06:00
feat(elasticsearch): worked on percentiles metric aggregator in editor and in elasticsearch response processing
This commit is contained in:
parent
3e9aca3ed4
commit
f942ec952e
@ -33,24 +33,26 @@ function (angular, _, queryDef) {
|
||||
};
|
||||
|
||||
$scope.validateModel = function() {
|
||||
$scope.index = _.indexOf(bucketAggs, $scope.agg);
|
||||
|
||||
$scope.isFirst = $scope.index === 0;
|
||||
$scope.isLast = $scope.index === bucketAggs.length - 1;
|
||||
$scope.aggOptionsString = "";
|
||||
$scope.settingsLinkText = "";
|
||||
|
||||
if ($scope.agg.type === "terms") {
|
||||
$scope.agg.order = $scope.agg.order || "desc";
|
||||
$scope.agg.size = $scope.agg.size || "0";
|
||||
$scope.agg.orderBy = $scope.agg.orderBy || "_count";
|
||||
$scope.agg.orderBy = $scope.agg.orderBy || "_term";
|
||||
|
||||
if ($scope.agg.size === '0') {
|
||||
$scope.aggOptionsString = "";
|
||||
$scope.settingsLinkText = "";
|
||||
} else {
|
||||
$scope.aggOptionsString = queryDef.describeOrder($scope.agg.order) + ' ' + $scope.agg.size + ', '
|
||||
$scope.settingsLinkText = queryDef.describeOrder($scope.agg.order) + ' ' + $scope.agg.size + ', '
|
||||
}
|
||||
$scope.aggOptionsString += 'Order by: ' + queryDef.describeOrderBy($scope.agg.orderBy, $scope.target);
|
||||
$scope.settingsLinkText += 'Order by: ' + queryDef.describeOrderBy($scope.agg.orderBy, $scope.target);
|
||||
|
||||
if ($scope.agg.size === '0') {
|
||||
$scope.aggOptionsString += ' (' + $scope.agg.order + ')';
|
||||
$scope.settingsLinkText += ' (' + $scope.agg.order + ')';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,10 +175,18 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
|
||||
// This is quite complex
|
||||
// neeed to recurise down the nested buckets to build series
|
||||
ElasticDatasource.prototype._processBuckets = function(aggs, target, series, level, parentName) {
|
||||
var seriesName, value, metric, i, y, bucket, childBucket, aggDef, esAgg;
|
||||
var seriesName, value, metric, i, y, z, bucket, childBucket, aggDef, esAgg;
|
||||
var buckets;
|
||||
var dataFound = 0;
|
||||
|
||||
function addMetricPoint(seriesName, value, time) {
|
||||
var current = series[seriesName];
|
||||
if (!current) {
|
||||
current = series[seriesName] = {target: seriesName, datapoints: []};
|
||||
}
|
||||
current.datapoints.push([value, time]);
|
||||
}
|
||||
|
||||
aggDef = target.bucketAggs[level];
|
||||
esAgg = aggs[aggDef.id];
|
||||
|
||||
@ -191,16 +199,27 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
|
||||
metric = target.metrics[y];
|
||||
seriesName = parentName;
|
||||
|
||||
if (metric.type === 'count') {
|
||||
seriesName += ' count';
|
||||
value = bucket.doc_count;
|
||||
} else {
|
||||
seriesName += ' ' + metric.field + ' ' + metric.type;
|
||||
value = bucket[metric.id].value;
|
||||
switch(metric.type) {
|
||||
case 'count': {
|
||||
seriesName += ' count';
|
||||
value = bucket.doc_count;
|
||||
addMetricPoint(seriesName, value, bucket.key);
|
||||
break;
|
||||
}
|
||||
case 'percentiles': {
|
||||
var values = bucket[metric.id].values;
|
||||
for (var prop in values) {
|
||||
addMetricPoint(seriesName + ' ' + prop, values[prop], bucket.key)
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
seriesName += ' ' + metric.field + ' ' + metric.type;
|
||||
value = bucket[metric.id].value;
|
||||
addMetricPoint(seriesName, value, bucket.key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var serie = series[seriesName] = series[seriesName] || {target: seriesName, datapoints: []};
|
||||
serie.datapoints.push([value, bucket.key]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -8,27 +8,43 @@ function (angular, _, queryDef) {
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
module.controller('ElasticMetricAggCtrl', function($scope, uiSegmentSrv, $q) {
|
||||
module.controller('ElasticMetricAggCtrl', function($scope, uiSegmentSrv, $q, $rootScope) {
|
||||
var metricAggs = $scope.target.metrics;
|
||||
|
||||
$scope.metricAggTypes = queryDef.metricAggTypes;
|
||||
|
||||
$scope.init = function() {
|
||||
$scope.agg = metricAggs[$scope.index];
|
||||
$scope.validateModel();
|
||||
}
|
||||
|
||||
$rootScope.onAppEvent('elastic-query-updated', function() {
|
||||
$scope.index = _.indexOf(metricAggs, $scope.agg);
|
||||
|
||||
$scope.isFirst = $scope.index === 0;
|
||||
$scope.isSingle = metricAggs.length === 1;
|
||||
$scope.validateModel();
|
||||
});
|
||||
|
||||
$scope.validateModel = function() {
|
||||
if (!$scope.agg.field) {
|
||||
$scope.agg.field = 'select field';
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watchCollection("target.metrics", function() {
|
||||
$scope.isFirst = $scope.index === 0;
|
||||
$scope.isLast = $scope.index === metricAggs.length - 1;
|
||||
$scope.isSingle = metricAggs.length === 1;
|
||||
});
|
||||
if ($scope.agg.type === 'percentiles') {
|
||||
$scope.agg.settings.percents = $scope.agg.settings.percents || [25,50,75,95,99];
|
||||
$scope.settingsLinkText = 'values: ' + $scope.agg.settings.percents.join(',');
|
||||
}
|
||||
}
|
||||
|
||||
$scope.toggleOptions = function() {
|
||||
$scope.showOptions = !$scope.showOptions;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.onTypeChange = function() {
|
||||
$scope.agg.settings = {};
|
||||
$scope.onChange();
|
||||
};
|
||||
|
||||
$scope.addMetricAgg = function() {
|
||||
var addIndex = metricAggs.length;
|
||||
|
@ -8,8 +8,8 @@
|
||||
<metric-segment-model property="agg.type" options="bucketAggTypes" on-change="onChangeInternal()"></metric-segment-model>
|
||||
<metric-segment-model property="agg.field" get-options="getFields()" on-change="onChangeInternal()"></metric-segment>
|
||||
</li>
|
||||
<li class="tight-form-item tight-form-align" ng-if="aggOptionsString">
|
||||
<a ng-click="toggleOptions()">{{aggOptionsString}}</a>
|
||||
<li class="tight-form-item tight-form-align" ng-if="settingsLinkText">
|
||||
<a ng-click="toggleOptions()">{{settingsLinkText}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -4,13 +4,13 @@
|
||||
Metric
|
||||
</li>
|
||||
<li>
|
||||
<metric-segment-model property="agg.type" options="metricAggTypes" on-change="onChange()"></metric-segment-model>
|
||||
<metric-segment-model property="agg.type" options="metricAggTypes" on-change="onTypeChange()"></metric-segment-model>
|
||||
</li>
|
||||
<li ng-if="agg.type !== 'count'">
|
||||
<metric-segment-model property="agg.field" get-options="getFields()" on-change="onChange()"></metric-segment>
|
||||
</li>
|
||||
<li class="tight-form-item tight-form-align" ng-if="aggOptionsString">
|
||||
<a ng-click="toggleOptions()">{{aggOptionsString}}</a>
|
||||
<li class="tight-form-item tight-form-align" ng-if="settingsLinkText">
|
||||
<a ng-click="toggleOptions()">{{settingsLinkText}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@ -25,4 +25,18 @@
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="tight-form" ng-if="showOptions">
|
||||
<div style="margin: 20px 0 20px 148px;display: inline-block">
|
||||
<div class="tight-form last" ng-if="agg.type === 'percentiles'">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
Percentiles
|
||||
</li>
|
||||
<li>
|
||||
<input type="text" class="input-xlarge tight-form-input last" ng-model="agg.settings.percents" array-join ng-blur="onChange()"></input>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -48,7 +48,7 @@ function (angular) {
|
||||
esAgg["date_histogram"] = {
|
||||
"interval": target.interval || "$interval",
|
||||
"field": aggDef.field,
|
||||
"min_doc_count": 0,
|
||||
"min_doc_count": 1,
|
||||
"extended_bounds": { "min": "$timeFrom", "max": "$timeTo" }
|
||||
};
|
||||
break;
|
||||
@ -92,8 +92,15 @@ function (angular) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var metricAgg = {field: metric.field};
|
||||
for (var prop in metric.settings) {
|
||||
if (metric.settings.hasOwnProperty(prop)) {
|
||||
metricAgg[prop] = metric.settings[prop];
|
||||
}
|
||||
}
|
||||
|
||||
var aggField = {};
|
||||
aggField[metric.type] = {field: metric.field};
|
||||
aggField[metric.type] = metricAgg;
|
||||
nestedAggs.aggs[metric.id] = aggField;
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ function (_) {
|
||||
{text: "Max of", value: 'max' },
|
||||
{text: "Min of", value: 'min' },
|
||||
{text: "Standard Deviations", value: 'std_dev' },
|
||||
{text: "Percentiles", value: 'percentiles' },
|
||||
],
|
||||
|
||||
bucketAggTypes: [
|
||||
|
@ -65,6 +65,31 @@ define([
|
||||
expect(secondLevel.aggs["5"].avg.field).to.be("@value");
|
||||
});
|
||||
|
||||
it('with metric percentiles', function() {
|
||||
var builder = new ElasticQueryBuilder();
|
||||
|
||||
var query = builder.build({
|
||||
metrics: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'percentiles',
|
||||
field: '@load_time',
|
||||
settings: {
|
||||
percents: [1,2,3,4]
|
||||
}
|
||||
}
|
||||
],
|
||||
bucketAggs: [
|
||||
{type: 'date_histogram', field: '@timestamp', id: '3'}
|
||||
],
|
||||
}, 100, 1000);
|
||||
|
||||
var firstLevel = query.aggs["3"];
|
||||
|
||||
expect(firstLevel.aggs["1"].percentiles.field).to.be("@load_time");
|
||||
expect(firstLevel.aggs["1"].percentiles.percents).to.eql([1,2,3,4]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -145,6 +145,48 @@ define([
|
||||
});
|
||||
});
|
||||
|
||||
describe('with percentiles ', function() {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
result = ctx.ds._processTimeSeries([{
|
||||
refId: 'A',
|
||||
metrics: [{type: 'percentiles', settings: {percents: [75, 90]}, id: '1'}],
|
||||
bucketAggs: [{type: 'date_histogram', field: '@timestamp', id: '3'}],
|
||||
}], {
|
||||
responses: [{
|
||||
aggregations: {
|
||||
"3": {
|
||||
buckets: [
|
||||
{
|
||||
"1": {values: {"75": 3.3, "90": 5.5}},
|
||||
doc_count: 10,
|
||||
key: 1000
|
||||
},
|
||||
{
|
||||
"1": {values: {"75": 2.3, "90": 4.5}},
|
||||
doc_count: 15,
|
||||
key: 2000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(2);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].target).to.be('A 75');
|
||||
expect(result.data[1].target).to.be('A 90');
|
||||
expect(result.data[0].datapoints[0][0]).to.be(3.3);
|
||||
expect(result.data[0].datapoints[0][1]).to.be(1000);
|
||||
expect(result.data[1].datapoints[1][0]).to.be(4.5);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user