influxdbDatasource.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. define([
  2. 'angular',
  3. 'underscore',
  4. 'kbn'
  5. ],
  6. function (angular, _, kbn) {
  7. 'use strict';
  8. var module = angular.module('kibana.services');
  9. module.factory('InfluxDatasource', function($q, $http, filterSrv) {
  10. function InfluxDatasource(datasource) {
  11. this.type = 'influxDB';
  12. this.editorSrc = 'app/partials/influxdb/editor.html';
  13. this.urls = datasource.urls;
  14. this.username = datasource.username;
  15. this.password = datasource.password;
  16. this.name = datasource.name;
  17. this.templateSettings = {
  18. interpolate : /\[\[([\s\S]+?)\]\]/g,
  19. };
  20. }
  21. InfluxDatasource.prototype.query = function(options) {
  22. var promises = _.map(options.targets, function(target) {
  23. var query;
  24. if (target.hide || !((target.series && target.column) || target.query)) {
  25. return [];
  26. }
  27. var timeFilter = getTimeFilter(options);
  28. if (target.rawQuery) {
  29. query = target.query;
  30. query = query.replace(";", "");
  31. var queryElements = query.split(" ");
  32. var lowerCaseQueryElements = query.toLowerCase().split(" ");
  33. var whereIndex = lowerCaseQueryElements.indexOf("where");
  34. var groupByIndex = lowerCaseQueryElements.indexOf("group");
  35. var orderIndex = lowerCaseQueryElements.indexOf("order");
  36. if (whereIndex !== -1) {
  37. queryElements.splice(whereIndex+1, 0, timeFilter, "and");
  38. }
  39. else {
  40. if (groupByIndex !== -1) {
  41. queryElements.splice(groupByIndex, 0, "where", timeFilter);
  42. }
  43. else if (orderIndex !== -1) {
  44. queryElements.splice(orderIndex, 0, "where", timeFilter);
  45. }
  46. else {
  47. queryElements.push("where");
  48. queryElements.push(timeFilter);
  49. }
  50. }
  51. query = queryElements.join(" ");
  52. query = filterSrv.applyFilterToTarget(query);
  53. }
  54. else {
  55. var template = "select [[func]](\"[[column]]\") as \"[[column]]_[[func]]\" from [[series]] " +
  56. "where [[timeFilter]] [[condition_add]] [[condition_key]] [[condition_op]] [[condition_value]] " +
  57. "group by time([[interval]]) order asc";
  58. var templateData = {
  59. series: target.series,
  60. column: target.column,
  61. func: target.function,
  62. timeFilter: timeFilter,
  63. interval: target.interval || options.interval,
  64. condition_add: target.condiction_filter ? target.condition_add : '',
  65. condition_key: target.condiction_filter ? target.condition_key : '',
  66. condition_op: target.condiction_filter ? target.condition_op : '',
  67. condition_value: target.condiction_filter ? target.condition_value: ''
  68. };
  69. query = _.template(template, templateData, this.templateSettings);
  70. query = filterSrv.applyFilterToTarget(query);
  71. target.query = query;
  72. }
  73. return this.doInfluxRequest(query, target.alias).then(handleInfluxQueryResponse);
  74. }, this);
  75. return $q.all(promises).then(function(results) {
  76. return { data: _.flatten(results) };
  77. });
  78. };
  79. InfluxDatasource.prototype.listColumns = function(seriesName) {
  80. return this.doInfluxRequest('select * from ' + seriesName + ' limit 1').then(function(data) {
  81. if (!data) {
  82. return [];
  83. }
  84. return data[0].columns;
  85. });
  86. };
  87. InfluxDatasource.prototype.listSeries = function() {
  88. return this.doInfluxRequest('list series').then(function(data) {
  89. return _.map(data, function(series) {
  90. return series.name;
  91. });
  92. });
  93. };
  94. InfluxDatasource.prototype.metricFindQuery = function (query) {
  95. var interpolated;
  96. try {
  97. interpolated = filterSrv.applyFilterToTarget(query);
  98. }
  99. catch(err) {
  100. return $q.reject(err);
  101. }
  102. return this.doInfluxRequest(query, 'filters')
  103. .then(function (results) {
  104. return _.map(results[0].points, function (metric) {
  105. return {
  106. text: metric[1],
  107. expandable: false
  108. };
  109. });
  110. });
  111. };
  112. function retry(deferred, callback, delay) {
  113. return callback().then(undefined, function(reason) {
  114. if (reason.status !== 0) {
  115. deferred.reject(reason);
  116. }
  117. setTimeout(function() {
  118. return retry(deferred, callback, Math.min(delay * 2, 30000));
  119. }, delay);
  120. });
  121. }
  122. InfluxDatasource.prototype.doInfluxRequest = function(query, alias) {
  123. var _this = this;
  124. var deferred = $q.defer();
  125. retry(deferred, function() {
  126. var currentUrl = _this.urls.shift();
  127. _this.urls.push(currentUrl);
  128. var params = {
  129. u: _this.username,
  130. p: _this.password,
  131. q: query
  132. };
  133. var options = {
  134. method: 'GET',
  135. url: currentUrl + '/series',
  136. params: params,
  137. };
  138. return $http(options).success(function (data) {
  139. data.alias = alias;
  140. deferred.resolve(data);
  141. });
  142. }, 10);
  143. return deferred.promise;
  144. };
  145. function handleInfluxQueryResponse(data) {
  146. var output = [];
  147. _.each(data, function(series) {
  148. var timeCol = series.columns.indexOf('time');
  149. _.each(series.columns, function(column, index) {
  150. if (column === "time" || column === "sequence_number") {
  151. return;
  152. }
  153. var target = data.alias || series.name + "." + column;
  154. var datapoints = [];
  155. for(var i = 0; i < series.points.length; i++) {
  156. var t = Math.floor(series.points[i][timeCol] / 1000);
  157. var v = series.points[i][index];
  158. datapoints[i] = [v,t];
  159. }
  160. output.push({ target:target, datapoints:datapoints });
  161. });
  162. });
  163. return output;
  164. }
  165. function getTimeFilter(options) {
  166. var from = getInfluxTime(options.range.from);
  167. var until = getInfluxTime(options.range.to);
  168. if (until === 'now()') {
  169. return 'time > now() - ' + from;
  170. }
  171. return 'time > ' + from + ' and time < ' + until;
  172. }
  173. function getInfluxTime(date) {
  174. if (_.isString(date)) {
  175. if (date === 'now') {
  176. return 'now()';
  177. }
  178. else if (date.indexOf('now') >= 0) {
  179. return date.substring(4);
  180. }
  181. date = kbn.parseDate(date);
  182. }
  183. return to_utc_epoch_seconds(date);
  184. }
  185. function to_utc_epoch_seconds(date) {
  186. return (date.getTime() / 1000).toFixed(0) + 's';
  187. }
  188. return InfluxDatasource;
  189. });
  190. });