Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 84 additions & 1 deletion dist/datasource.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function (angular, _, dateMath, moment) {
var filters = target.filters;
var aggregators = target.aggregators;
var postAggregators = target.postAggregators;
var bucketAggregators = getBucketAggregators(target.postAggregators);
var groupBy = _.map(target.groupBy, (e) => { return templateSrv.replace(e) });
var limitSpec = null;
var metricNames = getMetricNames(aggregators, postAggregators);
Expand Down Expand Up @@ -189,7 +190,13 @@ function (angular, _, dateMath, moment) {
else {
promise = this._timeSeriesQuery(datasource, intervals, granularity, filters, aggregators, postAggregators)
.then(function(response) {
return convertTimeSeriesData(response.data, metricNames);
if (_.isEmpty(bucketAggregators)) {
return convertTimeSeriesData(response.data, metricNames);
}
else {
return convertBucketsData(response.data, bucketAggregators);
}

});
}
/*
Expand Down Expand Up @@ -352,6 +359,12 @@ function (angular, _, dateMath, moment) {
return _.union(_.map(displayAggs, 'name'), _.map(postAggregators, 'name'));
}

function getBucketAggregators(postAggregators) {
return _.filter(postAggregators, function (agg) {
return agg.type === 'buckets';
});
}

function formatTimestamp(ts) {
return moment(ts).format('X')*1000;
}
Expand All @@ -370,6 +383,76 @@ function (angular, _, dateMath, moment) {
});
}

function convertBucketsData(md, bucketAggs) {

/*
The response data is of the form:
[
{
timestamp: "xxx",
result:
<aggregator name>:
breaks: [...],
counts: [...]
},
...
]

We need to transform the data so that each breakpoint has a series:
[
{
target: <breakpoint 0>,
datapoints: [
[<count>, <timestamp in ms>],
]
},
...
]

*/

if (! md.length) {
console.log("Cannot calculate buckets because query data is empty");
return [];
}

/*
The original data will not have values for all breakpoints.
We first need to work out which breakpoints to use.
*/
var bucket = _.map(bucketAggs, 'name')[0];
var bucketSize = Number(_.map(bucketAggs, 'bucketSize')[0]);
var topbreaks = _.map(md, function (item) {
return item.result[bucket].breaks.slice(-1)[0];
});
var breaks = _.range(0, _.max(topbreaks), bucketSize);

if (! breaks.length) {
console.log("Cannot calculate buckets because there are no breakpoints");
return [];
}

return breaks.map(function (metric) {
return {
target: String(metric),
datapoints: md.map(function (item) {
var index = item.result[bucket].breaks.indexOf(metric);
if (index == -1) {
return [
null,
formatTimestamp(item.timestamp)
];
} else {
return [
item.result[bucket].counts[index],
formatTimestamp(item.timestamp)
];
}
})
};
});
}

function getGroupName(groupBy, metric) {
return groupBy.map(function (dim) {
return metric.event[dim];
Expand Down
15 changes: 15 additions & 0 deletions dist/partials/query.editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,14 @@
</a>
</label>
</div>
<div ng-switch-when="buckets">
<label class="gf-form-label">
{{postAggregator.type}}:&nbsp;name&nbsp;=&nbsp;{{postAggregator.name}},&nbsp;field&nbsp;=&nbsp;{{postAggregator.fieldName}}, &nbsp;size&nbsp;=&nbsp;{{postAggregator.bucketSize}}
<a ng-click="ctrl.removePostAggregator($index)">
<i class="fa fa-remove"></i>
</a>
</label>
</div>
</div>
</div>

Expand Down Expand Up @@ -469,6 +477,13 @@
<input type="text" ng-switch-when="quantile" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.probability" placeholder="probability" ng-blur="ctrl.targetBlur()">
</div>

<!-- buckets -->
<div class="gf-form" ng-show="ctrl.addPostAggregatorMode" ng-switch on="ctrl.target.currentPostAggregator.type">
<input type="text" ng-switch-when="buckets" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.name" placeholder="output name" ng-blur="ctrl.targetBlur()">
<input type="text" ng-switch-when="buckets" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.fieldName" placeholder="agg name" ng-blur="ctrl.targetBlur()">
<input type="text" ng-switch-when="buckets" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.bucketSize" placeholder="bucketSize" ng-blur="ctrl.targetBlur()">
</div>

<div class="gf-form" ng-show="ctrl.addPostAggregatorMode">
<label class="gf-form-label">
<a ng-click="ctrl.addPostAggregator()">add tag</a>
Expand Down
2 changes: 2 additions & 0 deletions dist/query_ctrl.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export declare class DruidQueryCtrl extends QueryCtrl {
"max": any;
"min": any;
"quantile": any;
"buckets": any;
};
arithmeticPostAggregatorFns: {
'+': any;
Expand Down Expand Up @@ -107,6 +108,7 @@ export declare class DruidQueryCtrl extends QueryCtrl {
validateMaxPostAggregator(target: any): string;
validateMinPostAggregator(target: any): string;
validateQuantilePostAggregator(target: any): string;
validateBucketsPostAggregator(target: any): string;
validateArithmeticPostAggregator(target: any): string;
validateTarget(): any;
}
13 changes: 12 additions & 1 deletion dist/query_ctrl.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/query_ctrl.js.map

Large diffs are not rendered by default.

13 changes: 12 additions & 1 deletion dist/query_ctrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export class DruidQueryCtrl extends QueryCtrl {
"arithmetic": this.validateArithmeticPostAggregator.bind(this),
"max": this.validateMaxPostAggregator.bind(this),
"min": this.validateMinPostAggregator.bind(this),
"quantile": this.validateQuantilePostAggregator.bind(this)
"quantile": this.validateQuantilePostAggregator.bind(this),
"buckets": this.validateBucketsPostAggregator.bind(this)
};

arithmeticPostAggregatorFns = {'+': null, '-': null, '*': null, '/': null};
Expand Down Expand Up @@ -513,6 +514,16 @@ export class DruidQueryCtrl extends QueryCtrl {
return null;
}

validateBucketsPostAggregator(target) {
var err = this.validateSimplePostAggregator('buckets', target);
if (err) { return err; }
if (!target.currentPostAggregator.bucketSize) {
return "Must provide a bucket size for the buckets post aggregator.";
}
return null;
}


validateArithmeticPostAggregator(target) {
if (!target.currentPostAggregator.name) {
return "Must provide an output name for arithmetic post aggregator.";
Expand Down
2 changes: 2 additions & 0 deletions dist/test/query_ctrl.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export declare class DruidQueryCtrl extends QueryCtrl {
"max": any;
"min": any;
"quantile": any;
"buckets": any;
};
arithmeticPostAggregatorFns: {
'+': any;
Expand Down Expand Up @@ -107,6 +108,7 @@ export declare class DruidQueryCtrl extends QueryCtrl {
validateMaxPostAggregator(target: any): string;
validateMinPostAggregator(target: any): string;
validateQuantilePostAggregator(target: any): string;
validateBucketsPostAggregator(target: any): string;
validateArithmeticPostAggregator(target: any): string;
validateTarget(): any;
}
13 changes: 12 additions & 1 deletion dist/test/query_ctrl.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/test/query_ctrl.js.map

Large diffs are not rendered by default.

85 changes: 84 additions & 1 deletion src/datasource.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ function (angular, _, dateMath, moment) {
var filters = target.filters;
var aggregators = target.aggregators;
var postAggregators = target.postAggregators;
var bucketAggregators = getBucketAggregators(target.postAggregators);
var groupBy = _.map(target.groupBy, (e) => { return templateSrv.replace(e) });
var limitSpec = null;
var metricNames = getMetricNames(aggregators, postAggregators);
Expand Down Expand Up @@ -189,7 +190,13 @@ function (angular, _, dateMath, moment) {
else {
promise = this._timeSeriesQuery(datasource, intervals, granularity, filters, aggregators, postAggregators)
.then(function(response) {
return convertTimeSeriesData(response.data, metricNames);
if (_.isEmpty(bucketAggregators)) {
return convertTimeSeriesData(response.data, metricNames);
}
else {
return convertBucketsData(response.data, bucketAggregators);
}

});
}
/*
Expand Down Expand Up @@ -352,6 +359,12 @@ function (angular, _, dateMath, moment) {
return _.union(_.map(displayAggs, 'name'), _.map(postAggregators, 'name'));
}

function getBucketAggregators(postAggregators) {
return _.filter(postAggregators, function (agg) {
return agg.type === 'buckets';
});
}

function formatTimestamp(ts) {
return moment(ts).format('X')*1000;
}
Expand All @@ -370,6 +383,76 @@ function (angular, _, dateMath, moment) {
});
}

function convertBucketsData(md, bucketAggs) {

/*
The response data is of the form:
[
{
timestamp: "xxx",
result:
<aggregator name>:
breaks: [...],
counts: [...]
},
...
]

We need to transform the data so that each breakpoint has a series:
[
{
target: <breakpoint 0>,
datapoints: [
[<count>, <timestamp in ms>],
]
},
...
]

*/

if (! md.length) {
console.log("Cannot calculate buckets because query data is empty");
return [];
}

/*
The original data will not have values for all breakpoints.
We first need to work out which breakpoints to use.
*/
var bucket = _.map(bucketAggs, 'name')[0];
var bucketSize = Number(_.map(bucketAggs, 'bucketSize')[0]);
var topbreaks = _.map(md, function (item) {
return item.result[bucket].breaks.slice(-1)[0];
});
var breaks = _.range(0, _.max(topbreaks), bucketSize);

if (! breaks.length) {
console.log("Cannot calculate buckets because there are no breakpoints");
return [];
}

return breaks.map(function (metric) {
return {
target: String(metric),
datapoints: md.map(function (item) {
var index = item.result[bucket].breaks.indexOf(metric);
if (index == -1) {
return [
null,
formatTimestamp(item.timestamp)
];
} else {
return [
item.result[bucket].counts[index],
formatTimestamp(item.timestamp)
];
}
})
};
});
}

function getGroupName(groupBy, metric) {
return groupBy.map(function (dim) {
return metric.event[dim];
Expand Down
15 changes: 15 additions & 0 deletions src/partials/query.editor.html
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,14 @@
</a>
</label>
</div>
<div ng-switch-when="buckets">
<label class="gf-form-label">
{{postAggregator.type}}:&nbsp;name&nbsp;=&nbsp;{{postAggregator.name}},&nbsp;field&nbsp;=&nbsp;{{postAggregator.fieldName}}, &nbsp;size&nbsp;=&nbsp;{{postAggregator.bucketSize}}
<a ng-click="ctrl.removePostAggregator($index)">
<i class="fa fa-remove"></i>
</a>
</label>
</div>
</div>
</div>

Expand Down Expand Up @@ -469,6 +477,13 @@
<input type="text" ng-switch-when="quantile" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.probability" placeholder="probability" ng-blur="ctrl.targetBlur()">
</div>

<!-- buckets -->
<div class="gf-form" ng-show="ctrl.addPostAggregatorMode" ng-switch on="ctrl.target.currentPostAggregator.type">
<input type="text" ng-switch-when="buckets" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.name" placeholder="output name" ng-blur="ctrl.targetBlur()">
<input type="text" ng-switch-when="buckets" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.fieldName" placeholder="agg name" ng-blur="ctrl.targetBlur()">
<input type="text" ng-switch-when="buckets" class="input-small gf-form-input" spellcheck="false" ng-model="ctrl.target.currentPostAggregator.bucketSize" placeholder="bucketSize" ng-blur="ctrl.targetBlur()">
</div>

<div class="gf-form" ng-show="ctrl.addPostAggregatorMode">
<label class="gf-form-label">
<a ng-click="ctrl.addPostAggregator()">add tag</a>
Expand Down
Loading