mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
feat(elasticsearch): small progress on new elasticsearch metric query capability
This commit is contained in:
@@ -19,17 +19,9 @@ function (angular, _) {
|
||||
$scope.target.region = $scope.target.region || $scope.datasource.getDefaultRegion();
|
||||
$scope.target.errors = validateTarget();
|
||||
|
||||
$scope.regionSegment = $scope.getSegmentForValue($scope.target.region, 'select region');
|
||||
$scope.namespaceSegment = $scope.getSegmentForValue($scope.target.namespace, 'select namespace');
|
||||
$scope.metricSegment = $scope.getSegmentForValue($scope.target.metricName, 'select metric');
|
||||
};
|
||||
|
||||
$scope.getSegmentForValue = function(value, fallbackText) {
|
||||
if (value) {
|
||||
return uiSegmentSrv.newSegment(value);
|
||||
} else {
|
||||
return uiSegmentSrv.newSegment({value: fallbackText, fake: true});
|
||||
}
|
||||
$scope.regionSegment = uiSegmentSrv.getSegmentForValue($scope.target.region, 'select region');
|
||||
$scope.namespaceSegment = uiSegmentSrv.getSegmentForValue($scope.target.namespace, 'select namespace');
|
||||
$scope.metricSegment = uiSegmentSrv.getSegmentForValue($scope.target.metricName, 'select metric');
|
||||
};
|
||||
|
||||
$scope.getRegions = function() {
|
||||
|
||||
@@ -138,13 +138,21 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
|
||||
var queryBuilder = new ElasticQueryBuilder;
|
||||
var query = queryBuilder.build(options.targets);
|
||||
query = query.replace(/\$interval/g, options.interval);
|
||||
query = query.replace(/\$rangeFrom/g, options.range.from);
|
||||
query = query.replace(/\$rangeTo/g, options.range.to);
|
||||
query = query.replace(/\$rangeFrom/g, this.translateTime(options.range.from));
|
||||
query = query.replace(/\$rangeTo/g, this.translateTime(options.range.to));
|
||||
query = query.replace(/\$maxDataPoints/g, options.maxDataPoints);
|
||||
query = templateSrv.replace(query, options.scopedVars);
|
||||
return this._post('/_search?search_type=count', query).then(this._getTimeSeries);
|
||||
};
|
||||
|
||||
ElasticDatasource.prototype.translateTime = function(date) {
|
||||
if (_.isString(date)) {
|
||||
return date;
|
||||
}
|
||||
|
||||
return date.toJSON();
|
||||
};
|
||||
|
||||
ElasticDatasource.prototype._getTimeSeries = function(results) {
|
||||
var _aggregation2timeSeries = function(aggregation) {
|
||||
var datapoints = aggregation.date_histogram.buckets.map(function(entry) {
|
||||
@@ -169,6 +177,26 @@ function (angular, _, config, kbn, moment, ElasticQueryBuilder) {
|
||||
return { data: data };
|
||||
};
|
||||
|
||||
ElasticDatasource.prototype.metricFindQuery = function(query) {
|
||||
var region;
|
||||
var namespace;
|
||||
var metricName;
|
||||
|
||||
var transformSuggestData = function(suggestData) {
|
||||
return _.map(suggestData, function(v) {
|
||||
return { text: v };
|
||||
});
|
||||
};
|
||||
|
||||
var d = $q.defer();
|
||||
|
||||
var regionQuery = query.match(/^region\(\)/);
|
||||
if (regionQuery) {
|
||||
d.resolve(transformSuggestData(this.performSuggestRegion()));
|
||||
return d.promise;
|
||||
}
|
||||
};
|
||||
|
||||
return ElasticDatasource;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,32 +37,12 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<input type="text" class="tight-form-clear-input" style="width: 80%" ng-model="target.query" focus-me="target.rawQuery" spellcheck='false' ng-model-onblur ng-change="get_data()" ng-show="target.rawQuery"/>
|
||||
|
||||
<ul class="tight-form-list" role="menu" ng-hide="target.rawQuery">
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
Function
|
||||
</li>
|
||||
<li class="dropdown tight-form-item">
|
||||
<a gf-dropdown="functionMenu" class="dropdown-toggle" data-toggle="dropdown">
|
||||
{{target.function}}<span>(value)</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
<div class="tight-form" ng-hide="target.rawQuery">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
Key Field
|
||||
<li class="tight-form-item query-keyword">
|
||||
Timestamp field
|
||||
</li>
|
||||
<li>
|
||||
<metric-segment segment="keyFieldSegment" on-value-changed="keyFieldChanged()"></metric-segment>
|
||||
<metric-segment segment="timestampSegment" get-alt-segments="getFields()" on-value-changed="timestampChanged()"></metric-segment>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -71,14 +51,11 @@
|
||||
|
||||
<div class="tight-form" ng-hide="target.rawQuery">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
Value Field
|
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||
Value field
|
||||
</li>
|
||||
<li>
|
||||
<metric-segment segment="valueFieldSegment" on-value-changed="valueFieldChanged()"></metric-segment>
|
||||
<metric-segment segment="valueFieldSegment" get-alt-segments="getFields()" on-value-changed="valueFieldChanged()"></metric-segment>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -87,11 +64,7 @@
|
||||
|
||||
<div class="tight-form" ng-hide="target.rawQuery">
|
||||
<ul class="tight-form-list">
|
||||
<li class="tight-form-item">
|
||||
<i class="fa fa-eye invisible"></i>
|
||||
</li>
|
||||
|
||||
<li class="tight-form-item query-keyword" style="width: 75px;">
|
||||
<li class="tight-form-item query-keyword tight-form-align" style="width: 75px;">
|
||||
Term
|
||||
</li>
|
||||
|
||||
|
||||
@@ -3,52 +3,55 @@ define([
|
||||
function () {
|
||||
'use strict';
|
||||
|
||||
function ElasticQueryBuilder() {
|
||||
}
|
||||
function ElasticQueryBuilder() { }
|
||||
|
||||
ElasticQueryBuilder.prototype.build = function(targets) {
|
||||
var query = {
|
||||
"aggs": {},
|
||||
"size": "$maxDataPoints"
|
||||
};
|
||||
|
||||
var self = this;
|
||||
targets.forEach(function(target) {
|
||||
if (!target.hide) {
|
||||
query["aggs"][target.termKey + "_" + target.termValue] = {
|
||||
"filter": {
|
||||
"and": [
|
||||
self._buildRangeFilter(target),
|
||||
self._buildTermFilter(target)
|
||||
]
|
||||
},
|
||||
"aggs": {
|
||||
targets.forEach(function(target, index) {
|
||||
if (target.hide) {
|
||||
return;
|
||||
}
|
||||
|
||||
var esQuery = {
|
||||
"filter": {
|
||||
"and": [
|
||||
self._buildRangeFilter(target)
|
||||
]
|
||||
},
|
||||
"aggs": {
|
||||
"date_histogram": {
|
||||
"date_histogram": {
|
||||
"date_histogram": {
|
||||
"interval": target.interval || "$interval",
|
||||
"field": target.keyField,
|
||||
"min_doc_count": 0,
|
||||
},
|
||||
"aggs": {
|
||||
"interval": target.interval || "$interval",
|
||||
"field": target.timestampField,
|
||||
"min_doc_count": 0,
|
||||
},
|
||||
"aggs": {
|
||||
"stats": {
|
||||
"stats": {
|
||||
"stats": {
|
||||
"field": target.valueField
|
||||
}
|
||||
"field": target.valueField
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (target.groupByField) {
|
||||
query["aggs"][target.termKey + "_" + target.termValue]["aggs"] = {
|
||||
"terms": {
|
||||
"terms": {
|
||||
"field": target.groupByField
|
||||
},
|
||||
"aggs": query["aggs"][target.termKey + "_" + target.termValue]["aggs"]
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
if (target.groupByField) {
|
||||
query["aggs"][target.termKey + "_" + target.termValue]["aggs"] = {
|
||||
"terms": {
|
||||
"terms": {
|
||||
"field": target.groupByField
|
||||
},
|
||||
"aggs": query["aggs"][target.termKey + "_" + target.termValue]["aggs"]
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
query["aggs"]['query:' + index] = esQuery;
|
||||
});
|
||||
query = JSON.stringify(query);
|
||||
return query;
|
||||
@@ -56,7 +59,7 @@ function () {
|
||||
|
||||
ElasticQueryBuilder.prototype._buildRangeFilter = function(target) {
|
||||
var filter = {"range":{}};
|
||||
filter["range"][target.keyField] = {
|
||||
filter["range"][target.timestampField] = {
|
||||
"gte": "$rangeFrom",
|
||||
"lte": "$rangeTo"
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ function (angular, _, ElasticQueryBuilder) {
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('ElasticQueryCtrl', function($scope, $timeout, $sce, templateSrv, $q) {
|
||||
module.controller('ElasticQueryCtrl', function($scope, $timeout, uiSegmentSrv, templateSrv, $q) {
|
||||
|
||||
$scope.functionList = ['count', 'min', 'max', 'total', 'mean'];
|
||||
|
||||
@@ -17,63 +17,40 @@ function (angular, _, ElasticQueryBuilder) {
|
||||
});
|
||||
|
||||
$scope.init = function() {
|
||||
var target = $scope.target;
|
||||
target.function = target.function || 'mean';
|
||||
|
||||
$scope.queryBuilder = new ElasticQueryBuilder(target);
|
||||
|
||||
if (!target.keyField) {
|
||||
target.keyField = '@timestamp';
|
||||
}
|
||||
$scope.keyFieldSegment = new MetricSegment({value: target.keyField});
|
||||
var target = $scope.target;
|
||||
target.function = target.function || 'mean';
|
||||
target.timestampField = target.timestampField || '@timestamp';
|
||||
target.valueField = target.valueField || 'value' ;
|
||||
|
||||
if (!target.valueField) {
|
||||
target.valueField = 'metric';
|
||||
}
|
||||
$scope.valueFieldSegment = new MetricSegment({value: target.valueField});
|
||||
$scope.timestampSegment = uiSegmentSrv.newSegment(target.timestampField);
|
||||
$scope.valueFieldSegment = uiSegmentSrv.newSegment(target.valueField);
|
||||
|
||||
if (!target.termKey) {
|
||||
target.termKey = 'service.raw';
|
||||
}
|
||||
$scope.termKeySegment = new MetricSegment({value: target.termKey});
|
||||
$scope.termKeySegment = uiSegmentSrv.getSegmentForValue(target.termKey, 'select term field');
|
||||
$scope.termValueSegment = uiSegmentSrv.getSegmentForValue(target.termValue, 'select term value');
|
||||
$scope.groupByFieldSegment = uiSegmentSrv.getSegmentForValue(target.groupByField, 'add group by');
|
||||
};
|
||||
|
||||
if (!target.termValue) {
|
||||
target.termValue = 'cpu-average/cpu-user';
|
||||
}
|
||||
$scope.termValueSegment = new MetricSegment({value: target.termValue});
|
||||
$scope.getFields = function() {
|
||||
return $scope.datasource.metricFindQuery('fields()')
|
||||
.then($scope.transformToSegments(true));
|
||||
};
|
||||
|
||||
if (!target.groupByField) {
|
||||
target.groupByField = 'host.raw';
|
||||
}
|
||||
$scope.groupByFieldSegment = new MetricSegment({value: target.groupByField});
|
||||
$scope.transformToSegments = function(addTemplateVars) {
|
||||
return function(results) {
|
||||
var segments = _.map(results, function(segment) {
|
||||
return uiSegmentSrv.newSegment({ value: segment.text, expandable: segment.expandable });
|
||||
});
|
||||
|
||||
if (!target.measurement) {
|
||||
$scope.measurementSegment = MetricSegment.newSelectMeasurement();
|
||||
} else {
|
||||
$scope.measurementSegment = new MetricSegment(target.measurement);
|
||||
}
|
||||
|
||||
$scope.tagSegments = [];
|
||||
_.each(target.tags, function(tag) {
|
||||
if (tag.condition) {
|
||||
$scope.tagSegments.push(MetricSegment.newCondition(tag.condition));
|
||||
if (addTemplateVars) {
|
||||
_.each(templateSrv.variables, function(variable) {
|
||||
segments.unshift(uiSegmentSrv.newSegment({ type: 'template', value: '$' + variable.name, expandable: true }));
|
||||
});
|
||||
}
|
||||
$scope.tagSegments.push(new MetricSegment({value: tag.key, type: 'key', cssClass: 'query-segment-key' }));
|
||||
$scope.tagSegments.push(new MetricSegment.newOperator("="));
|
||||
$scope.tagSegments.push(new MetricSegment({value: tag.value, type: 'value', cssClass: 'query-segment-value'}));
|
||||
});
|
||||
|
||||
$scope.fixTagSegments();
|
||||
|
||||
$scope.groupBySegments = [];
|
||||
_.each(target.groupByTags, function(tag) {
|
||||
$scope.groupBySegments.push(new MetricSegment(tag));
|
||||
});
|
||||
|
||||
$scope.groupBySegments.push(MetricSegment.newPlusButton());
|
||||
|
||||
$scope.removeTagFilterSegment = new MetricSegment({fake: true, value: '-- remove tag filter --'});
|
||||
$scope.removeGroupBySegment = new MetricSegment({fake: true, value: '-- remove group by --'});
|
||||
return segments;
|
||||
};
|
||||
};
|
||||
|
||||
$scope.valueFieldChanged = function() {
|
||||
@@ -101,48 +78,11 @@ function (angular, _, ElasticQueryBuilder) {
|
||||
$scope.$parent.get_data();
|
||||
};
|
||||
|
||||
$scope.fixTagSegments = function() {
|
||||
var count = $scope.tagSegments.length;
|
||||
var lastSegment = $scope.tagSegments[Math.max(count-1, 0)];
|
||||
|
||||
if (!lastSegment || lastSegment.type !== 'plus-button') {
|
||||
$scope.tagSegments.push(MetricSegment.newPlusButton());
|
||||
}
|
||||
};
|
||||
|
||||
$scope.groupByTagUpdated = function(segment, index) {
|
||||
if (segment.value === $scope.removeGroupBySegment.value) {
|
||||
$scope.target.groupByTags.splice(index, 1);
|
||||
$scope.groupBySegments.splice(index, 1);
|
||||
$scope.$parent.get_data();
|
||||
return;
|
||||
}
|
||||
|
||||
if (index === $scope.groupBySegments.length-1) {
|
||||
$scope.groupBySegments.push(MetricSegment.newPlusButton());
|
||||
}
|
||||
|
||||
segment.type = 'group-by-key';
|
||||
segment.fake = false;
|
||||
|
||||
$scope.target.groupByTags[index] = segment.value;
|
||||
$scope.$parent.get_data();
|
||||
};
|
||||
|
||||
$scope.changeFunction = function(func) {
|
||||
$scope.target.function = func;
|
||||
$scope.$parent.get_data();
|
||||
};
|
||||
|
||||
$scope.measurementChanged = function() {
|
||||
$scope.target.measurement = $scope.measurementSegment.value;
|
||||
$scope.$parent.get_data();
|
||||
};
|
||||
|
||||
$scope.toggleQueryMode = function () {
|
||||
$scope.target.rawQuery = !$scope.target.rawQuery;
|
||||
};
|
||||
|
||||
$scope.handleQueryError = function(err) {
|
||||
$scope.parserError = err.message || 'Failed to issue metric query';
|
||||
return [];
|
||||
|
||||
@@ -32,6 +32,14 @@ function (angular, _) {
|
||||
this.html = options.html || $sce.trustAsHtml(templateSrv.highlightVariablesAsHtml(this.value));
|
||||
}
|
||||
|
||||
this.getSegmentForValue = function(value, fallbackText) {
|
||||
if (value) {
|
||||
return this.newSegment(value);
|
||||
} else {
|
||||
return this.newSegment({value: fallbackText, fake: true});
|
||||
}
|
||||
};
|
||||
|
||||
this.newSelectMeasurement = function() {
|
||||
return new MetricSegment({value: 'select measurement', fake: true});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user