Browse Source

Merge branch 'master' into external-plugins

Torkel Ödegaard 10 years ago
parent
commit
63b50ab9b1

+ 2 - 2
docs/sources/installation/performance.md

@@ -8,7 +8,7 @@ page_keywords: grafana, performance, documentation
 
 
 ## Graphite
 ## Graphite
 
 
-Graphite 0.9.13 adds a much needed feature to the JSON rendering API
+Graphite 0.9.14 adds a much needed feature to the JSON rendering API
 that is very important for Grafana. If you are experiencing slow load &
 that is very important for Grafana. If you are experiencing slow load &
 rendering times for large time ranges then it is most likely caused by
 rendering times for large time ranges then it is most likely caused by
 running Graphite 0.9.12 or lower.
 running Graphite 0.9.12 or lower.
@@ -17,6 +17,6 @@ The latest version of Graphite adds a `maxDataPoints` parameter to the
 JSON render API. Without this feature Graphite can return hundreds of
 JSON render API. Without this feature Graphite can return hundreds of
 thousands of data points per graph, which can hang your browser. Be sure
 thousands of data points per graph, which can hang your browser. Be sure
 to upgrade to
 to upgrade to
-[0.9.13](http://graphite.readthedocs.org/en/latest/releases/0_9_13.html).
+[0.9.14](http://graphite.readthedocs.org/en/latest/releases/0_9_14.html).
 
 
 
 

+ 3 - 1
public/app/core/time_series.ts

@@ -101,6 +101,7 @@ class TimeSeries {
     var nullAsZero = fillStyle === 'null as zero';
     var nullAsZero = fillStyle === 'null as zero';
     var currentTime;
     var currentTime;
     var currentValue;
     var currentValue;
+    var nonNulls = 0;
 
 
     for (var i = 0; i < this.datapoints.length; i++) {
     for (var i = 0; i < this.datapoints.length; i++) {
       currentValue = this.datapoints[i][0];
       currentValue = this.datapoints[i][0];
@@ -117,6 +118,7 @@ class TimeSeries {
         if (_.isNumber(currentValue)) {
         if (_.isNumber(currentValue)) {
           this.stats.total += currentValue;
           this.stats.total += currentValue;
           this.allIsNull = false;
           this.allIsNull = false;
+          nonNulls++;
         }
         }
 
 
         if (currentValue > this.stats.max) {
         if (currentValue > this.stats.max) {
@@ -139,7 +141,7 @@ class TimeSeries {
     if (this.stats.min === Number.MAX_VALUE) { this.stats.min = null; }
     if (this.stats.min === Number.MAX_VALUE) { this.stats.min = null; }
 
 
     if (result.length) {
     if (result.length) {
-      this.stats.avg = (this.stats.total / result.length);
+      this.stats.avg = (this.stats.total / nonNulls);
       this.stats.current = result[result.length-1][1];
       this.stats.current = result[result.length-1][1];
       if (this.stats.current === null && result.length > 1) {
       if (this.stats.current === null && result.length > 1) {
         this.stats.current = result[result.length-2][1];
         this.stats.current = result[result.length-2][1];

+ 7 - 0
public/app/features/templating/editorCtrl.js

@@ -96,6 +96,13 @@ function (angular, _) {
       }
       }
     };
     };
 
 
+    $scope.duplicate = function(variable) {
+      $scope.current = angular.copy(variable);
+      $scope.variables.push($scope.current);
+      $scope.current.name = 'copy_of_'+variable.name;
+      $scope.updateSubmenuVisibility();
+    };
+
     $scope.update = function() {
     $scope.update = function() {
       if ($scope.isValid()) {
       if ($scope.isValid()) {
         $scope.runQuery().then(function() {
         $scope.runQuery().then(function() {

+ 6 - 1
public/app/features/templating/partials/editor.html

@@ -39,7 +39,7 @@
 		<div ng-if="mode === 'list'">
 		<div ng-if="mode === 'list'">
 
 
 			<div class="editor-row row">
 			<div class="editor-row row">
-				<div class="span8">
+				<div style="max-width: 1024px">
 					<div ng-if="variables.length === 0">
 					<div ng-if="variables.length === 0">
 						<em>No template variables defined</em>
 						<em>No template variables defined</em>
 					</div>
 					</div>
@@ -59,6 +59,11 @@
 									Edit
 									Edit
 								</a>
 								</a>
 							</td>
 							</td>
+              <td style="width: 1%">
+                <a ng-click="duplicate(variable)" class="btn btn-inverse btn-small">
+                  Duplicate
+                </a>
+              </td>
 							<td style="width: 1%"><i ng-click="_.move(variables,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
 							<td style="width: 1%"><i ng-click="_.move(variables,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
 							<td style="width: 1%"><i ng-click="_.move(variables,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
 							<td style="width: 1%"><i ng-click="_.move(variables,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
 							<td style="width: 1%">
 							<td style="width: 1%">

+ 1 - 1
public/app/plugins/datasource/cloudwatch/datasource.js

@@ -263,7 +263,7 @@ function (angular, _) {
         })
         })
         .each(function(dp) {
         .each(function(dp) {
           var timestamp = new Date(dp.Timestamp).getTime();
           var timestamp = new Date(dp.Timestamp).getTime();
-          if (lastTimestamp && (timestamp - lastTimestamp) > periodMs * 2) {
+          if (lastTimestamp && (timestamp - lastTimestamp) > periodMs) {
             dps.push([null, lastTimestamp + periodMs]);
             dps.push([null, lastTimestamp + periodMs]);
           }
           }
           lastTimestamp = timestamp;
           lastTimestamp = timestamp;

+ 1 - 1
public/app/plugins/datasource/cloudwatch/specs/datasource_specs.ts

@@ -55,7 +55,7 @@ describe('CloudWatchDatasource', function() {
         },
         },
         {
         {
           Average: 5,
           Average: 5,
-          Timestamp: 'Wed Dec 31 1969 16:20:00 GMT-0800 (PST)'
+          Timestamp: 'Wed Dec 31 1969 16:15:00 GMT-0800 (PST)'
         }
         }
       ],
       ],
       Label: 'CPUUtilization'
       Label: 'CPUUtilization'

+ 2 - 1
public/app/plugins/datasource/elasticsearch/query_builder.js

@@ -10,7 +10,7 @@ function (angular) {
 
 
   ElasticQueryBuilder.prototype.getRangeFilter = function() {
   ElasticQueryBuilder.prototype.getRangeFilter = function() {
     var filter = {};
     var filter = {};
-    filter[this.timeField] = {"gte": "$timeFrom", "lte": "$timeTo"};
+    filter[this.timeField] = {"gte": "$timeFrom", "lte": "$timeTo", "format": "epoch_millis"};
     return filter;
     return filter;
   };
   };
 
 
@@ -127,6 +127,7 @@ function (angular) {
             "interval": this.getInterval(aggDef),
             "interval": this.getInterval(aggDef),
             "field": this.timeField,
             "field": this.timeField,
             "min_doc_count": 0,
             "min_doc_count": 0,
+            "format": "epoch_millis",
             "extended_bounds": { "min": "$timeFrom", "max": "$timeTo" }
             "extended_bounds": { "min": "$timeFrom", "max": "$timeTo" }
           };
           };
           break;
           break;

+ 24 - 15
public/app/plugins/datasource/prometheus/datasource.js

@@ -48,6 +48,7 @@ function (angular, _, moment, dateMath) {
       var end = getPrometheusTime(options.range.to, true);
       var end = getPrometheusTime(options.range.to, true);
 
 
       var queries = [];
       var queries = [];
+      options = _.clone(options);
       _.each(options.targets, _.bind(function(target) {
       _.each(options.targets, _.bind(function(target) {
         if (!target.expr || target.hide) {
         if (!target.expr || target.hide) {
           return;
           return;
@@ -58,7 +59,13 @@ function (angular, _, moment, dateMath) {
 
 
         var interval = target.interval || options.interval;
         var interval = target.interval || options.interval;
         var intervalFactor = target.intervalFactor || 1;
         var intervalFactor = target.intervalFactor || 1;
-        query.step = this.calculateInterval(interval, intervalFactor);
+        target.step = query.step = this.calculateInterval(interval, intervalFactor);
+        var range = Math.ceil(end - start);
+        // Prometheus drop query if range/step > 11000
+        // calibrate step if it is too big
+        if (query.step !== 0 && range / query.step > 11000) {
+          target.step = query.step = Math.ceil(range / 11000);
+        }
 
 
         queries.push(query);
         queries.push(query);
       }, this));
       }, this));
@@ -96,17 +103,7 @@ function (angular, _, moment, dateMath) {
     };
     };
 
 
     PrometheusDatasource.prototype.performTimeSeriesQuery = function(query, start, end) {
     PrometheusDatasource.prototype.performTimeSeriesQuery = function(query, start, end) {
-      var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end;
-
-      var step = query.step;
-      var range = Math.ceil(end - start);
-      // Prometheus drop query if range/step > 11000
-      // calibrate step if it is too big
-      if (step !== 0 && range / step > 11000) {
-        step = Math.ceil(range / 11000);
-      }
-      url += '&step=' + step;
-
+      var url = '/api/v1/query_range?query=' + encodeURIComponent(query.expr) + '&start=' + start + '&end=' + end + '&step=' + query.step;
       return this._request('GET', url);
       return this._request('GET', url);
     };
     };
 
 
@@ -212,7 +209,7 @@ function (angular, _, moment, dateMath) {
         sec = 1;
         sec = 1;
       }
       }
 
 
-      return Math.ceil(sec * intervalFactor) + 's';
+      return Math.ceil(sec * intervalFactor);
     };
     };
 
 
     function transformMetricData(md, options) {
     function transformMetricData(md, options) {
@@ -221,8 +218,20 @@ function (angular, _, moment, dateMath) {
 
 
       metricLabel = createMetricLabel(md.metric, options);
       metricLabel = createMetricLabel(md.metric, options);
 
 
-      dps = _.map(md.values, function(value) {
-        return [parseFloat(value[1]), value[0] * 1000];
+      var stepMs = parseInt(options.step) * 1000;
+      var lastTimestamp = null;
+      _.each(md.values, function(value) {
+        var dp_value = parseFloat(value[1]);
+        if (_.isNaN(dp_value)) {
+          dp_value = null;
+        }
+
+        var timestamp = value[0] * 1000;
+        if (lastTimestamp && (timestamp - lastTimestamp) > stepMs) {
+          dps.push([null, lastTimestamp + stepMs]);
+        }
+        lastTimestamp = timestamp;
+        dps.push([dp_value, timestamp]);
       });
       });
 
 
       return { target: metricLabel, datapoints: dps };
       return { target: metricLabel, datapoints: dps };

+ 1 - 1
public/app/plugins/datasource/prometheus/specs/datasource_specs.ts

@@ -19,7 +19,7 @@ describe('PrometheusDatasource', function() {
     var results;
     var results;
     var urlExpected = 'proxied/api/v1/query_range?query=' +
     var urlExpected = 'proxied/api/v1/query_range?query=' +
                       encodeURIComponent('test{job="testjob"}') +
                       encodeURIComponent('test{job="testjob"}') +
-                      '&start=1443438675&end=1443460275&step=60s';
+                      '&start=1443438675&end=1443460275&step=60';
     var query = {
     var query = {
       range: { from: moment(1443438674760), to: moment(1443460274760) },
       range: { from: moment(1443438674760), to: moment(1443460274760) },
       targets: [{ expr: 'test{job="testjob"}' }],
       targets: [{ expr: 'test{job="testjob"}' }],

+ 11 - 0
public/test/core/time_series_specs.js

@@ -43,6 +43,17 @@ define([
         expect(series.stats.max).to.be(-4);
         expect(series.stats.max).to.be(-4);
       });
       });
 
 
+      it('average value should ignore nulls', function() {
+        series = new TimeSeries(testData);
+        series.getFlotPairs('null', yAxisFormats);
+        expect(series.stats.avg).to.be(6.333333333333333);
+      });
+
+      it('with null as zero style, average value should treat nulls as 0', function() {
+        series = new TimeSeries(testData);
+        series.getFlotPairs('null as zero', yAxisFormats);
+        expect(series.stats.avg).to.be(4.75);
+      });
     });
     });
 
 
     describe('series overrides', function() {
     describe('series overrides', function() {