refactoring of graphite panel to be more datasource agnostic, start of experimental influxdb support

This commit is contained in:
Torkel Ödegaard 2014-02-27 21:46:06 +01:00
parent ed2770e380
commit e3f56f2645
14 changed files with 140 additions and 67 deletions

View File

@ -69,8 +69,7 @@
"nullPointMode": "connected", "nullPointMode": "connected",
"steppedLine": false, "steppedLine": false,
"tooltip": { "tooltip": {
"value_type": "cumulative", "value_type": "cumulative"
"query_as_alias": true
}, },
"targets": [ "targets": [
{ {

View File

@ -289,7 +289,7 @@ function (angular, $, kbn, moment, _) {
seriesInfo = item.series.info; seriesInfo = item.series.info;
format = scope.panel.y_formats[seriesInfo.yaxis - 1]; format = scope.panel.y_formats[seriesInfo.yaxis - 1];
if (seriesInfo.alias || scope.panel.tooltip.query_as_alias) { if (seriesInfo.alias) {
group = '<small style="font-size:0.9em;">' + group = '<small style="font-size:0.9em;">' +
'<i class="icon-circle" style="color:'+item.series.color+';"></i>' + ' ' + '<i class="icon-circle" style="color:'+item.series.color+';"></i>' + ' ' +
(seriesInfo.alias || seriesInfo.query)+ (seriesInfo.alias || seriesInfo.query)+

View File

@ -88,8 +88,7 @@ function (angular, $) {
var nameAsPath = name.replace(".", "/"); var nameAsPath = name.replace(".", "/");
$scope.require([ $scope.require([
'jquery', 'jquery',
'text!panels/'+nameAsPath+'/module.html', 'text!panels/'+nameAsPath+'/module.html'
'text!panels/'+nameAsPath+'/editor.html'
], function ($, moduleTemplate) { ], function ($, moduleTemplate) {
var $module = $(moduleTemplate); var $module = $(moduleTemplate);
// top level controllers // top level controllers

View File

@ -27,27 +27,23 @@
</div> </div>
<div class="panel-full-edit-tabs" ng-if="editMode"> <div class="panel-full-edit-tabs" ng-if="editMode">
<div ng-model="editor.index" bs-tabs> <div ng-model="editor.index" bs-tabs>
<div ng-repeat="tab in editorTabs" data-title="{{tab}}"> <div ng-repeat="tab in editorTabs" data-title="{{tab}}">
</div>
</div> </div>
</div>
<!-- <div class="tab-content" ng-show="editorTabs[editor.index] == 'General'"> <div class="tab-content" ng-repeat="tab in panelMeta.fullEditorTabs" ng-show="editorTabs[editor.index] == tab.title">
<div ng-include src="'app/partials/panelgeneral.html'"></div> <div ng-include src="tab.src"></div>
<div class="editor-row" ng-show="datasources.length > 0"> <div class="editor-row" ng-show="editor.index === 0">
<div class="section"> <div class="section">
<div class="editor-option"> <h5>Datasource options</h5>
<label class="small">Datasource</label> <div class="editor-option">
<select class="input-large" ng-options="obj.value as obj.name for obj in datasources" ng-model="panel.datasource" ng-change="datasourceChanged()"></select> <label class="small">Datasource name</label>
</div> <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>
--> </div>
<div class="tab-content" ng-repeat="tab in panelMeta.editorTabs" ng-show="editorTabs[editor.index] == tab.title">
<div ng-include src="tab.src"></div>
</div>
</div> </div>
</div> </div>

View File

@ -38,15 +38,15 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
$scope.panelMeta = { $scope.panelMeta = {
modals : [], modals : [],
editorTabs: [],
editorTabs : [ fullEditorTabs : [
{ {
title: 'General', title: 'General',
src:'app/partials/panelgeneral.html' src:'app/partials/panelgeneral.html'
}, },
{ {
title:'Targets', title: 'Metrics',
src:'app/panels/graphite/editor.html'
}, },
{ {
title:'Axes & Grid', title:'Axes & Grid',
@ -80,7 +80,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
], ],
status : "Unstable", status : "Unstable",
description : "Graphite graphing panel <br /><br />" description : "Graphs panel"
}; };
// Set and populate defaults // Set and populate defaults
@ -224,21 +224,18 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
$scope.fullscreen = false; $scope.fullscreen = false;
$scope.options = false; $scope.options = false;
$scope.editor = {index: 1}; $scope.editor = {index: 1};
$scope.editorTabs = _.pluck($scope.panelMeta.editorTabs,'title'); $scope.editorTabs = _.pluck($scope.panelMeta.fullEditorTabs,'title');
$scope.hiddenSeries = {}; $scope.hiddenSeries = {};
$scope.datasources = datasourceSrv.listOptions(); $scope.datasources = datasourceSrv.listOptions();
$scope.datasource = datasourceSrv.get($scope.panel.datasource); $scope.datasourceChanged();
// 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;
$scope.get_data(); $scope.get_data();
}; };
$scope.datasourceChanged = function() { $scope.datasourceChanged = function() {
$scope.datasource = datasourceSrv.get($scope.panel.datasource); $scope.datasource = datasourceSrv.get($scope.panel.datasource);
$scope.panelMeta.fullEditorTabs[1].src = $scope.datasource.editorSrc;
$scope.get_data(); $scope.get_data();
}; };

View File

@ -1,3 +1,4 @@
<div class="editor-row"> <div class="editor-row">
<div ng-repeat="target in panel.targets" <div ng-repeat="target in panel.targets"
@ -75,7 +76,7 @@
</ul> </ul>
</li> </li>
<li ng-repeat="func in functions"> <li ng-repeat="func in functions">
<a class="grafana-target-segment grafana-target-function dropdown-toggle" bs-popover="'app/panels/graphite/funcEditor.html'" data-placement="bottom"> <a class="grafana-target-segment grafana-target-function dropdown-toggle" bs-popover="'app/partials/graphite/funcEditor.html'" data-placement="bottom">
{{func.text}} {{func.text}}
</a> </a>
</li> </li>

View File

@ -0,0 +1 @@
<h5>InfluxDB<h5>

View File

@ -1,6 +1,6 @@
<div ng-include="'app/partials/panelgeneral.html'"></div> <div ng-include="'app/partials/panelgeneral.html'"></div>
<div ng-include="edit_path(panel.type)"></div> <div ng-if="!panelMeta.fullEditorTabs" ng-include="edit_path(panel.type)"></div>
<div ng-repeat="tab in panelMeta.editorTabs"> <div ng-repeat="tab in panelMeta.editorTabs">
<h5>{{tab.title}}</h5> <h5>{{tab.title}}</h5>
<div ng-include="tab.src"></div> <div ng-include="tab.src"></div>
</div> </div>

View File

@ -1,24 +1,20 @@
<div class="editor-row"> <div class="editor-row">
<div class="section"> <div class="section">
<strong>{{panelMeta.status}}</strong> // <span ng-bind-html="panelMeta.description"></span> <h5>General options</h5>
<div class="editor-option">
<label class="small">Title</label><input type="text" class="input-medium" ng-model='panel.title'></input>
</div>
<div class="editor-option" ng-hide="panel.sizeable == false">
<label class="small">Span</label> <select class="input-mini" ng-model="panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select>
</div>
<div class="editor-option">
<label class="small">Editable</label><input type="checkbox" ng-model="panel.editable" ng-checked="panel.editable">
</div>
<div class="editor-option" ng-show="!_.isUndefined(panel.spyable)">
<label class="small">
Inspect <i class="icon-question-sign" bs-tooltip="'Allow query reveal via <i class=icon-eye-open></i>'"></i>
</label>
<input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable">
</div> </div>
</div> </div>
<div class="editor-row"> </div>
<div class="section">
<div class="editor-option">
<label class="small">Title</label><input type="text" class="input-medium" ng-model='panel.title'></input>
</div>
<div class="editor-option" ng-hide="panel.sizeable == false">
<label class="small">Span</label> <select class="input-mini" ng-model="panel.span" ng-options="f for f in [0,1,2,3,4,5,6,7,8,9,10,11,12]"></select>
</div>
<div class="editor-option">
<label class="small">Editable</label><input type="checkbox" ng-model="panel.editable" ng-checked="panel.editable">
</div>
<div class="editor-option" ng-show="!_.isUndefined(panel.spyable)">
<label class="small">
Inspect <i class="icon-question-sign" bs-tooltip="'Allow query reveal via <i class=icon-eye-open></i>'"></i>
</label>
<input type="checkbox" ng-model="panel.spyable" ng-checked="panel.spyable">
</div>
</div>
</div>

View File

@ -7,6 +7,5 @@ define([
'./datasourceSrv', './datasourceSrv',
'./keyboardManager', './keyboardManager',
'./annotationsSrv', './annotationsSrv',
'./graphite/graphiteDatasource',
], ],
function () {}); function () {});

View File

@ -1,25 +1,32 @@
define([ define([
'angular', 'angular',
'underscore', 'underscore',
'config' 'config',
'./graphite/graphiteDatasource',
'./influxdb/influxdbDatasource',
], ],
function (angular, _, config) { function (angular, _, config) {
'use strict'; 'use strict';
var module = angular.module('kibana.services'); var module = angular.module('kibana.services');
module.service('datasourceSrv', function($q, filterSrv, $http, GraphiteDatasource) { module.service('datasourceSrv', function($q, filterSrv, $http, GraphiteDatasource, InfluxDatasource) {
var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true } ); var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true } );
this.default = new GraphiteDatasource(defaultDatasource); this.default = new GraphiteDatasource(defaultDatasource);
this.get = function(name) { this.get = function(name) {
if (!name) { if (!name) { return this.default; }
return this.default;
}
return new GraphiteDatasource(config.datasources[name]); var ds = config.datasources[name];
switch(ds.type) {
case 'graphite':
return new GraphiteDatasource(ds);
case 'influxdb':
return new InfluxDatasource(ds);
}
}; };
this.listOptions = function() { this.listOptions = function() {

View File

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

View File

@ -0,0 +1,77 @@
define([
'angular',
'underscore',
],
function (angular, _) {
'use strict';
var module = angular.module('kibana.services');
module.factory('InfluxDatasource', function($q, $http) {
function InfluxDatasource(datasource) {
this.type = 'influxDB';
this.editorSrc = 'app/partials/influxDB/editor.html';
this.url = datasource.url;
this.username = datasource.username;
this.password = datasource.password;
}
InfluxDatasource.prototype.query = function() {
var q = "select value from request_count where time > now() - 1h group by time(1m)";
var output = { data: [] };
return this.doInfluxRequest(q).then(function(results) {
_.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.data.push({ target:target, datapoints:datapoints });
});
});
return output;
});
};
InfluxDatasource.prototype.doInfluxRequest = function(query) {
var params = {
u: this.username,
p: this.password,
q: query
};
var options = {
method: 'GET',
url: this.url + '/series',
params: params,
};
return $http(options);
};
return InfluxDatasource;
});
});