Elastic search annotations are working, need to refactor and unify datasource abstraction more, #201

This commit is contained in:
Torkel Ödegaard
2014-07-29 17:24:42 +02:00
parent 4e47447dec
commit fa3b84a615
11 changed files with 126 additions and 9 deletions
+1
View File
@@ -12,6 +12,7 @@
- [Issue #610](https://github.com/grafana/grafana/issues/610). InfluxDB: Support for InfluxdB v0.8 list series response schemea (series typeahead)
- [Issue #266](https://github.com/grafana/grafana/issues/266). Graphite: New option cacheTimeout to override graphite default memcache timeout
- [Issue #606](https://github.com/grafana/grafana/issues/606). General: New global option in config.js to specify admin password (useful to hinder users from accidentally make changes)
- [Issue #201](https://github.com/grafana/grafana/issues/201). Annotations: Elasticsearch datasource support for events
**Changes**
- [Issue #536](https://github.com/grafana/grafana/issues/536). Graphite: Use unix epoch for Graphite from/to for absolute time ranges
+1 -1
View File
@@ -12,7 +12,7 @@ function (angular, app, _) {
var module = angular.module('grafana.panels.annotations', []);
app.useModule(module);
module.controller('AnnotationsEditorCtrl', function($scope, datasourceSrv, $rootScope) {
module.controller('AnnotationsEditorCtrl', function($scope, datasourceSrv) {
var annotationDefaults = {
name: '',
+1 -1
View File
@@ -27,7 +27,7 @@
<li ng-show="dashboard.loader.save_elasticsearch">
<form class="input-prepend nomargin save-dashboard-dropdown-save-form">
<input class='input-medium' ng-model="dashboard.title" type="text" ng-model="elasticsearch.title"/>
<input class='input-medium' ng-model="dashboard.title" type="text" />
<button class="btn" ng-click="saveDashboard()"><i class="icon-save"></i></button>
</form>
</li>
@@ -1 +1,39 @@
<h2>Elasticsearch</h2>
<div class="editor-row">
<div class="section">
<h5>Index name</h5>
<div class="editor-option">
<input type="text" class="span4" ng-model='currentAnnotation.index' placeholder="events-*"></input>
</div>
</div>
<div class="section">
<h5>Search query (lucene) <tip>Use [[filterName]] in query to replace part of the query with a filter value</h5>
<div class="editor-option">
<input type="text" class="span6" ng-model='currentAnnotation.query' placeholder="tags:deploy"></input>
</div>
</div>
</div>
<div class="editor-row">
<div class="section">
<h5>Field mappings</h5>
<div class="editor-option">
<label class="small">Time</label>
<input type="text" class="input-small" ng-model='currentAnnotation.timeField' placeholder="@timestamp"></input>
</div>
<div class="editor-option">
<label class="small">Title</label>
<input type="text" class="input-small" ng-model='currentAnnotation.titleField' placeholder="desc"></input>
</div>
<div class="editor-option">
<label class="small">Tags</label>
<input type="text" class="input-small" ng-model='currentAnnotation.tagsField' placeholder="tags"></input>
</div>
<div class="editor-option">
<label class="small">Text</label>
<input type="text" class="input-small" ng-model='currentAnnotation.textField' placeholder=""></input>
</div>
</div>
</div>
+1 -1
View File
@@ -64,7 +64,7 @@ define([
function addAnnotation(options) {
var tooltip = "<small><b>" + options.title + "</b><br/>";
if (options.tags) {
tooltip += (options.tags || '') + '<br/>';
tooltip += '<span class="tag label label-tag">' + (options.tags || '') + '</span><br/>';
}
if (timezone === 'browser') {
@@ -19,10 +19,87 @@ function (angular, _, $, config, kbn, moment) {
this.url = datasource.url;
this.name = datasource.name;
this.supportAnnotations = true;
this.index = datasource.index;
this.annotationEditorSrc = 'app/partials/elasticsearch/annotation_editor.html';
}
ElasticDatasource.prototype._request = function(method, url, data) {
var options = {
url: this.url + "/" + this.index + url,
method: method,
data: data
};
if (config.elasticsearchBasicAuth) {
options.headers = {
"Authorization": "Basic " + config.elasticsearchBasicAuth
};
}
return $http(options);
};
ElasticDatasource.prototype._get = function(url) {
return this._request('GET', url)
.then(function(results) {
return results.data;
});
};
ElasticDatasource.prototype._post = function(url, data) {
return this._request('POST', url, data)
.then(function(results) {
return results.data;
});
};
ElasticDatasource.prototype.annotationQuery = function(annotation, filterSrv, rangeUnparsed) {
var range = {};
var timeField = annotation.timeField || '@timestamp';
var queryString = annotation.query || '*';
var tagsField = annotation.tagsField || 'tags';
var titleField = annotation.titleField || 'desc';
var textField = annotation.textField || null;
range[annotation.timeField]= {
from: rangeUnparsed.from,
to: rangeUnparsed.to,
};
var filter = { "bool": { "must": [{ "range": range }] } };
var query = { "bool": { "should": [{ "query_string": { "query": queryString } }] } };
var data = { "query" : { "filtered": { "query" : query, "filter": filter } }, "size": 100 };
this.index = annotation.index;
return this._request('POST', '/_search', data).then(function(results) {
var list = [];
var hits = results.data.hits.hits;
for (var i = 0; i < hits.length; i++) {
var source = hits[i]._source;
var event = {
annotation: annotation,
time: moment.utc(source[timeField]).valueOf(),
title: source[titleField],
};
if (source[tagsField]) {
if (_.isArray(source[tagsField])) {
event.tags = source[tagsField].join(', ');
}
else {
event.tags = source[tagsField];
}
}
if (textField && source[textField]) {
event.text = source[textField];
}
list.push(event);
}
return list;
});
};
return ElasticDatasource;
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+3 -1
View File
@@ -128,4 +128,6 @@
}
}
.annotation-tags {
color: @purple;
}
-1
View File
@@ -12,7 +12,6 @@ module.exports = function(config) {
'app/routes/**/*.js',
'app/app.js',
'vendor/angular/**/*.js',
'vendor/elasticjs/elastic-angular-client.js'
],
dest: '<%= tempDir %>'
}