mirror of https://github.com/grafana/grafana
commit
0dd0cfeb2e
@ -0,0 +1,64 @@ |
||||
<div> |
||||
<div class="row-fluid"> |
||||
<div class="span12"> |
||||
The trends panel will give you a percentage representation of how your query |
||||
has moved in your current timespan compared a specified amount of time ago. For |
||||
example, if the time is 1:10pm, your time picker was set to "Last 10m", and the |
||||
"Time Ago" parameter was set to '1h', the panel would show how much the query |
||||
results have changed since 12:00-12:10pm |
||||
</div> |
||||
</div> |
||||
<h4>Settings</h4> |
||||
<div class="row-fluid"> |
||||
<div class="span3" ng-hide='panel.auto_int'> |
||||
<label class="small">Use Elasticsearch date math format here (eg 1m, 5m, 1d, 2w, 1y)</label> |
||||
</div> |
||||
<div class="span3"> |
||||
<label class="small">Time Ago</label> |
||||
<input type="text" class="input-small" ng-model="panel.ago"> |
||||
</div> |
||||
<div class="span2"> |
||||
<label class="small">Font Size</label> |
||||
<select class="input-small" ng-model="panel.style['font-size']" ng-options="f for f in ['7pt','8pt','9pt','10pt','12pt','14pt','16pt','18pt','20pt','24pt','28pt','32pt','36pt','42pt','48pt','52pt','60pt','72pt']"></select></span> |
||||
</div> |
||||
<div class="span3"> |
||||
<label class="small" >List Format</label> |
||||
<select class="input-small" ng-model="panel.arrangement" ng-options="f for f in ['horizontal','vertical']"></select></span> |
||||
</div> |
||||
</div> |
||||
|
||||
<h5>Queries</h5> |
||||
<div class="row-fluid"> |
||||
<div class="span3"> |
||||
<form style="margin-bottom: 0px"> |
||||
<label class="small">Label</label> |
||||
<input type="text" placeholder="New Label" style="width:70%" ng-model="newlabel"> |
||||
</form> |
||||
</div> |
||||
<div class="span8"> |
||||
<form class="input-append" style="margin-bottom: 0px"> |
||||
<label class="small">Query</label> |
||||
<input type="text" placeholder="New Query" style="width:80%" ng-model="newquery"> |
||||
<button class="btn" ng-click="add_query(newlabel,newquery);newlabel='';newquery='';set_refresh(true)"><i class="icon-plus"></i></button> |
||||
</form> |
||||
</div> |
||||
<div class="span1"> |
||||
</div> |
||||
</div> |
||||
<div class="row-fluid" ng-repeat="q in panel.query"> |
||||
<div class="span3"> |
||||
<form style="margin-bottom: 0px"> |
||||
<input type="text" style="width:70%" ng-model="q.label" ng-change="set_refresh(true)"> |
||||
</form> |
||||
</div> |
||||
<div class="span8"> |
||||
<form class="input-append" style="margin-bottom: 0px"> |
||||
<input type="text" style="width:80%" ng-model="q.query" ng-change="set_refresh(true)"> |
||||
<button class="btn" ng-click="get_data()"><i class="icon-search"></i></button> |
||||
</form> |
||||
</div> |
||||
<div class="span1"> |
||||
<i class="icon-remove pointer" ng-click="remove_query(q)"></i> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,10 @@ |
||||
<kibana-panel ng-controller='trends' ng-init="init()"> |
||||
|
||||
<div ng-style="panel.style" style="line-height:{{panel.style['font-size']}};display:inline-block;padding-right: 5px;" ng-repeat="query in data"> |
||||
<span ng-class="{'text-success': query.hits.new >= query.hits.old, 'text-error': query.hits.old > query.hits.new}" class='strong'> |
||||
<i class='large' ng-class="{'icon-caret-up': query.hits.new >= query.hits.old, 'icon-caret-down': query.hits.old > query.hits.new}"></i> {{query.percent}}% |
||||
</span> |
||||
<span class="tiny pointer light" bs-tooltip="'Then: '+query.hits.old+', Now: '+query.hits.new">({{query.label}})</span> |
||||
<br ng-show="panel.arrangement == 'vertical'"> |
||||
</div> |
||||
</kibana-panel> |
@ -0,0 +1,207 @@ |
||||
/* |
||||
|
||||
## Hits |
||||
|
||||
A variety of representations of the hits a query matches |
||||
|
||||
### Parameters |
||||
* query :: An array of queries. No labels here, just an array of strings. Maybe |
||||
there should be labels. Probably.
|
||||
* style :: A hash of css styles |
||||
* arrangement :: How should I arrange the query results? 'horizontal' or 'vertical' |
||||
* ago :: Date math formatted time to look back |
||||
### Group Events |
||||
#### Sends |
||||
* get_time :: On panel initialization get time range to query |
||||
#### Receives |
||||
* time :: An object containing the time range to use and the index(es) to query |
||||
* query :: An Array of queries, even if its only one |
||||
|
||||
*/ |
||||
angular.module('kibana.trends', []) |
||||
.controller('trends', function($scope, eventBus, kbnIndex) { |
||||
|
||||
// Set and populate defaults
|
||||
var _d = { |
||||
query : ["*"], |
||||
group : "default", |
||||
style : { "font-size": '14pt'}, |
||||
ago : '1d', |
||||
arrangement : 'vertical', |
||||
} |
||||
_.defaults($scope.panel,_d) |
||||
|
||||
$scope.init = function () { |
||||
$scope.hits = 0; |
||||
eventBus.register($scope,'time', function(event,time){ |
||||
set_time(time) |
||||
}); |
||||
eventBus.register($scope,'query', function(event, query) { |
||||
$scope.panel.query = _.map(query,function(q) { |
||||
return {query: q, label: q}; |
||||
}) |
||||
$scope.get_data(); |
||||
}); |
||||
// Now that we're all setup, request the time from our group
|
||||
eventBus.broadcast($scope.$id,$scope.panel.group,'get_time') |
||||
} |
||||
|
||||
$scope.get_data = function(segment,query_id) { |
||||
delete $scope.panel.error |
||||
$scope.panel.loading = true; |
||||
|
||||
// Make sure we have everything for the request to complete
|
||||
if(_.isUndefined($scope.index) || _.isUndefined($scope.time)) |
||||
return |
||||
|
||||
$scope.old_time = { |
||||
from : new Date($scope.time.from.getTime() - interval_to_seconds($scope.panel.ago)*1000), |
||||
to : new Date($scope.time.to.getTime() - interval_to_seconds($scope.panel.ago)*1000) |
||||
} |
||||
|
||||
var _segment = _.isUndefined(segment) ? 0 : segment |
||||
var request = $scope.ejs.Request(); |
||||
|
||||
// Build the question part of the query
|
||||
var queries = []; |
||||
_.each($scope.panel.query, function(v) { |
||||
queries.push($scope.ejs.FilteredQuery( |
||||
ejs.QueryStringQuery(v.query || '*'), |
||||
ejs.RangeFilter($scope.time.field) |
||||
.from($scope.time.from) |
||||
.to($scope.time.to)) |
||||
) |
||||
}); |
||||
|
||||
// Build the facet part
|
||||
_.each(queries, function(v) { |
||||
request = request |
||||
.facet($scope.ejs.QueryFacet("new"+_.indexOf(queries,v)) |
||||
.query(v) |
||||
).size(0) |
||||
}) |
||||
|
||||
var queries = []; |
||||
_.each($scope.panel.query, function(v) { |
||||
queries.push($scope.ejs.FilteredQuery( |
||||
ejs.QueryStringQuery(v.query || '*'), |
||||
ejs.RangeFilter($scope.time.field) |
||||
.from($scope.old_time.from) |
||||
.to($scope.old_time.to)) |
||||
) |
||||
}); |
||||
|
||||
// Build the facet part
|
||||
_.each(queries, function(v) { |
||||
request = request |
||||
.facet($scope.ejs.QueryFacet("old"+_.indexOf(queries,v)) |
||||
.query(v) |
||||
).size(0) |
||||
}) |
||||
|
||||
// TODO: Spy for hits panel
|
||||
//$scope.populate_modal(request);
|
||||
|
||||
// If we're on the first segment we need to get our indices
|
||||
if (_segment == 0) { |
||||
kbnIndex.indices( |
||||
$scope.old_time.from, |
||||
$scope.old_time.to, |
||||
$scope.time.pattern, |
||||
$scope.time.interval |
||||
).then(function (p) { |
||||
$scope.index = _.union(p,$scope.index); |
||||
process_results(request.indices($scope.index[_segment]).doSearch()); |
||||
}); |
||||
} else { |
||||
process_results(request.indices($scope.index[_segment]).doSearch()); |
||||
} |
||||
|
||||
// Populate scope when we have results
|
||||
function process_results(results) {
|
||||
results.then(function(results) { |
||||
|
||||
$scope.panel.loading = false; |
||||
if(_segment == 0) { |
||||
$scope.hits = {}; |
||||
$scope.data = []; |
||||
query_id = $scope.query_id = new Date().getTime(); |
||||
} |
||||
|
||||
// Check for error and abort if found
|
||||
if(!(_.isUndefined(results.error))) { |
||||
$scope.panel.error = $scope.parse_error(results.error); |
||||
return; |
||||
} |
||||
if($scope.query_id === query_id) { |
||||
var i = 0; |
||||
_.each($scope.panel.query, function(k) { |
||||
var n = results.facets['new'+i].count |
||||
var o = results.facets['old'+i].count |
||||
|
||||
var hits = { |
||||
new : _.isUndefined($scope.data[i]) || _segment == 0 ? n : $scope.data[i].hits.new+n,
|
||||
old : _.isUndefined($scope.data[i]) || _segment == 0 ? o : $scope.data[i].hits.old+o |
||||
} |
||||
|
||||
$scope.hits.new += n; |
||||
$scope.hits.old += o; |
||||
|
||||
var percent = Math.round(percentage(hits.old,hits.new)*100)/100 |
||||
// Create series
|
||||
$scope.data[i] = {
|
||||
label: $scope.panel.query[i].label || "query"+(parseInt(i)+1),
|
||||
hits: { |
||||
new : hits.new, |
||||
old : hits.old |
||||
}, |
||||
percent: _.isNull(percent) ? 0 : percent |
||||
}; |
||||
|
||||
i++; |
||||
}); |
||||
$scope.$emit('render'); |
||||
if(_segment < $scope.index.length-1)
|
||||
$scope.get_data(_segment+1,query_id) |
||||
|
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |
||||
|
||||
function percentage(x,y) { |
||||
return 100*(y-x)/x |
||||
} |
||||
|
||||
$scope.remove_query = function(q) { |
||||
$scope.panel.query = _.without($scope.panel.query,q); |
||||
$scope.get_data(); |
||||
} |
||||
|
||||
$scope.add_query = function(label,query) { |
||||
$scope.panel.query.unshift({ |
||||
query: query, |
||||
label: label,
|
||||
}); |
||||
$scope.get_data(); |
||||
} |
||||
|
||||
$scope.set_refresh = function (state) {
|
||||
$scope.refresh = state;
|
||||
} |
||||
|
||||
$scope.close_edit = function() { |
||||
if($scope.refresh) |
||||
$scope.get_data(); |
||||
$scope.refresh = false; |
||||
$scope.$emit('render'); |
||||
} |
||||
|
||||
function set_time(time) { |
||||
$scope.time = time; |
||||
$scope.index = time.index || $scope.index |
||||
$scope.get_data(); |
||||
} |
||||
|
||||
}) |
Loading…
Reference in new issue