Browse Source

more work on influxdb datasource, query editor, and refactoring

Torkel Ödegaard 12 years ago
parent
commit
50fd5512d6

+ 5 - 2
src/app/components/settings.js

@@ -52,14 +52,17 @@ function (_, crypto) {
     if (options.graphiteUrl) {
       settings.datasources = {
         graphite: {
-          name: 'default',
+          type: 'graphite',
           url: options.graphiteUrl,
           default: true
         }
       };
     }
 
-    _.map(settings.datasources, parseBasicAuth);
+    _.each(settings.datasources, function(datasource, key) {
+      datasource.name = key;
+      parseBasicAuth(datasource);
+    });
 
     var elasticParsed = parseBasicAuth({ url: settings.elasticsearch });
     settings.elasticsearchBasicAuth = elasticParsed.basicAuth;

+ 0 - 10
src/app/panels/graphite/module.html

@@ -27,16 +27,6 @@
 
     <div class="tab-content" ng-repeat="tab in panelMeta.fullEditorTabs" ng-show="editorTabs[editor.index] == tab.title">
       <div ng-include src="tab.src"></div>
-
-      <div class="editor-row" ng-show="editor.index === 0">
-        <div class="section">
-          <h5>Datasource options</h5>
-          <div class="editor-option">
-            <label class="small">Datasource name</label>
-            <select class="input-large" ng-options="obj.value as obj.name for obj in datasources" ng-model="panel.datasource" ng-change="datasourceChanged()"></select>
-          </div>
-        </div>
-      </div>
     </div>
   </div>
 </div>

+ 7 - 4
src/app/panels/graphite/module.js

@@ -46,6 +46,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
         },
         {
           title: 'Metrics',
+          src:'app/partials/metrics.html'
         },
         {
           title:'Axes & Grid',
@@ -206,12 +207,12 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
       $scope.hiddenSeries = {};
 
       $scope.datasources = datasourceSrv.listOptions();
-      $scope.datasourceChanged();
+      $scope.setDatasource($scope.panel.datasource);
     };
 
-    $scope.datasourceChanged = function() {
-      $scope.datasource = datasourceSrv.get($scope.panel.datasource);
-      $scope.panelMeta.fullEditorTabs[1].src = $scope.datasource.editorSrc;
+    $scope.setDatasource = function(datasource) {
+      $scope.panel.datasource = datasource;
+      $scope.datasource = datasourceSrv.get(datasource);
       $scope.get_data();
     };
 
@@ -299,6 +300,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
         yaxis: yaxis
       };
 
