فهرست منبع

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

Torkel Ödegaard 11 سال پیش
والد
کامیت
fa3b84a615

+ 1 - 0
CHANGELOG.md

@@ -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
src/app/panels/annotations/editor.js

@@ -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
src/app/partials/dashLoader.html

@@ -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>

+ 39 - 1
src/app/partials/elasticsearch/annotation_editor.html

@@ -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
src/app/services/annotationsSrv.js

@@ -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') {

+ 77 - 0
src/app/services/elasticsearch/es-datasource.js

@@ -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;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
src/css/bootstrap.dark.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
src/css/bootstrap.light.min.css


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
src/css/default.min.css


+ 3 - 1
src/css/less/graph.less

@@ -128,4 +128,6 @@
   }
 }
 
-
+.annotation-tags {
+  color: @purple;
+}

+ 0 - 1
tasks/options/ngmin.js

@@ -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 %>'
     }

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است