Commit 9bb440bc by Torkel Ödegaard

Merge branch 'master' of github.com:grafana/grafana

parents 62269bb8 e73b82d5
...@@ -181,25 +181,33 @@ func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) { ...@@ -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) { ...@@ -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) { ...@@ -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 {
......
...@@ -52,6 +52,7 @@ func RenderToPng(params *RenderOpts) (string, error) { ...@@ -52,6 +52,7 @@ func RenderToPng(params *RenderOpts) (string, error) {
cmdArgs := []string{ cmdArgs := []string{
"--ignore-ssl-errors=true", "--ignore-ssl-errors=true",
"--web-security=false",
scriptPath, scriptPath,
"url=" + url, "url=" + url,
"width=" + params.Width, "width=" + params.Width,
......
...@@ -112,10 +112,18 @@ function (angular, _, kbn) { ...@@ -112,10 +112,18 @@ function (angular, _, kbn) {
this._grafanaVariables[name] = value; this._grafanaVariables[name] = value;
}; };
this.variableExists = function(expression) { this.getVariableName = function(expression) {
this._regex.lastIndex = 0; this._regex.lastIndex = 0;
var match = this._regex.exec(expression); var match = this._regex.exec(expression);
return match && (self._index[match[1] || match[2]] !== void 0); if (!match) {
return null;
}
return match[1] || match[2];
};
this.variableExists = function(expression) {
var name = this.getVariableName(expression);
return name && (self._index[name] !== void 0);
}; };
this.highlightVariablesAsHtml = function(str) { this.highlightVariablesAsHtml = function(str) {
......
...@@ -16,6 +16,13 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { ...@@ -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) {
...@@ -24,7 +31,7 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { ...@@ -24,7 +31,7 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
var queries = []; var queries = [];
options = angular.copy(options); options = angular.copy(options);
options.targets = this.expandTemplateVariable(options.targets, templateSrv); options.targets = this.expandTemplateVariable(options.targets, options.scopedVars, templateSrv);
_.each(options.targets, function(target) { _.each(options.targets, function(target) {
if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) { if (target.hide || !target.namespace || !target.metricName || _.isEmpty(target.statistics)) {
return; return;
...@@ -98,6 +105,8 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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) { ...@@ -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();
...@@ -388,12 +412,12 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) { ...@@ -388,12 +412,12 @@ function (angular, _, moment, dateMath, kbn, CloudWatchAnnotationQuery) {
return str.indexOf('$' + variableName) !== -1; return str.indexOf('$' + variableName) !== -1;
}; };
this.expandTemplateVariable = function(targets, templateSrv) { this.expandTemplateVariable = function(targets, scopedVars, templateSrv) {
var self = this; var self = this;
return _.chain(targets) return _.chain(targets)
.map(function(target) { .map(function(target) {
var dimensionKey = _.findKey(target.dimensions, function(v) { var dimensionKey = _.findKey(target.dimensions, function(v) {
return templateSrv.variableExists(v); return templateSrv.variableExists(v) && !_.has(scopedVars, templateSrv.getVariableName(v));
}); });
if (dimensionKey) { if (dimensionKey) {
......
...@@ -61,14 +61,13 @@ function (angular, _) { ...@@ -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) {
......
...@@ -139,6 +139,7 @@ describe('CloudWatchDatasource', function() { ...@@ -139,6 +139,7 @@ describe('CloudWatchDatasource', function() {
] ]
} }
], ],
getVariableName: function (e) { return 'instance_id'; },
variableExists: function (e) { return true; }, variableExists: function (e) { return true; },
containsVariable: function (str, variableName) { return str.indexOf('$' + variableName) !== -1; } containsVariable: function (str, variableName) { return str.indexOf('$' + variableName) !== -1; }
}; };
...@@ -156,11 +157,72 @@ describe('CloudWatchDatasource', function() { ...@@ -156,11 +157,72 @@ describe('CloudWatchDatasource', function() {
} }
]; ];
var result = ctx.ds.expandTemplateVariable(targets, templateSrv); var result = ctx.ds.expandTemplateVariable(targets, {}, templateSrv);
expect(result[0].dimensions.InstanceId).to.be('i-34567890'); expect(result[0].dimensions.InstanceId).to.be('i-34567890');
}); });
}); });
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 = {};
......
...@@ -185,6 +185,7 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { ...@@ -185,6 +185,7 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) {
// Series could have different timeSteps, // Series could have different timeSteps,
// let's find the smallest one so that bars are correctly rendered. // let's find the smallest one so that bars are correctly rendered.
// In addition, only take series which are rendered as bars for this.
function getMinTimeStepOfSeries(data) { function getMinTimeStepOfSeries(data) {
var min = Number.MAX_VALUE; var min = Number.MAX_VALUE;
...@@ -192,6 +193,15 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { ...@@ -192,6 +193,15 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) {
if (!data[i].stats.timeStep) { if (!data[i].stats.timeStep) {
continue; continue;
} }
if (panel.bars) {
if (data[i].bars && data[i].bars.show === false) {
continue;
}
} else {
if (typeof data[i].bars === 'undefined' || typeof data[i].bars.show === 'undefined' || !data[i].bars.show) {
continue;
}
}
if (data[i].stats.timeStep < min) { if (data[i].stats.timeStep < min) {
min = data[i].stats.timeStep; min = data[i].stats.timeStep;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment