influxdbDatasource.js 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. define([
  2. 'angular',
  3. 'underscore',
  4. 'kbn',
  5. './influxSeries'
  6. ],
  7. function (angular, _, kbn, InfluxSeries) {
  8. 'use strict';
  9. var module = angular.module('kibana.services');
  10. module.factory('InfluxDatasource', function($q, $http) {
  11. function InfluxDatasource(datasource) {
  12. this.type = 'influxDB';
  13. this.editorSrc = 'app/partials/influxdb/editor.html';
  14. this.urls = datasource.urls;
  15. this.username = datasource.username;
  16. this.password = datasource.password;
  17. this.name = datasource.name;
  18. this.templateSettings = {
  19. interpolate : /\[\[([\s\S]+?)\]\]/g,
  20. };
  21. this.supportAnnotations = true;
  22. this.annotationEditorSrc = 'app/partials/influxdb/annotation_editor.html';
  23. }
  24. InfluxDatasource.prototype.query = function(filterSrv, options) {
  25. var promises = _.map(options.targets, function(target) {
  26. var query;
  27. var alias = '';
  28. if (target.hide || !((target.series && target.column) || target.query)) {
  29. return [];
  30. }
  31. var timeFilter = getTimeFilter(options);
  32. var groupByField;
  33. if (target.rawQuery) {
  34. query = target.query;
  35. query = query.replace(";", "");
  36. var queryElements = query.split(" ");
  37. var lowerCaseQueryElements = query.toLowerCase().split(" ");
  38. var whereIndex = lowerCaseQueryElements.indexOf("where");
  39. var groupByIndex = lowerCaseQueryElements.indexOf("group");
  40. var orderIndex = lowerCaseQueryElements.indexOf("order");
  41. if (lowerCaseQueryElements[1].indexOf(',') !== -1) {
  42. groupByField = lowerCaseQueryElements[1].replace(',', '');
  43. }
  44. if (whereIndex !== -1) {
  45. queryElements.splice(whereIndex + 1, 0, timeFilter, "and");
  46. }
  47. else {
  48. if (groupByIndex !== -1) {
  49. queryElements.splice(groupByIndex, 0, "where", timeFilter);
  50. }
  51. else if (orderIndex !== -1) {
  52. queryElements.splice(orderIndex, 0, "where", timeFilter);
  53. }
  54. else {
  55. queryElements.push("where");
  56. queryElements.push(timeFilter);
  57. }
  58. }
  59. query = queryElements.join(" ");
  60. query = filterSrv.applyTemplateToTarget(query);
  61. }
  62. else {
  63. var template = "select [[group]][[group_comma]] [[func]]([[column]]) from [[series]] " +
  64. "where [[timeFilter]] [[condition_add]] [[condition_key]] [[condition_op]] [[condition_value]] " +
  65. "group by time([[interval]])[[group_comma]] [[group]] order asc";
  66. var templateData = {
  67. series: target.series,
  68. column: target.column,
  69. func: target.function,
  70. timeFilter: timeFilter,
  71. interval: target.interval || options.interval,
  72. condition_add: target.condition_filter ? 'and' : '',
  73. condition_key: target.condition_filter ? target.condition_key : '',
  74. condition_op: target.condition_filter ? target.condition_op : '',
  75. condition_value: target.condition_filter ? target.condition_value : '',
  76. group_comma: target.groupby_field_add && target.groupby_field ? ',' : '',
  77. group: target.groupby_field_add ? target.groupby_field : '',
  78. };
  79. if(!templateData.series.match('^/.*/')) {
  80. templateData.series = '"' + templateData.series + '"';
  81. }
  82. query = _.template(template, templateData, this.templateSettings);
  83. query = filterSrv.applyTemplateToTarget(query);
  84. if (target.groupby_field_add) {
  85. groupByField = target.groupby_field;
  86. }
  87. target.query = query;
  88. }
  89. if (target.alias) {
  90. alias = filterSrv.applyTemplateToTarget(target.alias);
  91. }
  92. var handleResponse = _.partial(handleInfluxQueryResponse, alias, groupByField);
  93. return this.doInfluxRequest(query, alias).then(handleResponse);
  94. }, this);
  95. return $q.all(promises).then(function(results) {
  96. return { data: _.flatten(results) };
  97. });
  98. };
  99. InfluxDatasource.prototype.annotationQuery = function(annotation, filterSrv, rangeUnparsed) {
  100. var timeFilter = getTimeFilter({ range: rangeUnparsed });
  101. var query = _.template(annotation.query, {
  102. timeFilter: timeFilter
  103. }, this.templateSettings);
  104. return this.doInfluxRequest(query)
  105. .then(function (results) {
  106. var list = [];
  107. _.each(results, function (series) {
  108. var descriptionCol = 0;
  109. var tagsCol = 0;
  110. _.each(series.columns, function(column, index) {
  111. if (column === 'time' || column === 'sequence_number') {
  112. return;
  113. }
  114. if (!descriptionCol) {
  115. descriptionCol = index;
  116. }
  117. else {
  118. tagsCol = index;
  119. }
  120. });
  121. _.each(series.points, function (point) {
  122. var data = {
  123. annotation: annotation,
  124. time: point[0] * 1000,
  125. description: point[descriptionCol]
  126. };
  127. if (tagsCol) {
  128. data.tags = point[tagsCol];
  129. }
  130. list.push(data);
  131. });
  132. });
  133. return list;
  134. });
  135. };
  136. InfluxDatasource.prototype.listColumns = function(seriesName) {
  137. return this.doInfluxRequest('select * from /' + seriesName + '/ limit 1').then(function(data) {
  138. if (!data) {
  139. return [];
  140. }
  141. return data[0].columns;
  142. });
  143. };
  144. InfluxDatasource.prototype.listSeries = function() {
  145. return this.doInfluxRequest('select * from /.*/ limit 1').then(function(data) {
  146. return _.map(data, function(series) {
  147. return series.name;
  148. });
  149. });
  150. };
  151. InfluxDatasource.prototype.metricFindQuery = function (filterSrv, query) {
  152. var interpolated;
  153. try {
  154. interpolated = filterSrv.applyTemplateToTarget(query);
  155. }
  156. catch (err) {
  157. return $q.reject(err);
  158. }
  159. return this.doInfluxRequest(interpolated)
  160. .then(function (results) {
  161. return _.map(results[0].points, function (metric) {
  162. return {
  163. text: metric[1],
  164. expandable: false
  165. };
  166. });
  167. });
  168. };
  169. function retry(deferred, callback, delay) {
  170. return callback().then(undefined, function(reason) {
  171. if (reason.status !== 0 || reason.status >= 300) {
  172. deferred.reject(reason);
  173. }
  174. else {
  175. setTimeout(function() {
  176. return retry(deferred, callback, Math.min(delay * 2, 30000));
  177. }, delay);
  178. }
  179. });
  180. }
  181. InfluxDatasource.prototype.doInfluxRequest = function(query) {
  182. var _this = this;
  183. var deferred = $q.defer();
  184. retry(deferred, function() {
  185. var currentUrl = _this.urls.shift();
  186. _this.urls.push(currentUrl);
  187. var params = {
  188. u: _this.username,
  189. p: _this.password,
  190. time_precision: 's',
  191. q: query
  192. };
  193. var options = {
  194. method: 'GET',
  195. url: currentUrl + '/series',
  196. params: params,
  197. };
  198. return $http(options).success(function (data) {
  199. deferred.resolve(data);
  200. });
  201. }, 10);
  202. return deferred.promise;
  203. };
  204. function handleInfluxQueryResponse(alias, groupByField, seriesList) {
  205. var influxSeries = new InfluxSeries({
  206. seriesList: seriesList,
  207. alias: alias,
  208. groupByField: groupByField
  209. });
  210. return influxSeries.getTimeSeries();
  211. }
  212. function getTimeFilter(options) {
  213. var from = getInfluxTime(options.range.from);
  214. var until = getInfluxTime(options.range.to);
  215. if (until === 'now()') {
  216. return 'time > now() - ' + from;
  217. }
  218. return 'time > ' + from + ' and time < ' + until;
  219. }
  220. function getInfluxTime(date) {
  221. if (_.isString(date)) {
  222. if (date === 'now') {
  223. return 'now()';
  224. }
  225. else if (date.indexOf('now') >= 0) {
  226. return date.substring(4);
  227. }
  228. date = kbn.parseDate(date);
  229. }
  230. return to_utc_epoch_seconds(date);
  231. }
  232. function to_utc_epoch_seconds(date) {
  233. return (date.getTime() / 1000).toFixed(0) + 's';
  234. }
  235. return InfluxDatasource;
  236. });
  237. });