datasource.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. ///<reference path="../../../headers/common.d.ts" />
  2. import angular from 'angular';
  3. import _ from 'lodash';
  4. import * as dateMath from 'app/core/utils/datemath';
  5. import InfluxSeries from './influx_series';
  6. import InfluxQuery from './influx_query';
  7. /** @ngInject */
  8. export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv) {
  9. this.type = 'influxdb';
  10. this.urls = _.map(instanceSettings.url.split(','), function(url) {
  11. return url.trim();
  12. });
  13. this.username = instanceSettings.username;
  14. this.password = instanceSettings.password;
  15. this.name = instanceSettings.name;
  16. this.database = instanceSettings.database;
  17. this.basicAuth = instanceSettings.basicAuth;
  18. this.supportAnnotations = true;
  19. this.supportMetrics = true;
  20. this.query = function(options) {
  21. var timeFilter = getTimeFilter(options);
  22. var queryTargets = [];
  23. var i, y;
  24. var allQueries = _.map(options.targets, function(target) {
  25. if (target.hide) { return []; }
  26. queryTargets.push(target);
  27. // build query
  28. var queryModel = new InfluxQuery(target);
  29. var query = queryModel.render();
  30. query = query.replace(/\$interval/g, (target.interval || options.interval));
  31. return query;
  32. }).join("\n");
  33. // replace grafana variables
  34. allQueries = allQueries.replace(/\$timeFilter/g, timeFilter);
  35. // replace templated variables
  36. allQueries = templateSrv.replace(allQueries, options.scopedVars);
  37. return this._seriesQuery(allQueries).then(function(data): any {
  38. if (!data || !data.results) {
  39. return [];
  40. }
  41. var seriesList = [];
  42. for (i = 0; i < data.results.length; i++) {
  43. var result = data.results[i];
  44. if (!result || !result.series) { continue; }
  45. var target = queryTargets[i];
  46. var alias = target.alias;
  47. if (alias) {
  48. alias = templateSrv.replace(target.alias, options.scopedVars);
  49. }
  50. var influxSeries = new InfluxSeries({ series: data.results[i].series, alias: alias });
  51. switch (target.resultFormat) {
  52. case 'table': {
  53. seriesList.push(influxSeries.getTable());
  54. break;
  55. }
  56. default: {
  57. var timeSeries = influxSeries.getTimeSeries();
  58. for (y = 0; y < timeSeries.length; y++) {
  59. seriesList.push(timeSeries[y]);
  60. }
  61. break;
  62. }
  63. }
  64. }
  65. return { data: seriesList };
  66. });
  67. };
  68. this.annotationQuery = function(options) {
  69. var timeFilter = getTimeFilter({rangeRaw: options.rangeRaw});
  70. var query = options.annotation.query.replace('$timeFilter', timeFilter);
  71. query = templateSrv.replace(query);
  72. return this._seriesQuery(query).then(function(data) {
  73. if (!data || !data.results || !data.results[0]) {
  74. throw { message: 'No results in response from InfluxDB' };
  75. }
  76. return new InfluxSeries({series: data.results[0].series, annotation: options.annotation}).getAnnotations();
  77. });
  78. };
  79. this.metricFindQuery = function (query) {
  80. var interpolated;
  81. try {
  82. interpolated = templateSrv.replace(query);
  83. } catch (err) {
  84. return $q.reject(err);
  85. }
  86. return this._seriesQuery(interpolated).then(function (results) {
  87. if (!results || results.results.length === 0) { return []; }
  88. var influxResults = results.results[0];
  89. if (!influxResults.series) {
  90. return [];
  91. }
  92. var series = influxResults.series[0];
  93. return _.map(series.values, function(value) {
  94. if (_.isArray(value)) {
  95. return { text: value[0] };
  96. } else {
  97. return { text: value };
  98. }
  99. });
  100. });
  101. };
  102. this._seriesQuery = function(query) {
  103. return this._influxRequest('GET', '/query', {q: query, epoch: 'ms'});
  104. };
  105. this.testDatasource = function() {
  106. return this.metricFindQuery('SHOW MEASUREMENTS LIMIT 1').then(function () {
  107. return { status: "success", message: "Data source is working", title: "Success" };
  108. });
  109. };
  110. this._influxRequest = function(method, url, data) {
  111. var self = this;
  112. var currentUrl = self.urls.shift();
  113. self.urls.push(currentUrl);
  114. var params: any = {
  115. u: self.username,
  116. p: self.password,
  117. };
  118. if (self.database) {
  119. params.db = self.database;
  120. }
  121. if (method === 'GET') {
  122. _.extend(params, data);
  123. data = null;
  124. }
  125. var options: any = {
  126. method: method,
  127. url: currentUrl + url,
  128. params: params,
  129. data: data,
  130. precision: "ms",
  131. inspect: { type: 'influxdb' },
  132. };
  133. options.headers = options.headers || {};
  134. if (self.basicAuth) {
  135. options.headers.Authorization = self.basicAuth;
  136. }
  137. return backendSrv.datasourceRequest(options).then(function(result) {
  138. return result.data;
  139. }, function(err) {
  140. if (err.status !== 0 || err.status >= 300) {
  141. if (err.data && err.data.error) {
  142. throw { message: 'InfluxDB Error Response: ' + err.data.error, data: err.data, config: err.config };
  143. } else {
  144. throw { message: 'InfluxDB Error: ' + err.message, data: err.data, config: err.config };
  145. }
  146. }
  147. });
  148. };
  149. function getTimeFilter(options) {
  150. var from = getInfluxTime(options.rangeRaw.from, false);
  151. var until = getInfluxTime(options.rangeRaw.to, true);
  152. var fromIsAbsolute = from[from.length-1] === 's';
  153. if (until === 'now()' && !fromIsAbsolute) {
  154. return 'time > ' + from;
  155. }
  156. return 'time > ' + from + ' and time < ' + until;
  157. }
  158. function getInfluxTime(date, roundUp) {
  159. if (_.isString(date)) {
  160. if (date === 'now') {
  161. return 'now()';
  162. }
  163. var parts = /^now-(\d+)([d|h|m|s])$/.exec(date);
  164. if (parts) {
  165. var amount = parseInt(parts[1]);
  166. var unit = parts[2];
  167. return 'now() - ' + amount + unit;
  168. }
  169. date = dateMath.parse(date, roundUp);
  170. }
  171. return (date.valueOf() / 1000).toFixed(0) + 's';
  172. }
  173. }