Просмотр исходного кода

Closes #35, grafana now supports multiple graphite backends. Check config.sample for how to setup. In the general tab of the graphite panel you can change datasource

Torkel Ödegaard 12 лет назад
Родитель
Сommit
36f56f3695

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

@@ -14,7 +14,12 @@ function (_, crypto) {
      */
     var defaults = {
       elasticsearch                 : "http://"+window.location.hostname+":9200",
-      graphiteUrl                   : "http://"+window.location.hostname+":8080",
+      datasources                   : {
+        default: {
+          url: "http://"+window.location.hostname+":8080",
+          default: true
+        }
+      },
       panel_names                   : [],
       default_route                 : '/dashboard/file/default.json',
       grafana_index                 : 'grafana-dash',
@@ -40,7 +45,22 @@ function (_, crypto) {
       }
     };
 
-    settings.graphiteBasicAuth = basicAuth(settings.graphiteUrl);
+    if (options.graphiteUrl) {
+      settings.datasources = {
+        graphite: {
+          name: 'default',
+          url: options.graphiteUrl,
+          default: true,
+          basicAuth: basicAuth(options.graphiteUrl)
+        }
+      };
+    }
+    else {
+      _.each(_.values(settings.datasources), function(source) {
+        source.basicAuth = basicAuth(source.url);
+      });
+    }
+
     settings.elasticsearchBasicAuth = basicAuth(settings.elasticsearch);
     return settings;
   };

+ 3 - 3
src/app/controllers/graphiteImport.js

