influxdbDatasource.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  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.alias) {
  85. alias = filterSrv.applyTemplateToTarget(target.alias);
  86. }
  87. if (target.groupby_field_add) {
  88. groupByField = target.groupby_field;
  89. }
  90. target.query = query;
  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.listColumns = function(seriesName) {
  100. return this.doInfluxRequest('select * from /' + seriesName + '/ limit 1').then(function(data) {
  101. if (!data) {
  102. return [];
  103. }
  104. return data[0].columns;
  105. });
  106. };
  107. InfluxDatasource.prototype.listSeries = function() {
  108. return this.doInfluxRequest('list series').then(function(data) {
  109. return _.map(data, function(series) {
  110. return series.name;
  111. });
  112. });
  113. };
  114. InfluxDatasource.prototype.metricFindQuery = function (filterSrv, query) {
  115. var interpolated;
  116. try {
  117. interpolated = filterSrv.applyTemplateToTarget(query);
  118. }
  119. catch (err) {
  120. return $q.reject(err);
  121. }
  122. return this.doInfluxRequest(query)
  123. .then(function (results) {
  124. return _.map(results[0].points, function (metric) {
  125. return {
  126. text: metric[1],
  127. expandable: false
  128. };
  129. });
  130. });
  131. };
  132. function retry(deferred, callback, delay) {
  133. return callback().then(undefined, function(reason) {
  134. if (reason.status !== 0 || reason.status >= 300) {
  135. deferred.reject(reason);
  136. }
  137. else {
  138. setTimeout(function() {
  139. return retry(deferred, callback, Math.min(delay * 2, 30000));
  140. }, delay);
  141. }
  142. });
  143. }
  144. InfluxDatasource.prototype.doInfluxRequest = function(query) {
  145. var _this = this;
  146. var deferred = $q.defer();
  147. retry(deferred, function() {
  148. var currentUrl = _this.urls.shift();
  149. _this.urls.push(currentUrl);
  150. var params = {
  151. u: _this.username,
  152. p: _this.password,
  153. time_precision: 's',
  154. q: query
  155. };
  156. var options = {
  157. method: 'GET',
  158. url: currentUrl + '/series',
  159. params: params,
  160. };
  161. return $http(options).success(function (data) {
  162. deferred.resolve(data);
  163. });
  164. }, 10);
  165. return deferred.promise;
  166. };
  167. function handleInfluxQueryResponse(alias, groupByField, seriesList) {
  168. var influxSeries = new InfluxSeries({
  169. seriesList: seriesList,
  170. alias: alias,
  171. groupByField: groupByField
  172. });
  173. return influxSeries.getTimeSeries();
  174. }
  175. function getTimeFilter(options) {
  176. var from = getInfluxTime(options.range.from);
  177. var until = getInfluxTime(options.range.to);
  178. if (until === 'now()') {
  179. return 'time > now() - ' + from;
  180. }
  181. return 'time > ' + from + ' and time < ' + until;
  182. }
  183. function getInfluxTime(date) {
  184. if (_.isString(date)) {
  185. if (date === 'now') {
  186. return 'now()';
  187. }
  188. else if (date.indexOf('now') >= 0) {
  189. return date.substring(4);
  190. }
  191. date = kbn.parseDate(date);
  192. }
  193. return to_utc_epoch_seconds(date);
  194. }
  195. function to_utc_epoch_seconds(date) {
  196. return (date.getTime() / 1000).toFixed(0) + 's';
  197. }
  198. return InfluxDatasource;
  199. });
  200. });