Merge branch 'annotations'

This commit is contained in:
Rashid Khan
2013-10-30 10:59:40 -07:00
8 changed files with 784 additions and 18 deletions
+2
View File
@@ -32,6 +32,7 @@ require.config({
'jquery.flot': '../vendor/jquery/jquery.flot',
'jquery.flot.pie': '../vendor/jquery/jquery.flot.pie',
'jquery.flot.events': '../vendor/jquery/jquery.flot.events',
'jquery.flot.selection': '../vendor/jquery/jquery.flot.selection',
'jquery.flot.stack': '../vendor/jquery/jquery.flot.stack',
'jquery.flot.stackpercent':'../vendor/jquery/jquery.flot.stackpercent',
@@ -66,6 +67,7 @@ require.config({
'jquery-ui': ['jquery'],
'jquery.flot': ['jquery'],
'jquery.flot.pie': ['jquery', 'jquery.flot'],
'jquery.flot.events': ['jquery', 'jquery.flot'],
'jquery.flot.selection':['jquery', 'jquery.flot'],
'jquery.flot.stack': ['jquery', 'jquery.flot'],
'jquery.flot.stackpercent':['jquery', 'jquery.flot'],
+92 -14
View File
@@ -37,7 +37,7 @@ define([
'./timeSeries',
'jquery.flot',
'jquery.flot.pie',
'jquery.flot.events',
'jquery.flot.selection',
'jquery.flot.time',
'jquery.flot.stack',
@@ -67,7 +67,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
},
{
title:'Queries',
src:'app/partials/querySelect.html'
src:'app/panels/histogram/queriesEditor.html'
},
],
status : "Stable",
@@ -84,6 +84,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
mode : 'all',
ids : []
},
annotate : {
enable : false,
query : "*",
size : 20,
field : '@message',
sort : ['_score','desc']
},
value_field : null,
auto_int : true,
resolution : 100,
@@ -121,6 +128,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
_.defaults($scope.panel,_d);
_.defaults($scope.panel.tooltip,_d.tooltip);
_.defaults($scope.panel.annotate,_d.annotate);
_.defaults($scope.panel.grid,_d.grid);
@@ -190,6 +198,16 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
* this call is made recursively for more segments
*/
$scope.get_data = function(segment, query_id) {
var
_range,
_interval,
request,
queries,
results;
$scope.panel.annotate.enable = true;
$scope.panel.annotate.ids = [1];
if (_.isUndefined(segment)) {
segment = 0;
}
@@ -199,8 +217,8 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
if(dashboard.indices.length === 0) {
return;
}
var _range = $scope.get_time_range();
var _interval = $scope.get_interval(_range);
_range = $scope.get_time_range();
_interval = $scope.get_interval(_range);
if ($scope.panel.auto_int) {
$scope.panel.interval = kbn.secondsToHms(
@@ -208,11 +226,11 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}
$scope.panelMeta.loading = true;
var request = $scope.ejs.Request().indices(dashboard.indices[segment]);
request = $scope.ejs.Request().indices(dashboard.indices[segment]);
$scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
var queries = querySrv.getQueryObjs($scope.panel.queries.ids);
queries = querySrv.getQueryObjs($scope.panel.queries.ids);
// Build the query
_.each(queries, function(q) {
@@ -224,7 +242,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
var facet = $scope.ejs.DateHistogramFacet(q.id);
if($scope.panel.mode === 'count') {
facet = facet.field($scope.panel.time_field);
facet = facet.field($scope.panel.time_field).global(true);
} else {
if(_.isNull($scope.panel.value_field)) {
$scope.panel.error = "In " + $scope.panel.mode + " mode a field must be specified";
@@ -233,14 +251,30 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
facet = facet.keyField($scope.panel.time_field).valueField($scope.panel.value_field);
}
facet = facet.interval(_interval).facetFilter($scope.ejs.QueryFilter(query));
request = request.facet(facet).size(0);
request = request.facet(facet)
.size($scope.panel.annotate.enable ? $scope.panel.annotate.size : 0);
});
if($scope.panel.annotate.enable) {
var query = $scope.ejs.FilteredQuery(
$scope.ejs.QueryStringQuery($scope.panel.annotate.query || '*'),
filterSrv.getBoolFilter(filterSrv.idsByType('time'))
);
request = request.query(query);
// This is a hack proposed by @boaz to work around the fact that we can't get
// to field data values directly, and we need timestamps as normalized longs
request = request.sort([
$scope.ejs.Sort($scope.panel.annotate.sort[0]).order($scope.panel.annotate.sort[1]),
$scope.ejs.Sort($scope.panel.time_field).desc()
]);
}
// Populate the inspector panel
$scope.populate_modal(request);
// Then run it
var results = request.doSearch();
results = request.doSearch();
// Populate scope when we have results
results.then(function(results) {
@@ -249,6 +283,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
if(segment === 0) {
$scope.hits = 0;
$scope.data = [];
$scope.annotations = [];
query_id = $scope.query_id = new Date().getTime();
}
@@ -298,6 +333,30 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
i++;
});
if($scope.panel.annotate.enable) {
$scope.annotations = $scope.annotations.concat(_.map(results.hits.hits, function(hit) {
var _p = _.omit(hit,'_source','sort','_score');
var _h = _.extend(kbn.flatten_json(hit._source),_p);
return {
min: hit.sort[1],
max: hit.sort[1],
eventType: "annotation",
title: null,
description: "<small><i class='icon-tag icon-flip-vertical'></i> "+
_h[$scope.panel.annotate.field]+"</small><br>"+
moment(hit.sort[1]).format('YYYY-MM-DD HH:mm:ss'),
score: hit.sort[0]
};
}));
// Sort the data
$scope.annotations = _.sortBy($scope.annotations, function(v){
// Sort in reverse
return v.score*($scope.panel.annotate.sort[1] === 'desc' ? -1 : 1);
});
// And slice to the right size
$scope.annotations = $scope.annotations.slice(0,$scope.panel.annotate.size);
}
// Tell the histogram directive to render.
$scope.$emit('render');
@@ -429,7 +488,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
bars: {
show: scope.panel.bars,
fill: 1,
barWidth: barwidth/1.8,
barWidth: barwidth/1.5,
zero: false,
lineWidth: 0
},
@@ -464,6 +523,25 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}
};
if(scope.panel.annotate.enable) {
options.events = {
levels: 1,
data: scope.annotations,
types: {
'annotation': {
level: 1,
icon: {
icon: "icon-tag icon-flip-vertical",
size: 20,
color: "#222",
outline: "#bbb"
}
}
}
//xaxis: int // the x axis to attach events to
};
}
if(scope.panel.interactive) {
options.selection = { mode: "x", color: '#666' };
}
@@ -503,13 +581,13 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
function time_format(interval) {
var _int = kbn.interval_to_seconds(interval);
if(_int >= 2628000) {
return "%m/%y";
return "%Y-%m";
}
if(_int >= 86400) {
return "%m/%d/%y";
return "%Y-%m-%d";
}
if(_int >= 60) {
return "%H:%M<br>%m/%d";
return "%H:%M<br>%m-%d";
}
return "%H:%M:%S";
@@ -534,7 +612,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
}
$tooltip
.html(
group + value + " @ " + moment(item.datapoint[0]).format('MM/DD HH:mm:ss')
group + value + " @ " + moment(item.datapoint[0]).format('YYYY-MM-DD HH:mm:ss')
)
.place_tt(pos.pageX, pos.pageY);
} else {
@@ -0,0 +1,43 @@
<h4>Charted</h4>
<div ng-include src="'app/partials/querySelect.html'"></div>
<div class="editor-row">
<h4>Markers</h4>
<div class="small">
Here you can specify a query to be plotted on your chart as a marker. Hovering over a marker will display the field you specify below. If more documents are found than the limit you set, they will be scored by Elasticsearch and events that best match your query will be displayed.
</div>
<style>
.querySelect .query {
margin-right: 5px;
}
.querySelect .selected {
border: 3px solid;
}
.querySelect .unselected {
border: 0px solid;
}
</style>
<p>
<div class="editor-option">
<label class="small">Enable</label>
<input type="checkbox" ng-change="set_refresh(true)" ng-model="panel.annotate.enable" ng-checked="panel.annotate.enable">
</div>
<div class="editor-option" ng-show="panel.annotate.enable">
<label class="small">Marker Query</label>
<input type="text" ng-change="set_refresh(true)" class="input-large" ng-model="panel.annotate.query"/>
</div>
<div class="editor-option" ng-show="panel.annotate.enable">
<label class="small">Tooltip field</label>
<input type="text" class="input-small" ng-model="panel.annotate.field" bs-typeahead="fields.list"/>
</div>
<div class="editor-option" ng-show="panel.annotate.enable">
<label class="small">Limit <tip>Max markers on the chart</tip></label>
<input type="number" class="input-mini" ng-model="panel.annotate.size" ng-change="set_refresh(true)"/>
</div>
<div class="editor-option" ng-show="panel.annotate.enable">
<label class="small">Sort <tip>Determine the most relevant markers using this field</tip></label>
<input type="text" class="input-small" bs-typeahead="fields.list" ng-model="panel.annotate.sort[0]" ng-change="set_refresh(true)" />
<i ng-click="panel.annotate.sort[1] = _.toggle(panel.annotate.sort[1],'desc','asc');set_refresh(true)" ng-class="{'icon-chevron-up': panel.annotate.sort[1] == 'asc','icon-chevron-down': panel.annotate.sort[1] == 'desc'}"></i>
</div>
</div>