Commit 50fd5512 by Torkel Ödegaard

more work on influxdb datasource, query editor, and refactoring

parent 291dd9bd
...@@ -52,14 +52,17 @@ function (_, crypto) { ...@@ -52,14 +52,17 @@ function (_, crypto) {
if (options.graphiteUrl) { if (options.graphiteUrl) {
settings.datasources = { settings.datasources = {
graphite: { graphite: {
name: 'default', type: 'graphite',
url: options.graphiteUrl, url: options.graphiteUrl,
default: true default: true
} }
}; };
} }
_.map(settings.datasources, parseBasicAuth); _.each(settings.datasources, function(datasource, key) {
datasource.name = key;
parseBasicAuth(datasource);
});
var elasticParsed = parseBasicAuth({ url: settings.elasticsearch }); var elasticParsed = parseBasicAuth({ url: settings.elasticsearch });
settings.elasticsearchBasicAuth = elasticParsed.basicAuth; settings.elasticsearchBasicAuth = elasticParsed.basicAuth;
......
...@@ -27,16 +27,6 @@ ...@@ -27,16 +27,6 @@
<div class="tab-content" ng-repeat="tab in panelMeta.fullEditorTabs" ng-show="editorTabs[editor.index] == tab.title"> <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 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> </div>
</div> </div>
\ No newline at end of file
...@@ -46,6 +46,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -46,6 +46,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}, },
{ {
title: 'Metrics', title: 'Metrics',
src:'app/partials/metrics.html'
}, },
{ {
title:'Axes & Grid', title:'Axes & Grid',
...@@ -206,12 +207,12 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -206,12 +207,12 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
$scope.hiddenSeries = {}; $scope.hiddenSeries = {};
$scope.datasources = datasourceSrv.listOptions(); $scope.datasources = datasourceSrv.listOptions();
$scope.datasourceChanged(); $scope.setDatasource($scope.panel.datasource);
}; };
$scope.datasourceChanged = function() { $scope.setDatasource = function(datasource) {
$scope.datasource = datasourceSrv.get($scope.panel.datasource); $scope.panel.datasource = datasource;
$scope.panelMeta.fullEditorTabs[1].src = $scope.datasource.editorSrc; $scope.datasource = datasourceSrv.get(datasource);
$scope.get_data(); $scope.get_data();
}; };
...@@ -299,6 +300,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -299,6 +300,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
yaxis: yaxis yaxis: yaxis
}; };
$scope.legend.push(seriesInfo);
var series = new timeSeries.ZeroFilled({ var series = new timeSeries.ZeroFilled({
datapoints: datapoints, datapoints: datapoints,
info: seriesInfo, info: seriesInfo,
......
<div class="editor-row"> <div class="editor-row" style="margin-top: 10px;">
<div ng-repeat="target in panel.targets" <div ng-repeat="target in panel.targets"
class="grafana-target" class="grafana-target"
...@@ -112,6 +112,3 @@ ...@@ -112,6 +112,3 @@
</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 target</button>
</div>
\ No newline at end of file
<h5>InfluxDB queries<h5>
<div class="editor-row"> <div class="editor-row" style="margin-top: 10px;">
<div ng-repeat="target in panel.targets" <div ng-repeat="target in panel.targets"
class="grafana-target" class="grafana-target"
...@@ -44,10 +43,8 @@ ...@@ -44,10 +43,8 @@
</ul> </ul>
<ul class="grafana-segment-list" role="menu"> <ul class="grafana-segment-list" role="menu">
<li> <li class="grafana-target-segment">
<a class="grafana-target-segment"> from series
from series
</a>
</li> </li>
<li> <li>
<input type="text" <input type="text"
...@@ -55,12 +52,10 @@ ...@@ -55,12 +52,10 @@
ng-model="target.series" ng-model="target.series"
spellcheck='false' spellcheck='false'
placeholder="series name" placeholder="series name"
ng-model-onblur ng-change="targetTextChanged()" > ng-model-onblur ng-change="get_data()" >
</li> </li>
<li> <li class="grafana-target-segment">
<a class="grafana-target-segment"> select
select
</a>
</li> </li>
<li> <li>
<input type="text" <input type="text"
...@@ -68,25 +63,31 @@ ...@@ -68,25 +63,31 @@
ng-model="target.column" ng-model="target.column"
placeholder="value column" placeholder="value column"
spellcheck='false' spellcheck='false'
ng-model-onblur ng-change="targetTextChanged()" > ng-model-onblur ng-change="get_data()" >
</li>
<li class="grafana-target-segment">
function
</li> </li>
<li> <li>
<a class="grafana-target-segment"> <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>
function </li>
</a> <li class="grafana-target-segment">
group by time
</li> </li>
<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> </li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div> </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>
\ No newline at end of file
<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>
...@@ -18,6 +18,7 @@ function (angular, _, $, config, kbn, moment) { ...@@ -18,6 +18,7 @@ function (angular, _, $, config, kbn, moment) {
this.basicAuth = datasource.basicAuth; this.basicAuth = datasource.basicAuth;
this.url = datasource.url; this.url = datasource.url;
this.editorSrc = 'app/partials/graphite/editor.html'; this.editorSrc = 'app/partials/graphite/editor.html';
this.name = datasource.name;
} }
GraphiteDatasource.prototype.query = function(options) { GraphiteDatasource.prototype.query = function(options) {
......
define([ define([
'angular', 'angular',
'underscore', 'underscore',
'kbn'
], ],
function (angular, _) { function (angular, _, kbn) {
'use strict'; 'use strict';
var module = angular.module('kibana.services'); var module = angular.module('kibana.services');
...@@ -15,6 +16,7 @@ function (angular, _) { ...@@ -15,6 +16,7 @@ function (angular, _) {
this.url = datasource.url; this.url = datasource.url;
this.username = datasource.username; this.username = datasource.username;
this.password = datasource.password; this.password = datasource.password;
this.name = datasource.name;
this.templateSettings = { this.templateSettings = {
interpolate : /\[\[([\s\S]+?)\]\]/g, interpolate : /\[\[([\s\S]+?)\]\]/g,
...@@ -22,49 +24,32 @@ function (angular, _) { ...@@ -22,49 +24,32 @@ function (angular, _) {
} }
InfluxDatasource.prototype.query = function(options) { 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 template = "select [[func]]([[column]]) from [[series]] where [[timeFilter]] group by time([[interval]]) order asc";
var timeCol = series.columns.indexOf('time');
_.each(series.columns, function(column, index) { var templateData = {
if (column === "time" || column === "sequence_number") { series: target.series,
return; 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; return this.doInfluxRequest(query).then(handleInfluxQueryResponse);
var datapoints = [];
var i, y; }, this);
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];
}
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, _) { ...@@ -85,24 +70,59 @@ function (angular, _) {
return $http(options); 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) { function getTimeFilter(options) {
var from = options.range.from; var from = getInfluxTime(options.range.from);
var until = options.range.to; var until = getInfluxTime(options.range.to);
if (_.isString(from)) { if (until === 'now()') {
return 'time > now() - ' + from.substring(4); return 'time > now() - ' + from;
}
else {
from = to_utc_epoch_seconds(from);
} }
if (until === 'now') { return 'time > ' + from + ' and time < ' + until;
return 'time > ' + from; }
}
else { function getInfluxTime(date) {
until = to_utc_epoch_seconds(until); if (_.isString(date)) {
return 'time > ' + from + ' and time < ' + until; 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) { function to_utc_epoch_seconds(date) {
......
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