+      $scope.legend.push(seriesInfo);
+
       var series = new timeSeries.ZeroFilled({
         datapoints: datapoints,
         info: seriesInfo,

+ 1 - 4
src/app/partials/graphite/editor.html

@@ -1,5 +1,5 @@
 
-<div class="editor-row">
+<div class="editor-row" style="margin-top: 10px;">
 
 	<div  ng-repeat="target in panel.targets"
         class="grafana-target"
@@ -112,6 +112,3 @@
   </div>
 </div>
 
-<div class="editor-row" style="margin-top: 20px" ng-show="editor.index == 1">
-  <button class="btn btn-success pull-right" ng-click="add_target(panel.target)">Add target</button>
-</div>

+ 21 - 20
src/app/partials/influxdb/editor.html

@@ -1,6 +1,5 @@
-<h5>InfluxDB queries<h5>
 
-<div class="editor-row">
+<div class="editor-row" style="margin-top: 10px;">
 
   <div  ng-repeat="target in panel.targets"
         class="grafana-target"
@@ -44,10 +43,8 @@
         </ul>
 
         <ul class="grafana-segment-list" role="menu">
-          <li>
-            <a class="grafana-target-segment">
-              from series
-            </a>
+          <li class="grafana-target-segment">
+            from series
           </li>
           <li>
             <input type="text"
@@ -55,12 +52,10 @@
                    ng-model="target.series"
                    spellcheck='false'
                    placeholder="series name"
-                   ng-model-onblur ng-change="targetTextChanged()" >
+                   ng-model-onblur ng-change="get_data()" >
           </li>
-          <li>
-            <a class="grafana-target-segment">
-              select
-            </a>
+          <li class="grafana-target-segment">
+            select
           </li>
           <li>
             <input type="text"
@@ -68,25 +63,31 @@
                    ng-model="target.column"
                    placeholder="value column"
                    spellcheck='false'
-                   ng-model-onblur ng-change="targetTextChanged()" >
+                   ng-model-onblur ng-change="get_data()" >
+          </li>
+          <li class="grafana-target-segment">
+            function
           </li>
           <li>
-            <a class="grafana-target-segment">
-              function
-            </a>
+            <select class="input-medium grafana-target-segment-input"  ng-change="get_data()" ng-model="target.function" ng-options="f for f in ['mean', 'sum', 'min', 'max', 'median', 'derivative', 'stddev']" ></select>
+          </li>
+          <li class="grafana-target-segment">
+            group by time
           </li>
           <li>
-            <select class="input-small grafana-target-segment-input" ng-model="target.function" ng-options="f for f in ['mean', 'sum']" ></select>
+            <input type="text"
+                   class="input-mini grafana-target-segment-input"
+                   ng-model="target.interval"
+                   placeholder="{{interval}}"
+                   bs-tooltip="'Leave blank for auto handling based on time range and panel width'"
+                   spellcheck='false'
+                   ng-model-onblur ng-change="get_data()" >
           </li>
         </ul>
 
-
         <div class="clearfix"></div>
       </div>
     </div>
   </div>
 </div>
 
-<div class="editor-row" style="margin-top: 20px" ng-show="editor.index == 1">
-  <button class="btn btn-success pull-right" ng-click="add_target(panel.target)">Add query</button>
-</div>

+ 17 - 0
src/app/partials/metrics.html

@@ -0,0 +1,17 @@
+<div ng-include src="datasource.editorSrc"></div>
+
+
+<div class="editor-row" style="margin-top: 20px">
+  <button class="btn btn-success pull-right" ng-click="add_target(panel.target)">Add query</button>
+
+  <div class="btn-group pull-right" style="margin-right: 10px;">
+    <button class="btn btn-info dropdown-toggle" data-toggle="dropdown">DS {{datasource.name}} <span class="caret"></span></button>
+
+    <ul class="dropdown-menu" role="menu">
+      <li ng-repeat="datasource in datasources" role="menuitem">
+        <a ng-click="setDatasource(datasource.value);">{{datasource.name}}</a>
+      </li>
+    </ul>
+ </div>
+
+</div>

+ 1 - 0
src/app/services/graphite/graphiteDatasource.js

@@ -18,6 +18,7 @@ function (angular, _, $, config, kbn, moment) {
       this.basicAuth = datasource.basicAuth;
       this.url = datasource.url;
       this.editorSrc = 'app/partials/graphite/editor.html';
+      this.name = datasource.name;
     }
 
     GraphiteDatasource.prototype.query = function(options) {

+ 69 - 49
src/app/services/influxdb/influxdbDatasource.js

@@ -1,8 +1,9 @@
 define([
   'angular',
   'underscore',
+  'kbn'
 ],
-function (angular, _) {
+function (angular, _, kbn) {
   'use strict';
 
   var module = angular.module('kibana.services');
@@ -15,6 +16,7 @@ function (angular, _) {
       this.url = datasource.url;
       this.username = datasource.username;
       this.password = datasource.password;
+      this.name = datasource.name;
 
       this.templateSettings = {
         interpolate : /\[\[([\s\S]+?)\]\]/g,
@@ -22,49 +24,32 @@ function (angular, _) {
     }
 
     InfluxDatasource.prototype.query = function(options) {
-      var target = options.targets[0];
-
-      var template = "select [[func]]([[column]]) from [[series]] where [[timeFilter]] group by time([[interval]])";
-      var templateData = {
-        series: target.series,
-        column: target.column,
-        func: target.function,
-        timeFilter: getTimeFilter(options),
-        interval: options.interval
-      };
-
-      var query = _.template(template, templateData, this.templateSettings);
-      console.log(query);
-
-      var output = { data: [] };
 
-      return this.doInfluxRequest(query).then(function(results) {
+      var promises = _.map(options.targets, function(target) {
+        if (!target.series || !target.column || target.hide) {
+          return [];
+        }
 
-        _.each(results.data, function(series) {
-          var timeCol = series.columns.indexOf('time');
+        var template = "select [[func]]([[column]]) from [[series]] where [[timeFilter]] group by time([[interval]]) order asc";
 
-          _.each(series.columns, function(column, index) {
-            if (column === "time" || column === "sequence_number") {
-              return;
-            }
+        var templateData = {
+          series: target.series,
+          column: target.column,
+          func: target.function,
+          timeFilter: getTimeFilter(options),
+          interval: target.interval || options.interval
+        };
 
-            console.log("series:"+series.name + ": "+series.points.length + " points");
+        var query = _.template(template, templateData, this.templateSettings);
+        console.log(query);
 
-            var target = series.name + "." + column;
-            var datapoints = [];
+        return this.doInfluxRequest(query).then(handleInfluxQueryResponse);
 
-            var i, y;
-            for(i = series.points.length - 1, y = 0; i >= 0; i--, y++) {
-              var t = Math.floor(series.points[i][timeCol] / 1000);
-              var v = series.points[i][index];
-              datapoints[y] = [v,t];
-            }
+      }, this);
 
-            output.data.push({ target:target, datapoints:datapoints });
-          });
-        });
+      return $q.all(promises).then(function(results) {
 
-        return output;
+        return { data: _.flatten(results) };
       });
 
     };
@@ -85,24 +70,59 @@ function (angular, _) {
       return $http(options);
     };
 
+    function handleInfluxQueryResponse(results) {
+      var output = [];
+
+      _.each(results.data, function(series) {
+        var timeCol = series.columns.indexOf('time');
+
+        _.each(series.columns, function(column, index) {
+          if (column === "time" || column === "sequence_number") {
+            return;
+          }
+
+          console.log("series:"+series.name + ": "+series.points.length + " points");
+
+          var target = series.name + "." + column;
+          var datapoints = [];
+
+          for(var i = 0; i < series.points.length; i++) {
+            var t = Math.floor(series.points[i][timeCol] / 1000);
+            var v = series.points[i][index];
+            datapoints[i] = [v,t];
+          }
+
+          output.push({ target:target, datapoints:datapoints });
+        });
+      });
+
+      return output;
+    }
+
     function getTimeFilter(options) {
-      var from = options.range.from;
-      var until = options.range.to;
+      var from = getInfluxTime(options.range.from);
+      var until = getInfluxTime(options.range.to);
 
-      if (_.isString(from)) {
-        return 'time > now() - ' + from.substring(4);
-      }
-      else {
-        from = to_utc_epoch_seconds(from);
+      if (until === 'now()') {
+        return 'time > now() - ' + from;
       }
 
-      if (until === 'now') {
-        return 'time > ' + from;
-      }
-      else {
-        until = to_utc_epoch_seconds(until);
-        return 'time > ' + from + ' and time < ' + until;
+      return 'time > ' + from + ' and time < ' + until;
+    }
+
+    function getInfluxTime(date) {
+      if (_.isString(date)) {
+        if (date === 'now') {
+          return 'now()';
+        }
+        else if (date.indexOf('now') >= 0) {
+          return date.substring(4);
+        }
+
+        date = kbn.parseDate(date);
       }
+
+      return to_utc_epoch_seconds(date);
     }
 
     function to_utc_epoch_seconds(date) {