mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Improvement and polish to the OpenTSDB query editor (Issue #492)
This commit is contained in:
commit
6885cea0fd
@ -14,6 +14,9 @@
|
|||||||
- Improvement to InfluxDB query editor and function/value column selection (Issue #473)
|
- Improvement to InfluxDB query editor and function/value column selection (Issue #473)
|
||||||
- Initial support for filtering (templated queries) for InfluxDB (PR #375) - thx @mavimo
|
- Initial support for filtering (templated queries) for InfluxDB (PR #375) - thx @mavimo
|
||||||
- Row editing and adding new panel is now a lot quicker and easier with the new row menu (Issue #475)
|
- Row editing and adding new panel is now a lot quicker and easier with the new row menu (Issue #475)
|
||||||
|
- New datasource! Initial support for OpenTSDB (PR #211) - thx @mpage
|
||||||
|
- Improvement and polish to the OpenTSDB query editor (Issue #492)
|
||||||
|
|
||||||
|
|
||||||
#### Changes
|
#### Changes
|
||||||
- Graphite panel is now renamed graph (Existing dashboards will still work)
|
- Graphite panel is now renamed graph (Existing dashboards will still work)
|
||||||
|
@ -11,4 +11,5 @@ define([
|
|||||||
'./influxTargetCtrl',
|
'./influxTargetCtrl',
|
||||||
'./playlistCtrl',
|
'./playlistCtrl',
|
||||||
'./inspectCtrl',
|
'./inspectCtrl',
|
||||||
|
'./opentsdbTargetCtrl',
|
||||||
], function () {});
|
], function () {});
|
||||||
|
118
src/app/controllers/opentsdbTargetCtrl.js
Normal file
118
src/app/controllers/opentsdbTargetCtrl.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'underscore',
|
||||||
|
'kbn'
|
||||||
|
],
|
||||||
|
function (angular, _, kbn) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var module = angular.module('kibana.controllers');
|
||||||
|
|
||||||
|
module.controller('OpenTSDBTargetCtrl', function($scope, $timeout) {
|
||||||
|
|
||||||
|
$scope.init = function() {
|
||||||
|
$scope.target.errors = validateTarget($scope.target);
|
||||||
|
$scope.aggregators = ['avg', 'sum', 'min', 'max', 'dev', 'zimsum', 'mimmin', 'mimmax'];
|
||||||
|
|
||||||
|
if (!$scope.target.aggregator) {
|
||||||
|
$scope.target.aggregator = 'sum';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$scope.target.downsampleAggregator) {
|
||||||
|
$scope.target.downsampleAggregator = 'sum';
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.$on('typeahead-updated', function() {
|
||||||
|
$timeout($scope.targetBlur);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.targetBlur = function() {
|
||||||
|
$scope.target.errors = validateTarget($scope.target);
|
||||||
|
|
||||||
|
// this does not work so good
|
||||||
|
if (!_.isEqual($scope.oldTarget, $scope.target) && _.isEmpty($scope.target.errors)) {
|
||||||
|
$scope.oldTarget = angular.copy($scope.target);
|
||||||
|
$scope.get_data();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.duplicate = function() {
|
||||||
|
var clone = angular.copy($scope.target);
|
||||||
|
$scope.panel.targets.push(clone);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.suggestMetrics = function(query, callback) {
|
||||||
|
$scope.datasource
|
||||||
|
.performSuggestQuery(query, 'metrics')
|
||||||
|
.then(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.suggestTagKeys = function(query, callback) {
|
||||||
|
$scope.datasource
|
||||||
|
.performSuggestQuery(query, 'tagk')
|
||||||
|
.then(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.suggestTagValues = function(query, callback) {
|
||||||
|
$scope.datasource
|
||||||
|
.performSuggestQuery(query, 'tagv')
|
||||||
|
.then(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.addTag = function() {
|
||||||
|
if (!$scope.addTagMode) {
|
||||||
|
$scope.addTagMode = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$scope.target.tags) {
|
||||||
|
$scope.target.tags = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.target.errors = validateTarget($scope.target);
|
||||||
|
|
||||||
|
if (!$scope.target.errors.tags) {
|
||||||
|
$scope.target.tags[$scope.target.currentTagKey] = $scope.target.currentTagValue;
|
||||||
|
$scope.target.currentTagKey = '';
|
||||||
|
$scope.target.currentTagValue = '';
|
||||||
|
$scope.targetBlur();
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.addTagMode = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.removeTag = function(key) {
|
||||||
|
delete $scope.target.tags[key];
|
||||||
|
$scope.targetBlur();
|
||||||
|
};
|
||||||
|
|
||||||
|
function validateTarget(target) {
|
||||||
|
var errs = {};
|
||||||
|
|
||||||
|
if (!target.metric) {
|
||||||
|
errs.metric = "You must supply a metric name.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.shouldDownsample) {
|
||||||
|
try {
|
||||||
|
if (target.downsampleInterval) {
|
||||||
|
kbn.describe_interval(target.downsampleInterval);
|
||||||
|
} else {
|
||||||
|
errs.downsampleInterval = "You must supply a downsample interval (e.g. '1m' or '1h').";
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
errs.downsampleInterval = err.message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.tags && _.has(target.tags, target.currentTagKey)) {
|
||||||
|
errs.tags = "Duplicate tag key '" + target.currentTagKey + "'.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
322
src/app/partials/opentsdb/editor.html
Normal file
322
src/app/partials/opentsdb/editor.html
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
<div class="editor-row" style="margin-top: 10px;">
|
||||||
|
<div ng-repeat="target in panel.targets"
|
||||||
|
class="grafana-target"
|
||||||
|
ng-class="{'grafana-target-hidden': target.hide}"
|
||||||
|
ng-controller="OpenTSDBTargetCtrl"
|
||||||
|
ng-init="init()">
|
||||||
|
|
||||||
|
<div class="grafana-target-inner-wrapper">
|
||||||
|
<div class="grafana-target-inner">
|
||||||
|
<ul class="grafana-target-controls">
|
||||||
|
<li class="dropdown">
|
||||||
|
<a class="pointer dropdown-toggle"
|
||||||
|
data-toggle="dropdown"
|
||||||
|
tabindex="1">
|
||||||
|
<i class="icon-cog"></i>
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu pull-right" role="menu">
|
||||||
|
<li role="menuitem">
|
||||||
|
<a tabindex="1"
|
||||||
|
ng-click="duplicate()">
|
||||||
|
Duplicate
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="pointer" tabindex="1" ng-click="removeTarget(target)">
|
||||||
|
<i class="icon-remove"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="grafana-target-controls-left">
|
||||||
|
<li>
|
||||||
|
<a class="grafana-target-segment"
|
||||||
|
ng-click="target.hide = !target.hide; get_data();"
|
||||||
|
role="menuitem">
|
||||||
|
<i class="icon-eye-open"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="grafana-segment-list" role="menu">
|
||||||
|
<li>
|
||||||
|
<input type="text"
|
||||||
|
class="input-xxlarge grafana-target-segment-input"
|
||||||
|
ng-model="target.metric"
|
||||||
|
spellcheck='false'
|
||||||
|
bs-typeahead="suggestMetrics"
|
||||||
|
placeholder="metric name"
|
||||||
|
data-min-length=0 data-items=100
|
||||||
|
ng-blur="targetBlur()"
|
||||||
|
>
|
||||||
|
<a bs-tooltip="target.errors.metric"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.metric">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Aggregator
|
||||||
|
<li>
|
||||||
|
<select ng-model="target.aggregator"
|
||||||
|
class="grafana-target-segment-input input-small"
|
||||||
|
ng-options="agg for agg in aggregators"
|
||||||
|
ng-change="targetBlur()">
|
||||||
|
</select>
|
||||||
|
<a bs-tooltip="target.errors.aggregator"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.aggregator">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Rate:
|
||||||
|
<input type="checkbox"
|
||||||
|
class="grafana-target-option-checkbox"
|
||||||
|
ng-model="target.shouldComputeRate"
|
||||||
|
ng-change="targetBlur()"
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li class="grafana-target-segment" ng-hide="!target.shouldComputeRate">
|
||||||
|
Counter:
|
||||||
|
<input type="checkbox"
|
||||||
|
class="grafana-target-option-checkbox"
|
||||||
|
ng-disabled="!target.shouldComputeRate"
|
||||||
|
ng-model="target.isCounter"
|
||||||
|
ng-change="targetBlur()">
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grafana-target-inner">
|
||||||
|
<ul class="grafana-segment-list" role="menu">
|
||||||
|
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Downsample:
|
||||||
|
<input type="checkbox"
|
||||||
|
class="grafana-target-option-checkbox"
|
||||||
|
ng-model="target.shouldDownsample"
|
||||||
|
ng-change="targetBlur(target)"
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li ng-hide="!target.shouldDownsample">
|
||||||
|
<input type="text"
|
||||||
|
class="input-small grafana-target-segment-input"
|
||||||
|
ng-disabled="!target.shouldDownsample"
|
||||||
|
ng-model="target.downsampleInterval"
|
||||||
|
ng-change="targetBlur()"
|
||||||
|
placeholder="interval"
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment" ng-hide="!target.shouldDownsample">
|
||||||
|
Aggregator
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li ng-hide="!target.shouldDownsample">
|
||||||
|
<select ng-model="target.downsampleAggregator"
|
||||||
|
class="grafana-target-segment-input input-small"
|
||||||
|
ng-options="agg for agg in aggregators"
|
||||||
|
ng-change="targetBlur()">
|
||||||
|
</select>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Tags:
|
||||||
|
</li>
|
||||||
|
<li ng-repeat="(key, value) in target.tags track by $index" class="grafana-target-segment">
|
||||||
|
{{key}} = {{value}}
|
||||||
|
<a ng-click="removeTag(key)">
|
||||||
|
<i class="icon-remove"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment" ng-hide="addTagMode">
|
||||||
|
<a ng-click="addTag()">
|
||||||
|
<i class="icon-plus-sign"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li ng-show="addTagMode">
|
||||||
|
<input type="text"
|
||||||
|
class="input-small grafana-target-segment-input"
|
||||||
|
spellcheck='false'
|
||||||
|
bs-typeahead="suggestTagKeys"
|
||||||
|
data-min-length=0 data-items=100
|
||||||
|
ng-model="target.currentTagKey"
|
||||||
|
placeholder="key">
|
||||||
|
<input type="text"
|
||||||
|
class="input-small grafana-target-segment-input"
|
||||||
|
spellcheck='false'
|
||||||
|
bs-typeahead="suggestTagValues"
|
||||||
|
data-min-length=0 data-items=100
|
||||||
|
ng-model="target.currentTagValue"
|
||||||
|
placeholder="value">
|
||||||
|
<a ng-click="addTag()">
|
||||||
|
<i class="icon-plus-sign"></i>
|
||||||
|
</a>
|
||||||
|
<a bs-tooltip="target.errors.tags"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.tags">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<!-- <ul class="grafana-segment-list" role="menu">
|
||||||
|
<li>
|
||||||
|
<input type="text"
|
||||||
|
class="input-xlarge grafana-target-segment-input"
|
||||||
|
ng-model="target.metric"
|
||||||
|
spellcheck='false'
|
||||||
|
bs-typeahead="suggestMetrics"
|
||||||
|
placeholder="metric name"
|
||||||
|
data-min-length=0 data-items=100
|
||||||
|
ng-blur="targetBlur()"
|
||||||
|
>
|
||||||
|
<a bs-tooltip="target.errors.metric"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.metric">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<select ng-model="target.aggregator"
|
||||||
|
class="grafana-target-segment-input input-small"
|
||||||
|
ng-options="agg for agg in aggregators"
|
||||||
|
ng-change="targetBlur()">
|
||||||
|
</select>
|
||||||
|
<a bs-tooltip="target.errors.aggregator"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.aggregator">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Rate:
|
||||||
|
<input type="checkbox"
|
||||||
|
class="grafana-target-option-checkbox"
|
||||||
|
ng-model="target.shouldComputeRate"
|
||||||
|
ng-change="targetBlur()"
|
||||||
|
>
|
||||||
|
<span ng-hide="!target.shouldComputeRate">
|
||||||
|
Counter:
|
||||||
|
<input type="checkbox"
|
||||||
|
class="grafana-target-option-checkbox"
|
||||||
|
ng-disabled="!target.shouldComputeRate"
|
||||||
|
ng-model="target.isCounter"
|
||||||
|
ng-change="targetBlur()"
|
||||||
|
>
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Downsample:
|
||||||
|
<input type="checkbox"
|
||||||
|
class="grafana-target-option-checkbox"
|
||||||
|
ng-model="target.shouldDownsample"
|
||||||
|
ng-change="targetBlur(target)"
|
||||||
|
>
|
||||||
|
<div ng-hide="!target.shouldDownsample">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Interval:
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text"
|
||||||
|
class="input-small"
|
||||||
|
ng-disabled="!target.shouldDownsample"
|
||||||
|
ng-model="target.downsampleInterval"
|
||||||
|
ng-change="targetBlur()">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a bs-tooltip="target.errors.downsampleInterval"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.downsampleInterval">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Aggregator:</td>
|
||||||
|
<td>
|
||||||
|
<select ng-model="target.downsampleAggregator"
|
||||||
|
class="grafana-target-segment-input input-small"
|
||||||
|
ng-options="agg for agg in aggregators"
|
||||||
|
ng-change="targetBlur()"
|
||||||
|
>
|
||||||
|
<option value="">Pick one</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a bs-tooltip="target.errors.downsampleAggregator"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.downsampleAggregator">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="grafana-target-segment">
|
||||||
|
Tags:
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div>
|
||||||
|
<input type="text"
|
||||||
|
class="input-small grafana-target-segment-input"
|
||||||
|
spellcheck='false'
|
||||||
|
bs-typeahead="suggestTagKeys"
|
||||||
|
data-min-length=0 data-items=100
|
||||||
|
ng-model="target.currentTagKey"
|
||||||
|
placeholder="key">
|
||||||
|
<input type="text"
|
||||||
|
class="input-small grafana-target-segment-input"
|
||||||
|
spellcheck='false'
|
||||||
|
bs-typeahead="suggestTagValues"
|
||||||
|
data-min-length=0 data-items=100
|
||||||
|
ng-model="target.currentTagValue"
|
||||||
|
placeholder="value">
|
||||||
|
<a ng-click="addTag()">
|
||||||
|
<i class="icon-plus-sign"></i>
|
||||||
|
</a>
|
||||||
|
<a bs-tooltip="target.errors.tags"
|
||||||
|
style="color: rgb(229, 189, 28)"
|
||||||
|
ng-show="target.errors.tags">
|
||||||
|
<i class="icon-warning-sign"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<table ng-hide="_.isEmpty(target.tags)">
|
||||||
|
<tr>
|
||||||
|
<th>Key</th>
|
||||||
|
<th>Value</td>
|
||||||
|
<tr ng-repeat="(key, value) in target.tags track by $index">
|
||||||
|
<td>{{ key }}</td>
|
||||||
|
<td>{{ value }}</td>
|
||||||
|
<td>
|
||||||
|
<a ng-click="removeTag(key)">
|
||||||
|
<i class="icon-remove"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
</ul> -->
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -4,13 +4,14 @@ define([
|
|||||||
'config',
|
'config',
|
||||||
'./graphite/graphiteDatasource',
|
'./graphite/graphiteDatasource',
|
||||||
'./influxdb/influxdbDatasource',
|
'./influxdb/influxdbDatasource',
|
||||||
|
'./opentsdb/opentsdbDatasource',
|
||||||
],
|
],
|
||||||
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, $http, GraphiteDatasource, InfluxDatasource) {
|
module.service('datasourceSrv', function($q, filterSrv, $http, GraphiteDatasource, InfluxDatasource, OpenTSDBDatasource) {
|
||||||
|
|
||||||
this.init = function() {
|
this.init = function() {
|
||||||
var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true });
|
var defaultDatasource = _.findWhere(_.values(config.datasources), { default: true });
|
||||||
@ -23,6 +24,8 @@ function (angular, _, config) {
|
|||||||
return new GraphiteDatasource(ds);
|
return new GraphiteDatasource(ds);
|
||||||
case 'influxdb':
|
case 'influxdb':
|
||||||
return new InfluxDatasource(ds);
|
return new InfluxDatasource(ds);
|
||||||
|
case 'opentsdb':
|
||||||
|
return new OpenTSDBDatasource(ds);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
155
src/app/services/opentsdb/opentsdbDatasource.js
Normal file
155
src/app/services/opentsdb/opentsdbDatasource.js
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'underscore',
|
||||||
|
'kbn'
|
||||||
|
],
|
||||||
|
function (angular, _, kbn) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var module = angular.module('kibana.services');
|
||||||
|
|
||||||
|
module.factory('OpenTSDBDatasource', function($q, $http) {
|
||||||
|
|
||||||
|
function OpenTSDBDatasource(datasource) {
|
||||||
|
this.type = 'opentsdb';
|
||||||
|
this.editorSrc = 'app/partials/opentsdb/editor.html';
|
||||||
|
this.url = datasource.url;
|
||||||
|
this.name = datasource.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called once per panel (graph)
|
||||||
|
OpenTSDBDatasource.prototype.query = function(filterSrv, options) {
|
||||||
|
var start = convertToTSDBTime(options.range.from);
|
||||||
|
var end = convertToTSDBTime(options.range.to);
|
||||||
|
var queries = _.compact(_.map(options.targets, convertTargetToQuery));
|
||||||
|
|
||||||
|
// No valid targets, return the empty result to save a round trip.
|
||||||
|
if (_.isEmpty(queries)) {
|
||||||
|
var d = $q.defer();
|
||||||
|
d.resolve({ data: [] });
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
var groupByTags = {};
|
||||||
|
_.each(queries, function(query) {
|
||||||
|
_.each(query.tags, function(val, key) {
|
||||||
|
if (val === "*") {
|
||||||
|
groupByTags[key] = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.performTimeSeriesQuery(queries, start, end)
|
||||||
|
.then(function(response) {
|
||||||
|
var result = _.map(response.data, function(metricData) {
|
||||||
|
return transformMetricData(metricData, groupByTags);
|
||||||
|
});
|
||||||
|
return { data: result };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenTSDBDatasource.prototype.performTimeSeriesQuery = function(queries, start, end) {
|
||||||
|
var reqBody = {
|
||||||
|
start: start,
|
||||||
|
queries: queries
|
||||||
|
};
|
||||||
|
|
||||||
|
// Relative queries (e.g. last hour) don't include an end time
|
||||||
|
if (end) {
|
||||||
|
reqBody.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
method: 'POST',
|
||||||
|
url: this.url + '/api/query',
|
||||||
|
data: reqBody
|
||||||
|
};
|
||||||
|
|
||||||
|
return $http(options);
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenTSDBDatasource.prototype.performSuggestQuery = function(query, type) {
|
||||||
|
var options = {
|
||||||
|
method: 'GET',
|
||||||
|
url: this.url + '/api/suggest',
|
||||||
|
params: {
|
||||||
|
type: type,
|
||||||
|
q: query
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return $http(options).then(function(result) {
|
||||||
|
return result.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function transformMetricData(md, groupByTags) {
|
||||||
|
var dps = [];
|
||||||
|
|
||||||
|
// TSDB returns datapoints has a hash of ts => value.
|
||||||
|
// Can't use _.pairs(invert()) because it stringifies keys/values
|
||||||
|
_.each(md.dps, function (v, k) {
|
||||||
|
dps.push([v, k]);
|
||||||
|
});
|
||||||
|
|
||||||
|
var target = md.metric;
|
||||||
|
if (!_.isEmpty(md.tags)) {
|
||||||
|
var tagData = [];
|
||||||
|
|
||||||
|
_.each(_.pairs(md.tags), function(tag) {
|
||||||
|
if (_.has(groupByTags, tag[0])) {
|
||||||
|
tagData.push(tag[0] + "=" + tag[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!_.isEmpty(tagData)) {
|
||||||
|
target = target + "{" + tagData.join(", ") + "}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { target: target, datapoints: dps };
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertTargetToQuery(target) {
|
||||||
|
if (!target.metric) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = {
|
||||||
|
metric: target.metric,
|
||||||
|
aggregator: "avg"
|
||||||
|
};
|
||||||
|
|
||||||
|
if (target.aggregator) {
|
||||||
|
query.aggregator = target.aggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.shouldComputeRate) {
|
||||||
|
query.rate = true;
|
||||||
|
query.rateOptions = {
|
||||||
|
counter: !!target.isCounter
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.shouldDownsample) {
|
||||||
|
query.downsample = target.downsampleInterval + "-" + target.downsampleAggregator;
|
||||||
|
}
|
||||||
|
|
||||||
|
query.tags = angular.copy(target.tags);
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertToTSDBTime(date) {
|
||||||
|
if (date === 'now') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
date = kbn.parseDate(date);
|
||||||
|
|
||||||
|
return date.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpenTSDBDatasource;
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
2
src/css/bootstrap.dark.min.css
vendored
2
src/css/bootstrap.dark.min.css
vendored
File diff suppressed because one or more lines are too long
2
src/css/bootstrap.light.min.css
vendored
2
src/css/bootstrap.light.min.css
vendored
File diff suppressed because one or more lines are too long
2
src/css/default.min.css
vendored
2
src/css/default.min.css
vendored
File diff suppressed because one or more lines are too long
@ -371,6 +371,10 @@ input[type=text].grafana-target-segment-input {
|
|||||||
padding: 8px 4px;
|
padding: 8px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input[type=checkbox].grafana-target-option-checkbox {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
select.grafana-target-segment-input {
|
select.grafana-target-segment-input {
|
||||||
border: none;
|
border: none;
|
||||||
border-right: 1px solid @grafanaTargetSegmentBorder;
|
border-right: 1px solid @grafanaTargetSegmentBorder;
|
||||||
|
Loading…
Reference in New Issue
Block a user