Elastic search annotations are working, need to refactor and unify datasource abstraction more, #201
This commit is contained in:
@@ -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 #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 #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 #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**
|
**Changes**
|
||||||
- [Issue #536](https://github.com/grafana/grafana/issues/536). Graphite: Use unix epoch for Graphite from/to for absolute time ranges
|
- [Issue #536](https://github.com/grafana/grafana/issues/536). Graphite: Use unix epoch for Graphite from/to for absolute time ranges
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function (angular, app, _) {
|
|||||||
var module = angular.module('grafana.panels.annotations', []);
|
var module = angular.module('grafana.panels.annotations', []);
|
||||||
app.useModule(module);
|
app.useModule(module);
|
||||||
|
|
||||||
module.controller('AnnotationsEditorCtrl', function($scope, datasourceSrv, $rootScope) {
|
module.controller('AnnotationsEditorCtrl', function($scope, datasourceSrv) {
|
||||||
|
|
||||||
var annotationDefaults = {
|
var annotationDefaults = {
|
||||||
name: '',
|
name: '',
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
<li ng-show="dashboard.loader.save_elasticsearch">
|
<li ng-show="dashboard.loader.save_elasticsearch">
|
||||||
<form class="input-prepend nomargin save-dashboard-dropdown-save-form">
|
<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>
|
<button class="btn" ng-click="saveDashboard()"><i class="icon-save"></i></button>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</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>
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ define([
|
|||||||
function addAnnotation(options) {
|
function addAnnotation(options) {
|
||||||
var tooltip = "<small><b>" + options.title + "</b><br/>";
|
var tooltip = "<small><b>" + options.title + "</b><br/>";
|
||||||
if (options.tags) {
|
if (options.tags) {
|
||||||
tooltip += (options.tags || '') + '<br/>';
|
tooltip += '<span class="tag label label-tag">' + (options.tags || '') + '</span><br/>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timezone === 'browser') {
|
if (timezone === 'browser') {
|
||||||
|
|||||||
@@ -19,10 +19,87 @@ function (angular, _, $, config, kbn, moment) {
|
|||||||
this.url = datasource.url;
|
this.url = datasource.url;
|
||||||
this.name = datasource.name;
|
this.name = datasource.name;
|
||||||
this.supportAnnotations = true;
|
this.supportAnnotations = true;
|
||||||
|
this.index = datasource.index;
|
||||||
this.annotationEditorSrc = 'app/partials/elasticsearch/annotation_editor.html';
|
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) {
|
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;
|
return ElasticDatasource;
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -128,4 +128,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.annotation-tags {
|
||||||
|
color: @purple;
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ module.exports = function(config) {
|
|||||||
'app/routes/**/*.js',
|
'app/routes/**/*.js',
|
||||||
'app/app.js',
|
'app/app.js',
|
||||||
'vendor/angular/**/*.js',
|
'vendor/angular/**/*.js',
|
||||||
'vendor/elasticjs/elastic-angular-client.js'
|
|
||||||
],
|
],
|
||||||
dest: '<%= tempDir %>'
|
dest: '<%= tempDir %>'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user