@@ -8,7 +8,7 @@ function (angular, app, _) {
 
   var module = angular.module('kibana.controllers');
 
-  module.controller('GraphiteImportCtrl', function($scope, $rootScope, $timeout, graphiteSrv, dashboard) {
+  module.controller('GraphiteImportCtrl', function($scope, $rootScope, $timeout, datasourceSrv, dashboard) {
 
     $scope.init = function() {
       console.log('hej!');
@@ -17,7 +17,7 @@ function (angular, app, _) {
     $scope.listAll = function(query) {
       delete $scope.error;
 
-      graphiteSrv.listDashboards(query)
+      datasourceSrv.default.listDashboards(query)
         .then(function(results) {
           $scope.dashboards = results;
         })
@@ -29,7 +29,7 @@ function (angular, app, _) {
     $scope.import = function(dashName) {
       delete $scope.error;
 
-      graphiteSrv.loadDashboard(dashName)
+      datasourceSrv.default.loadDashboard(dashName)
         .then(function(results) {
           if (!results.data || !results.data.state) {
             throw { message: 'no dashboard state received from graphite' };

+ 3 - 3
src/app/controllers/graphiteTarget.js

@@ -10,7 +10,7 @@ function (angular, _, config, gfunc, Parser) {
 
   var module = angular.module('kibana.controllers');
 
-  module.controller('GraphiteTargetCtrl', function($scope, $http, filterSrv, graphiteSrv) {
+  module.controller('GraphiteTargetCtrl', function($scope, $http, filterSrv) {
 
     $scope.init = function() {
       $scope.funcCategories = gfunc.getCategories();
@@ -121,7 +121,7 @@ function (angular, _, config, gfunc, Parser) {
       }
 
       var path = getSegmentPathUpTo(fromIndex + 1);
-      return graphiteSrv.metricFindQuery(path)
+      return $scope.datasource.metricFindQuery(path)
         .then(function(segments) {
           if (segments.length === 0) {
             $scope.segments = $scope.segments.splice(0, fromIndex);
@@ -158,7 +158,7 @@ function (angular, _, config, gfunc, Parser) {
       var query = index === 0 ?
         '*' : getSegmentPathUpTo(index) + '.*';
 
-      return graphiteSrv.metricFindQuery(query)
+      return $scope.datasource.metricFindQuery(query)
         .then(function(segments) {
           _.each(segments, function(segment) {
             segment.html = segment.val = segment.text;

+ 2 - 2
src/app/panels/filtering/module.js

@@ -14,7 +14,7 @@ function (angular, app, _) {
   var module = angular.module('kibana.panels.filtering', []);
   app.useModule(module);
 
-  module.controller('filtering', function($scope, filterSrv, graphiteSrv, $rootScope, dashboard) {
+  module.controller('filtering', function($scope, filterSrv, datasourceSrv, $rootScope, dashboard) {
 
     $scope.panelMeta = {
       status  : "Stable",
@@ -35,7 +35,7 @@ function (angular, app, _) {
     };
 
     $scope.applyFilter = function(filter) {
-      graphiteSrv.metricFindQuery(filter.query)
+      datasourceSrv.default.metricFindQuery(filter.query)
         .then(function (results) {
           filter.editing=undefined;
           filter.options = _.map(results, function(node) {

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

@@ -27,10 +27,20 @@
 
       <div class="tab-content" ng-show="editorTabs[editor.index] == 'General'">
         <div ng-include src="'app/partials/panelgeneral.html'"></div>
+
+        <div class="editor-row" ng-show="datasources.length > 0">
+          <div class="section">
+            <div class="editor-option">
+              <label class="small">Datasource</label>
+              <select class="input-large" ng-options="obj.value as obj.name for obj in datasources" ng-model="panel.datasource" ng-change="datasourceChanged()" />
+          </div>
+          </div>
+        </div>
       </div>
 
       <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>
+
   </div>
 </div>

+ 16 - 3
src/app/panels/graphite/module.js

@@ -34,7 +34,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
   var module = angular.module('kibana.panels.graphite', []);
   app.useModule(module);
 
-  module.controller('graphite', function($scope, $rootScope, filterSrv, graphiteSrv, $timeout, annotationsSrv) {
+  module.controller('graphite', function($scope, $rootScope, filterSrv, datasourceSrv, $timeout, annotationsSrv) {
 
     $scope.panelMeta = {
       modals : [],
@@ -82,6 +82,9 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
 
     // Set and populate defaults
     var _d = {
+
+      datasource: null,
+
       /** @scratch /panels/histogram/3
        * renderer:: sets client side (flot) or native graphite png renderer (png)
        */
@@ -220,6 +223,10 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
       $scope.editor = {index: 1};
       $scope.editorTabs = _.union(['General'],_.pluck($scope.panelMeta.fullEditorTabs,'title'));
       $scope.hiddenSeries = {};
+
+      $scope.datasources = datasourceSrv.listOptions();
+      $scope.datasource = datasourceSrv.get($scope.panel.datasource);
+
       // Always show the query if an alias isn't set. Users can set an alias if the query is too
       // long
       $scope.panel.tooltip.query_as_alias = true;
@@ -227,6 +234,11 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
       $scope.get_data();
     };
 
+    $scope.datasourceChanged = function() {
+      $scope.datasource = datasourceSrv.get($scope.panel.datasource);
+      $scope.get_data();
+    };
+
     $scope.remove_panel_from_row = function(row, panel) {
       if ($scope.fullscreen) {
         $rootScope.$emit('panel-fullscreen-exit');
@@ -284,12 +296,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
         range: $scope.rangeUnparsed,
         targets: $scope.panel.targets,
         format: $scope.panel.renderer === 'png' ? 'png' : 'json',
-        maxDataPoints: $scope.panel.span * 50
+        maxDataPoints: $scope.panel.span * 50,
+        datasource: $scope.panel.datasource
       };
 
       $scope.annotationsPromise = annotationsSrv.getAnnotations($scope.rangeUnparsed);
 
-      return graphiteSrv.query(graphiteQuery)
+      return $scope.datasource.query(graphiteQuery)
         .then($scope.receiveGraphiteData)
         .then(null, function(err) {
           $scope.panel.error = err.message || "Graphite HTTP Request Error";

+ 1 - 1
src/app/services/all.js

@@ -4,7 +4,7 @@ define([
   './filterSrv',
   './timer',
   './panelMove',
-  './graphite/graphiteSrv',
+  './datasourceSrv',
   './keyboardManager',
   './annotationsSrv',
 ],

+ 2 - 2
src/app/services/annotationsSrv.js

@@ -7,7 +7,7 @@ define([
 
   var module = angular.module('kibana.services');
 
-  module.service('annotationsSrv', function(dashboard, graphiteSrv, $q, alertSrv) {
+  module.service('annotationsSrv', function(dashboard, datasourceSrv, $q, alertSrv) {
 
     this.init = function() {
       this.annotationList = [
@@ -43,7 +43,7 @@ define([
         maxDataPoints: 100
       };
 
-      return graphiteSrv.query(graphiteQuery)
+      return datasourceSrv.default.query(graphiteQuery)
         .then(function(results) {
           return _.reduce(results.data, function(list, target) {
             _.each(target.datapoints, function (values) {

+ 0 - 1
src/app/services/dashboard.js

@@ -160,7 +160,6 @@ function (angular, $, kbn, _, config, moment, Modernizr) {
       $timeout(function() {
         // Ok, now that we've setup the current dashboard, we can inject our services
         filterSrv = $injector.get('filterSrv');
-        graphiteSrv = $injector.get('graphiteSrv');
         filterSrv.init();
 
       },0).then(function() {

+ 34 - 0
src/app/services/datasourceSrv.js

@@ -0,0 +1,34 @@
+define([
+  'angular',
+  'underscore',
+  'config',
+  './graphite/graphiteDatasource'
+],
+function (angular, _, config, GraphiteDatasource) {
+  'use strict';
+
+  var module = angular.module('kibana.services');
+
+  module.service('datasourceSrv', function($q, filterSrv, $http) {
+    var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true } );
+
+    this.default = new GraphiteDatasource(defaultDatasource, $q, filterSrv, $http);
+
+    this.get = function(name) {
+      if (!name) {
+        return this.default;
+      }
+
+      return new GraphiteDatasource(config.datasources[name], $q, filterSrv, $http);
+    };
+
+    this.listOptions = function() {
+      return _.map(config.datasources, function(value, key) {
+        return {
+          name: value.default ? key + ' (default)' : key,
+          value: value.default ? null : key
+        };
+      });
+    };
+  });
+});

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

@@ -0,0 +1,150 @@
+define([
+  'angular',
+  'underscore',
+  'jquery',
+  'config',
+  'kbn',
+  'moment'
+],
+function (angular, _, $, config, kbn, moment) {
+  'use strict';
+
+  function GraphiteDatasource(datasource, $q, filterSrv, $http) {
+    this.url = datasource.url;
+    this.type = 'graphite';
+    this.basicAuth = datasource.basicAuth;
+    this.$q = $q;
+    this.filterSrv = filterSrv;
+    this.$http = $http;
+  };
+
+  GraphiteDatasource.prototype.query = function(options) {
+    try {
+      var graphOptions = {
+        from: this.translateTime(options.range.from),
+        until: this.translateTime(options.range.to),
+        targets: options.targets,
+        format: options.format,
+        maxDataPoints: options.maxDataPoints,
+      };
+
+      var params = this.buildGraphiteParams(graphOptions);
+
+      if (options.format === 'png') {
+        return $q.when(graphiteRenderUrl + '?' + params.join('&'));
+      }
+
+      return this.doGraphiteRequest({
+        method: 'POST',
+        url: '/render',
+        datasource: options.datasource,
+        data: params.join('&'),
+        headers: {
+          'Content-Type': 'application/x-www-form-urlencoded',
+        }
+      });
+    }
+    catch(err) {
+      return this.$q.reject(err);
+    }
+  };
+
+  GraphiteDatasource.prototype.translateTime = function(date) {
+    if (_.isString(date)) {
+      if (date === 'now') {
+        return 'now';
+      }
+      else if (date.indexOf('now') >= 0) {
+        date = date.substring(3);
+        date = date.replace('m', 'min');
+        date = date.replace('M', 'mon');
+        return date;
+      }
+
+      date = kbn.parseDate(date);
+    }
+
+    date = moment.utc(date).local();
+
+    if (config.timezoneOffset) {
+      date = date.zone(config.timezoneOffset);
+    }
+
+    return date.format('HH:mm_YYYYMMDD');
+  };
+
+  GraphiteDatasource.prototype.metricFindQuery = function(query) {
+    var interpolated;
+    try {
+      interpolated = this.filterSrv.applyFilterToTarget(query);
+    }
+    catch(err) {
+      return $q.reject(err);
+    }
+
+    return this.doGraphiteRequest({method: 'GET', url: '/metrics/find/?query=' + interpolated })
+      .then(function(results) {
+        return _.map(results.data, function(metric) {
+          return {
+            text: metric.text,
+            expandable: metric.expandable ? true : false
+          };
+        });
+      });
+  };
+
+  GraphiteDatasource.prototype.listDashboards = function(query) {
+    return this.doGraphiteRequest({ method: 'GET',  url: '/dashboard/find/', params: {query: query || ''} })
+      .then(function(results) {
+        return results.data.dashboards;
+      });
+  };
+
+  GraphiteDatasource.prototype.loadDashboard = function(dashName) {
+    return this.doGraphiteRequest({method: 'GET', url: '/dashboard/load/' + encodeURIComponent(dashName) });
+  };
+
+  GraphiteDatasource.prototype.doGraphiteRequest = function(options) {
+    if (this.basicAuth) {
+      options.withCredentials = true;
+      options.headers = options.headers || {};
+      options.headers.Authorization = 'Basic ' + config.graphiteBasicAuth;
+    }
+
+    options.url = this.url + options.url;
+
+    return this.$http(options);
+  };
+
+  GraphiteDatasource.prototype.buildGraphiteParams = function(options) {
+    var clean_options = [];
+    var graphite_options = ['target', 'targets', 'from', 'until', 'rawData', 'format', 'maxDataPoints'];
+
+    if (options.format !== 'png') {
+      options['format'] = 'json';
+    }
+
+    _.each(options, function (value, key) {
+      if ($.inArray(key, graphite_options) === -1) {
+        return;
+      }
+
+      if (key === "targets") {
+        _.each(value, function (value) {
+          if (!value.hide) {
+            var targetValue = this.filterSrv.applyFilterToTarget(value.target);
+            clean_options.push("target=" + encodeURIComponent(targetValue));
+          }
+        }, this);
+      }
+      else if (value !== null) {
+        clean_options.push(key + "=" + encodeURIComponent(value));
+      }
+    }, this);
+    return clean_options;
+  };
+
+
+  return GraphiteDatasource;
+
+});

+ 0 - 161
src/app/services/graphite/graphiteSrv.js

@@ -1,161 +0,0 @@
-define([
-  'angular',
-  'underscore',
-  'jquery',
-  'config',
-  'kbn',
-  'moment'
-],
-function (angular, _, $, config, kbn, moment) {
-  'use strict';
-
-  var module = angular.module('kibana.services');
-
-  module.service('graphiteSrv', function($http, $q, filterSrv) {
-    var graphiteRenderUrl = config.graphiteUrl + "/render";
-
-    this.query = function(options) {
-      try {
-        var graphOptions = {
-          from: this.translateTime(options.range.from),
-          until: this.translateTime(options.range.to),
-          targets: options.targets,
-          format: options.format,
-          maxDataPoints: options.maxDataPoints
-        };
-
-        var params = buildGraphiteParams(graphOptions);
-
-        if (options.format === 'png') {
-          return $q.when(graphiteRenderUrl + '?' + params.join('&'));
-        }
-
-        return doGraphiteRequest({
-          method: 'POST',
-          url: graphiteRenderUrl,
-          data: params.join('&'),
-          headers: {
-            'Content-Type': 'application/x-www-form-urlencoded',
-          }
-        });
-      }
-      catch(err) {
-        return $q.reject(err);
-      }
-    };
-
-    this.translateTime = function(date) {
-      if (_.isString(date)) {
-        if (date === 'now') {
-          return 'now';
-        }
-        else if (date.indexOf('now') >= 0) {
-          date = date.substring(3);
-          date = date.replace('m', 'min');
-          date = date.replace('M', 'mon');
-          return date;
-        }
-
-        date = kbn.parseDate(date);
-      }
-
-      date = moment.utc(date).local();
-
-      if (config.timezoneOffset) {
-        date = date.zone(config.timezoneOffset);
-      }
-
-      return date.format('HH:mm_YYYYMMDD');
-    };
-
-    this.match = function(targets, graphiteTargetStr) {
-      var found = targets[0];
-
-      for (var i = 0; i < targets.length; i++) {
-        if (targets[i].target === graphiteTargetStr) {
-          found = targets[i];
-          break;
-        }
-        if(targets[i].target.match("'" + graphiteTargetStr + "'")) {
-          found = targets[i];
-        }
-      }
-
-      return found;
-    };
-
-    this.metricFindQuery = function(query) {
-      var interpolated;
-      try {
-        interpolated = filterSrv.applyFilterToTarget(query);
-      }
-      catch(err) {
-        return $q.reject(err);
-      }
-
-      var url = config.graphiteUrl + '/metrics/find/?query=' + interpolated;
-      return doGraphiteRequest({method: 'GET', url: url})
-        .then(function(results) {
-          return _.map(results.data, function(metric) {
-            return {
-              text: metric.text,
-              expandable: metric.expandable ? true : false
-            };
-          });
-        });
-    };
-
-    this.listDashboards = function(query) {
-      var url = config.graphiteUrl + '/dashboard/find/';
-      return doGraphiteRequest({ method: 'GET',  url: url, params: {query: query || ''} })
-        .then(function(results) {
-          return results.data.dashboards;
-        });
-    };
-
-    this.loadDashboard = function(dashName) {
-      var url = config.graphiteUrl + '/dashboard/load/' + encodeURIComponent(dashName);
-      return doGraphiteRequest({method: 'GET', url: url});
-    };
-
-    function doGraphiteRequest(options) {
-      if (config.graphiteBasicAuth) {
-        options.withCredentials = true;
-        options.headers = options.headers || {};
-        options.headers.Authorization = 'Basic ' + config.graphiteBasicAuth;
-      }
-
-      return $http(options);
-    }
-
-    function buildGraphiteParams(options) {
-      var clean_options = [];
-      var graphite_options = ['target', 'targets', 'from', 'until', 'rawData', 'format', 'maxDataPoints'];
-
-      if (options.format !== 'png') {
-        options['format'] = 'json';
-      }
-
-      $.each(options, function (key, value) {
-        if ($.inArray(key, graphite_options) === -1) {
-          return;
-        }
-
-        if (key === "targets") {
-          $.each(value, function (index, value) {
-            if (!value.hide) {
-              var targetValue = filterSrv.applyFilterToTarget(value.target);
-              clean_options.push("target=" + encodeURIComponent(targetValue));
-            }
-          });
-        }
-        else if (value !== null) {
-          clean_options.push(key + "=" + encodeURIComponent(value));
-        }
-      });
-      return clean_options;
-    }
-
-  });
-
-});

+ 9 - 0
src/config.sample.js

@@ -24,6 +24,15 @@ function (Settings) {
      */
     graphiteUrl: "http://"+window.location.hostname+":8080",
 
+    /**
+     * Multiple graphite servers? Comment out graphiteUrl and replace with
+     *
+     *  datasources: {
+     *    data_center_us: { type: 'graphite',  url: 'http://<graphite_url>',  default: true },
+     *    data_center_eu: { type: 'graphite',  url: 'http://<graphite_url>' }
+     *  }
+     */
+
     default_route: '/dashboard/file/default.json',
 
     /**