mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
(cloudwatch) percentile support (#6634)
* support extended statistics * handle different response format for extended statistics
This commit is contained in:
committed by
Torkel Ödegaard
parent
d56b9a720a
commit
be26c017f6
@@ -181,25 +181,33 @@ func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
|
|||||||
|
|
||||||
reqParam := &struct {
|
reqParam := &struct {
|
||||||
Parameters struct {
|
Parameters struct {
|
||||||
Namespace string `json:"namespace"`
|
Namespace string `json:"namespace"`
|
||||||
MetricName string `json:"metricName"`
|
MetricName string `json:"metricName"`
|
||||||
Dimensions []*cloudwatch.Dimension `json:"dimensions"`
|
Dimensions []*cloudwatch.Dimension `json:"dimensions"`
|
||||||
Statistics []*string `json:"statistics"`
|
Statistics []*string `json:"statistics"`
|
||||||
StartTime int64 `json:"startTime"`
|
ExtendedStatistics []*string `json:"extendedStatistics"`
|
||||||
EndTime int64 `json:"endTime"`
|
StartTime int64 `json:"startTime"`
|
||||||
Period int64 `json:"period"`
|
EndTime int64 `json:"endTime"`
|
||||||
|
Period int64 `json:"period"`
|
||||||
} `json:"parameters"`
|
} `json:"parameters"`
|
||||||
}{}
|
}{}
|
||||||
json.Unmarshal(req.Body, reqParam)
|
json.Unmarshal(req.Body, reqParam)
|
||||||
|
|
||||||
params := &cloudwatch.GetMetricStatisticsInput{
|
params := &cloudwatch.GetMetricStatisticsInput{
|
||||||
Namespace: aws.String(reqParam.Parameters.Namespace),
|
Namespace: aws.String(reqParam.Parameters.Namespace),
|
||||||
MetricName: aws.String(reqParam.Parameters.MetricName),
|
MetricName: aws.String(reqParam.Parameters.MetricName),
|
||||||
Dimensions: reqParam.Parameters.Dimensions,
|
Dimensions: reqParam.Parameters.Dimensions,
|
||||||
Statistics: reqParam.Parameters.Statistics,
|
Statistics: reqParam.Parameters.Statistics,
|
||||||
StartTime: aws.Time(time.Unix(reqParam.Parameters.StartTime, 0)),
|
ExtendedStatistics: reqParam.Parameters.ExtendedStatistics,
|
||||||
EndTime: aws.Time(time.Unix(reqParam.Parameters.EndTime, 0)),
|
StartTime: aws.Time(time.Unix(reqParam.Parameters.StartTime, 0)),
|
||||||
Period: aws.Int64(reqParam.Parameters.Period),
|
EndTime: aws.Time(time.Unix(reqParam.Parameters.EndTime, 0)),
|
||||||
|
Period: aws.Int64(reqParam.Parameters.Period),
|
||||||
|
}
|
||||||
|
if len(reqParam.Parameters.Statistics) != 0 {
|
||||||
|
params.Statistics = reqParam.Parameters.Statistics
|
||||||
|
}
|
||||||
|
if len(reqParam.Parameters.ExtendedStatistics) != 0 {
|
||||||
|
params.ExtendedStatistics = reqParam.Parameters.ExtendedStatistics
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := svc.GetMetricStatistics(params)
|
resp, err := svc.GetMetricStatistics(params)
|
||||||
@@ -292,11 +300,12 @@ func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
|
|||||||
|
|
||||||
reqParam := &struct {
|
reqParam := &struct {
|
||||||
Parameters struct {
|
Parameters struct {
|
||||||
Namespace string `json:"namespace"`
|
Namespace string `json:"namespace"`
|
||||||
MetricName string `json:"metricName"`
|
MetricName string `json:"metricName"`
|
||||||
Dimensions []*cloudwatch.Dimension `json:"dimensions"`
|
Dimensions []*cloudwatch.Dimension `json:"dimensions"`
|
||||||
Statistic string `json:"statistic"`
|
Statistic string `json:"statistic"`
|
||||||
Period int64 `json:"period"`
|
ExtendedStatistic string `json:"extendedStatistic"`
|
||||||
|
Period int64 `json:"period"`
|
||||||
} `json:"parameters"`
|
} `json:"parameters"`
|
||||||
}{}
|
}{}
|
||||||
json.Unmarshal(req.Body, reqParam)
|
json.Unmarshal(req.Body, reqParam)
|
||||||
@@ -312,6 +321,9 @@ func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
|
|||||||
if reqParam.Parameters.Statistic != "" {
|
if reqParam.Parameters.Statistic != "" {
|
||||||
params.Statistic = aws.String(reqParam.Parameters.Statistic)
|
params.Statistic = aws.String(reqParam.Parameters.Statistic)
|
||||||
}
|
}
|
||||||
|
if reqParam.Parameters.ExtendedStatistic != "" {
|
||||||
|
params.ExtendedStatistic = aws.String(reqParam.Parameters.ExtendedStatistic)
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := svc.DescribeAlarmsForMetric(params)
|
resp, err := svc.DescribeAlarmsForMetric(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -16,6 +16,13 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
|
|||||||
this.supportMetrics = true;
|
this.supportMetrics = true;
|
||||||
this.proxyUrl = instanceSettings.url;
|
this.proxyUrl = instanceSettings.url;
|
||||||
this.defaultRegion = instanceSettings.jsonData.defaultRegion;
|
this.defaultRegion = instanceSettings.jsonData.defaultRegion;
|
||||||
|
this.standardStatistics = [
|
||||||
|
'Average',
|
||||||
|
'Maximum',
|
||||||
|
'Minimum',
|
||||||
|
'Sum',
|
||||||
|
'SampleCount'
|
||||||
|
];
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
this.query = function(options) {
|
this.query = function(options) {
|
||||||
@@ -98,6 +105,8 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.performTimeSeriesQuery = function(query, start, end) {
|
this.performTimeSeriesQuery = function(query, start, end) {
|
||||||
|
var statistics = _.filter(query.statistics, function(s) { return _.includes(self.standardStatistics, s); });
|
||||||
|
var extendedStatistics = _.reject(query.statistics, function(s) { return _.includes(self.standardStatistics, s); });
|
||||||
return this.awsRequest({
|
return this.awsRequest({
|
||||||
region: query.region,
|
region: query.region,
|
||||||
action: 'GetMetricStatistics',
|
action: 'GetMetricStatistics',
|
||||||
@@ -105,7 +114,8 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
|
|||||||
namespace: query.namespace,
|
namespace: query.namespace,
|
||||||
metricName: query.metricName,
|
metricName: query.metricName,
|
||||||
dimensions: query.dimensions,
|
dimensions: query.dimensions,
|
||||||
statistics: query.statistics,
|
statistics: statistics,
|
||||||
|
extendedStatistics: extendedStatistics,
|
||||||
startTime: start,
|
startTime: start,
|
||||||
endTime: end,
|
endTime: end,
|
||||||
period: query.period
|
period: query.period
|
||||||
@@ -268,10 +278,19 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.performDescribeAlarmsForMetric = function(region, namespace, metricName, dimensions, statistic, period) {
|
this.performDescribeAlarmsForMetric = function(region, namespace, metricName, dimensions, statistic, period) {
|
||||||
|
var s = _.includes(self.standardStatistics, statistic) ? statistic : '';
|
||||||
|
var es = _.includes(self.standardStatistics, statistic) ? '' : statistic;
|
||||||
return this.awsRequest({
|
return this.awsRequest({
|
||||||
region: region,
|
region: region,
|
||||||
action: 'DescribeAlarmsForMetric',
|
action: 'DescribeAlarmsForMetric',
|
||||||
parameters: { namespace: namespace, metricName: metricName, dimensions: dimensions, statistic: statistic, period: period }
|
parameters: {
|
||||||
|
namespace: namespace,
|
||||||
|
metricName: metricName,
|
||||||
|
dimensions: dimensions,
|
||||||
|
statistic: s,
|
||||||
|
extendedStatistic: es,
|
||||||
|
period: period
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -338,6 +357,7 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
|
|||||||
var periodMs = options.period * 1000;
|
var periodMs = options.period * 1000;
|
||||||
|
|
||||||
return _.map(options.statistics, function(stat) {
|
return _.map(options.statistics, function(stat) {
|
||||||
|
var extended = !_.includes(self.standardStatistics, stat);
|
||||||
var dps = [];
|
var dps = [];
|
||||||
var lastTimestamp = null;
|
var lastTimestamp = null;
|
||||||
_.chain(md.Datapoints)
|
_.chain(md.Datapoints)
|
||||||
@@ -350,7 +370,11 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
|
|||||||
dps.push([null, lastTimestamp + periodMs]);
|
dps.push([null, lastTimestamp + periodMs]);
|
||||||
}
|
}
|
||||||
lastTimestamp = timestamp;
|
lastTimestamp = timestamp;
|
||||||
dps.push([dp[stat], timestamp]);
|
if (!extended) {
|
||||||
|
dps.push([dp[stat], timestamp]);
|
||||||
|
} else {
|
||||||
|
dps.push([dp.ExtendedStatistics[stat], timestamp]);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.value();
|
.value();
|
||||||
|
|
||||||
|
|||||||
@@ -61,14 +61,13 @@ function (angular, _) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.getStatSegments = function() {
|
$scope.getStatSegments = function() {
|
||||||
return $q.when([
|
return $q.when(_.flatten([
|
||||||
angular.copy($scope.removeStatSegment),
|
angular.copy($scope.removeStatSegment),
|
||||||
uiSegmentSrv.getSegmentForValue('Average'),
|
_.map($scope.datasource.standardStatistics, function(s) {
|
||||||
uiSegmentSrv.getSegmentForValue('Maximum'),
|
return uiSegmentSrv.getSegmentForValue(s);
|
||||||
uiSegmentSrv.getSegmentForValue('Minimum'),
|
}),
|
||||||
uiSegmentSrv.getSegmentForValue('Sum'),
|
uiSegmentSrv.getSegmentForValue('pNN.NN'),
|
||||||
uiSegmentSrv.getSegmentForValue('SampleCount'),
|
]));
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.statSegmentChanged = function(segment, index) {
|
$scope.statSegmentChanged = function(segment, index) {
|
||||||
|
|||||||
@@ -161,6 +161,67 @@ describe('CloudWatchDatasource', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('When performing CloudWatch query for extended statistics', function() {
|
||||||
|
var requestParams;
|
||||||
|
|
||||||
|
var query = {
|
||||||
|
range: { from: 'now-1h', to: 'now' },
|
||||||
|
targets: [
|
||||||
|
{
|
||||||
|
region: 'us-east-1',
|
||||||
|
namespace: 'AWS/ApplicationELB',
|
||||||
|
metricName: 'TargetResponseTime',
|
||||||
|
dimensions: {
|
||||||
|
LoadBalancer: 'lb',
|
||||||
|
TargetGroup: 'tg'
|
||||||
|
},
|
||||||
|
statistics: ['p90.00'],
|
||||||
|
period: 300
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = {
|
||||||
|
Datapoints: [
|
||||||
|
{
|
||||||
|
ExtendedStatistics: {
|
||||||
|
'p90.00': 1
|
||||||
|
},
|
||||||
|
Timestamp: 'Wed Dec 31 1969 16:00:00 GMT-0800 (PST)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedStatistics: {
|
||||||
|
'p90.00': 2
|
||||||
|
},
|
||||||
|
Timestamp: 'Wed Dec 31 1969 16:05:00 GMT-0800 (PST)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ExtendedStatistics: {
|
||||||
|
'p90.00': 5
|
||||||
|
},
|
||||||
|
Timestamp: 'Wed Dec 31 1969 16:15:00 GMT-0800 (PST)'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
Label: 'TargetResponseTime'
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
ctx.backendSrv.datasourceRequest = function(params) {
|
||||||
|
requestParams = params;
|
||||||
|
return ctx.$q.when({data: response});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return series list', function(done) {
|
||||||
|
ctx.ds.query(query).then(function(result) {
|
||||||
|
expect(result.data[0].target).to.be('TargetResponseTime_p90.00');
|
||||||
|
expect(result.data[0].datapoints[0][0]).to.be(response.Datapoints[0].ExtendedStatistics['p90.00']);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
ctx.$rootScope.$apply();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function describeMetricFindQuery(query, func) {
|
function describeMetricFindQuery(query, func) {
|
||||||
describe('metricFindQuery ' + query, () => {
|
describe('metricFindQuery ' + query, () => {
|
||||||
let scenario: any = {};
|
let scenario: any = {};
|
||||||
|
|||||||
Reference in New Issue
Block a user