more work on influxdb datasource, query editor, and refactoring
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
@@ -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,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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 promises = _.map(options.targets, function(target) {
|
||||
if (!target.series || !target.column || target.hide) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var query = _.template(template, templateData, this.templateSettings);
|
||||
console.log(query);
|
||||
var template = "select [[func]]([[column]]) from [[series]] where [[timeFilter]] group by time([[interval]]) order asc";
|
||||
|
||||
var output = { data: [] };
|
||||
var templateData = {
|
||||
series: target.series,
|
||||
column: target.column,
|
||||
func: target.function,
|
||||
timeFilter: getTimeFilter(options),
|
||||
interval: target.interval || options.interval
|
||||
};
|
||||
|
||||
return this.doInfluxRequest(query).then(function(results) {
|
||||
var query = _.template(template, templateData, this.templateSettings);
|
||||
console.log(query);
|
||||
|
||||
_.each(results.data, function(series) {
|
||||
var timeCol = series.columns.indexOf('time');
|
||||
return this.doInfluxRequest(query).then(handleInfluxQueryResponse);
|
||||
|
||||
_.each(series.columns, function(column, index) {
|
||||
if (column === "time" || column === "sequence_number") {
|
||||
return;
|
||||
}
|
||||
}, this);
|
||||
|
||||
console.log("series:"+series.name + ": "+series.points.length + " points");
|
||||
return $q.all(promises).then(function(results) {
|
||||
|
||||
var target = series.name + "." + column;
|
||||
var datapoints = [];
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
output.data.push({ target:target, datapoints:datapoints });
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
|
||||
Reference in New Issue
Block a user