datasource.js 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. define([
  19. 'angular',
  20. 'lodash',
  21. 'jquery',
  22. './directives',
  23. './queryCtrl'
  24. ],
  25. function (angular, _) {
  26. 'use strict';
  27. var module = angular.module('grafana.services');
  28. module.factory('AmbariMetricsDatasource', function ($q, backendSrv, templateSrv) {
  29. /**
  30. * AMS Datasource Constructor
  31. */
  32. function AmbariMetricsDatasource(datasource) {
  33. this.name = datasource.name;
  34. this.url = datasource.url;
  35. this.initMetricAppidMapping();
  36. }
  37. var allMetrics = {};
  38. var appIds = [];
  39. //We get a list of components and their associated metrics.
  40. AmbariMetricsDatasource.prototype.initMetricAppidMapping = function () {
  41. return backendSrv.get(this.url + '/ws/v1/timeline/metrics/metadata')
  42. .then(function (items) {
  43. allMetrics = {};
  44. appIds = [];
  45. _.forEach(items, function (metric,app) {
  46. metric.forEach(function (component) {
  47. if (!allMetrics[app]) {
  48. allMetrics[app] = [];
  49. }
  50. allMetrics[app].push(component.metricname);
  51. });
  52. });
  53. //We remove a couple of components from the list that do not contain any
  54. //pertinent metrics.
  55. delete allMetrics["timeline_metric_store_watcher"];
  56. delete allMetrics["amssmoketestfake"];
  57. appIds = Object.keys(allMetrics);
  58. });
  59. };
  60. /**
  61. * AMS Datasource Authentication
  62. */
  63. AmbariMetricsDatasource.prototype.doAmbariRequest = function (options) {
  64. if (this.basicAuth || this.withCredentials) {
  65. options.withCredentials = true;
  66. }
  67. if (this.basicAuth) {
  68. options.headers = options.headers || {};
  69. options.headers.Authorization = this.basicAuth;
  70. }
  71. options.url = this.url + options.url;
  72. options.inspect = {type: 'ambarimetrics'};
  73. return backendSrv.datasourceRequest(options);
  74. };
  75. /**
  76. * AMS Datasource Query
  77. */
  78. AmbariMetricsDatasource.prototype.query = function (options) {
  79. var emptyData = function (metric) {
  80. var legend = metric.alias ? metric.alias : metric.metric;
  81. return {
  82. data: {
  83. target: legend,
  84. datapoints: []
  85. }
  86. };
  87. };
  88. var self = this;
  89. var getMetricsData = function (target) {
  90. var alias = target.alias ? target.alias : target.metric;
  91. if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "yarnqueues") {
  92. alias = alias + ' on ' + target.qmetric; }
  93. if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "kafka-topics") {
  94. alias = alias + ' on ' + target.kbTopic; }
  95. return function (res) {
  96. console.log('processing metric ' + target.metric);
  97. if (!res.metrics[0] || target.hide) {
  98. return $q.when(emptyData(target));
  99. }
  100. var series = [];
  101. var metricData = res.metrics[0].metrics;
  102. // Added hostname to legend for templated dashboards.
  103. var hostLegend = res.metrics[0].hostname ? ' on ' + res.metrics[0].hostname : '';
  104. var timeSeries = {};
  105. timeSeries = {
  106. target: alias + hostLegend,
  107. datapoints: []
  108. };
  109. for (var k in metricData){
  110. if (metricData.hasOwnProperty(k)) {
  111. timeSeries.datapoints.push([metricData[k], (k - k % 1000)]);
  112. }
  113. }
  114. series.push(timeSeries);
  115. return $q.when({data: series});
  116. };
  117. };
  118. // To speed up querying on templatized dashboards.
  119. var allHostMetricsData = function (target) {
  120. var alias = target.alias ? target.alias : target.metric;
  121. if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "hbase-users") {
  122. alias = alias + ' for ' + target.hbUser; }
  123. // Aliases for Storm Topologies and components under a topology.
  124. if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "topologies" &&
  125. !templateSrv.variables[1]) {
  126. alias = alias + ' on ' + target.sTopology;
  127. }
  128. if(!_.isEmpty(templateSrv.variables[1]) && templateSrv.variables[1].name === "component") {
  129. alias = alias + ' on ' + target.sTopology + ' for ' + target.sComponent;
  130. }
  131. return function (res) {
  132. console.log('processing metric ' + target.metric);
  133. if (!res.metrics[0] || target.hide) {
  134. return $q.when(emptyData(target));
  135. }
  136. var series = [];
  137. var timeSeries = {};
  138. var metricData = res.metrics;
  139. _.map(metricData, function (data) {
  140. var aliasSuffix = data.hostname ? ' on ' + data.hostname : '';
  141. if(!_.isEmpty(templateSrv.variables) && templateSrv.variables[0].query === "hbase-tables") {
  142. var tableName = "Tables.";
  143. var tableSuffix = data.metricname.substring(data.metricname.indexOf(tableName) + tableName.length,
  144. data.metricname.lastIndexOf("_metric"));
  145. var aliasSuffix = ' on ' + tableSuffix;
  146. }
  147. if(templateSrv.variables[0].query === "callers") {
  148. alias = data.metricname.substring(data.metricname.indexOf('(')+1, data.metricname.indexOf(')'));
  149. }
  150. timeSeries = {
  151. target: alias + aliasSuffix,
  152. datapoints: []
  153. };
  154. for (var k in data.metrics){
  155. if (data.metrics.hasOwnProperty(k)) {
  156. timeSeries.datapoints.push([data.metrics[k], (k - k % 1000)]);
  157. }
  158. }
  159. series.push(timeSeries);
  160. });
  161. return $q.when({data: series});
  162. };
  163. };
  164. var getHostAppIdData = function(target) {
  165. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  166. + target.precision;
  167. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  168. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  169. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  170. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform +
  171. metricAggregator + "&hostname=" + target.hosts + '&appId=' + target.app + '&startTime=' + from +
  172. '&endTime=' + to + precision + seriesAggregator).then(
  173. getMetricsData(target)
  174. );
  175. };
  176. //Check if it's a templated dashboard.
  177. var templatedHosts = templateSrv.variables.filter(function(o) { return o.name === "hosts"});
  178. var templatedHost = (_.isEmpty(templatedHosts)) ? '' : templatedHosts[0].options.filter(function(host)
  179. { return host.selected; }).map(function(hostName) { return hostName.value; });
  180. var tComponents = _.isEmpty(templateSrv.variables) ? '' : templateSrv.variables.filter(function(variable)
  181. { return variable.name === "components"});
  182. var tComponent = _.isEmpty(tComponents) ? '' : tComponents[0].current.value;
  183. var getServiceAppIdData = function(target) {
  184. var tHost = (_.isEmpty(templateSrv.variables)) ? templatedHost : target.templatedHost;
  185. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  186. + target.precision;
  187. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  188. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  189. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  190. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform
  191. + metricAggregator + '&hostname=' + tHost + '&appId=' + target.app + '&startTime=' + from +
  192. '&endTime=' + to + precision + seriesAggregator).then(
  193. getMetricsData(target)
  194. );
  195. };
  196. // To speed up querying on templatized dashboards.
  197. var getAllHostData = function(target) {
  198. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  199. + target.precision;
  200. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  201. var topN = ""; var isBottomN = "";
  202. if (!_.isEmpty(templateSrv.variables.filter(function(o) { return o.name === "instances";}))) {
  203. var metricTopN = _.filter(templateSrv.variables, function (o) { return o.name === "instances"; });
  204. var metricTopAgg = _.filter(templateSrv.variables, function (o) { return o.name === "topagg"; });
  205. isBottomN = templateSrv.variables.filter(function(o) { return o.name === "orientation";})[0].current.value
  206. === "bottom" ? true : false;
  207. topN = '&topN=' + metricTopN[0].current.value +'&topNFunction=' + metricTopAgg[0].current.value + '&isBottomN='+ isBottomN;
  208. }
  209. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  210. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  211. var templatedComponent = (_.isEmpty(tComponent)) ? target.app : tComponent;
  212. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.metric + metricTransform
  213. + metricAggregator + '&hostname=' + target.templatedHost + '&appId=' + templatedComponent + '&startTime=' + from +
  214. '&endTime=' + to + precision + topN + seriesAggregator).then(
  215. allHostMetricsData(target)
  216. );
  217. };
  218. var getYarnAppIdData = function(target) {
  219. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  220. + target.precision;
  221. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  222. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  223. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  224. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.queue + metricTransform
  225. + metricAggregator + '&appId=resourcemanager&startTime=' + from +
  226. '&endTime=' + to + precision + seriesAggregator).then(
  227. getMetricsData(target)
  228. );
  229. };
  230. var getHbaseAppIdData = function(target) {
  231. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  232. + target.precision;
  233. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  234. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.hbMetric + '&appId=hbase&startTime='
  235. + from + '&endTime=' + to + precision + seriesAggregator).then(
  236. allHostMetricsData(target)
  237. );
  238. };
  239. var getKafkaAppIdData = function(target) {
  240. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  241. + target.precision;
  242. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  243. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  244. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  245. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.kbMetric + metricTransform
  246. + metricAggregator + '&appId=kafka_broker&startTime=' + from +
  247. '&endTime=' + to + precision + seriesAggregator).then(
  248. getMetricsData(target)
  249. );
  250. };
  251. var getNnAppIdData = function(target) {
  252. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  253. + target.precision;
  254. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  255. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  256. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  257. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.nnMetric + metricTransform
  258. + metricAggregator + '&appId=namenode&startTime=' + from + '&endTime=' + to + precision + seriesAggregator).then(
  259. allHostMetricsData(target)
  260. );
  261. };
  262. // Storm Topology calls.
  263. var getStormData = function(target) {
  264. var precision = target.precision === 'default' || typeof target.precision == 'undefined' ? '' : '&precision='
  265. + target.precision;
  266. var metricAggregator = target.aggregator === "none" ? '' : '._' + target.aggregator;
  267. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  268. var seriesAggregator = !target.seriesAggregator || target.seriesAggregator === "none" ? '' : '&seriesAggregateFunction=' + target.seriesAggregator;
  269. return backendSrv.get(self.url + '/ws/v1/timeline/metrics?metricNames=' + target.sTopoMetric + metricTransform
  270. + metricAggregator + '&appId=nimbus&startTime=' + from + '&endTime=' + to + precision + seriesAggregator).then(
  271. allHostMetricsData(target)
  272. );
  273. };
  274. // Time Ranges
  275. var from = Math.floor(options.range.from.valueOf() / 1000);
  276. var to = Math.floor(options.range.to.valueOf() / 1000);
  277. var metricsPromises = [];
  278. if (!_.isEmpty(templateSrv.variables)) {
  279. // YARN Queues Dashboard
  280. if (templateSrv.variables[0].query === "yarnqueues") {
  281. var allQueues = templateSrv.variables.filter(function(variable) { return variable.query === "yarnqueues";});
  282. var selectedQs = (_.isEmpty(allQueues)) ? "" : allQueues[0].options.filter(function(q)
  283. { return q.selected; }).map(function(qName) { return qName.value; });
  284. // All Queues
  285. if (!_.isEmpty(_.find(selectedQs, function (wildcard) { return wildcard === "*"; }))) {
  286. var allQueue = allQueues[0].options.filter(function(q) {
  287. return q.text !== "All"; }).map(function(queue) { return queue.value; });
  288. _.forEach(allQueue, function(processQueue) {
  289. metricsPromises.push(_.map(options.targets, function(target) {
  290. target.qmetric = processQueue;
  291. target.queue = target.metric.replace('root', target.qmetric);
  292. return getYarnAppIdData(target);
  293. }));
  294. });
  295. } else {
  296. // All selected queues.
  297. _.forEach(selectedQs, function(processQueue) {
  298. metricsPromises.push(_.map(options.targets, function(target) {
  299. target.qmetric = processQueue;
  300. target.queue = target.metric.replace('root', target.qmetric);
  301. return getYarnAppIdData(target);
  302. }));
  303. });
  304. }
  305. }
  306. // Templatized Dashboard for per-user metrics in HBase.
  307. if (templateSrv.variables[0].query === "hbase-users") {
  308. var allUsers = templateSrv.variables.filter(function(variable) { return variable.query === "hbase-users";});
  309. var selectedUsers = (_.isEmpty(allUsers)) ? "" : allUsers[0].options.filter(function(user)
  310. { return user.selected; }).map(function(uName) { return uName.value; });
  311. selectedUsers = templateSrv._values.Users.lastIndexOf('}') > 0 ? templateSrv._values.Users.slice(1,-1) :
  312. templateSrv._values.Users;
  313. var selectedUser = selectedUsers.split(',');
  314. _.forEach(selectedUser, function(processUser) {
  315. metricsPromises.push(_.map(options.targets, function(target) {
  316. target.hbUser = processUser;
  317. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  318. target.hbMetric = target.metric.replace('*', target.hbUser) + metricTransform +'._' + target.aggregator;
  319. return getHbaseAppIdData(target);
  320. }));
  321. });
  322. }
  323. // Templatized Dashboard for per-table metrics in HBase.
  324. if (templateSrv.variables[0].query === "hbase-tables") {
  325. var splitTables = [];
  326. var allTables = templateSrv._values.Tables.lastIndexOf('}') > 0 ? templateSrv._values.Tables.slice(1,-1) :
  327. templateSrv._values.Tables;
  328. var allTable = allTables.split(',');
  329. while (allTable.length > 0) {
  330. splitTables.push(allTable.splice(0,20));
  331. }
  332. _.forEach(splitTables, function(table) {
  333. metricsPromises.push(_.map(options.targets, function(target) {
  334. var hbMetric = [];
  335. _.map(table, function(tableMetric) { hbMetric.push(target.metric.replace('*', tableMetric)); });
  336. var metricTransform = !target.transform || target.transform === "none" ? '' : '._' + target.transform;
  337. hbMetric = _.map(hbMetric, function(tbl) { return tbl + metricTransform +'._' + target.aggregator; });
  338. target.hbMetric = _.flatten(hbMetric).join(',');
  339. return getHbaseAppIdData(target);
  340. }));
  341. });
  342. }
  343. // Templatized Dashboard for per-topic metrics in Kafka.
  344. if (templateSrv.variables[0].query === "kafka-topics") {
  345. var allTopics = templateSrv.variables.filter(function(variable) { return variable.query === "kafka-topics";});
  346. var selectedTopics = (_.isEmpty(allTopics)) ? "" : allTopics[0].options.filter(function(topic)
  347. { return topic.selected; }).map(function(topicName) { return topicName.value; });
  348. selectedTopics = templateSrv._values.Topics.lastIndexOf('}') > 0 ? templateSrv._values.Topics.slice(1,-1) :
  349. templateSrv._values.Topics;
  350. var selectedTopic = selectedTopics.split(',');
  351. _.forEach(selectedTopic, function(processTopic) {
  352. metricsPromises.push(_.map(options.targets, function(target) {
  353. target.kbTopic = processTopic;
  354. target.kbMetric = target.metric.replace('*', target.kbTopic);
  355. return getKafkaAppIdData(target);
  356. }));
  357. });
  358. }
  359. //Templatized Dashboard for Call Queues
  360. if (templateSrv.variables[0].query === "callers") {
  361. var allCallers = templateSrv.variables.filter(function(variable) { return variable.query === "callers";});
  362. var selectedCallers = (_.isEmpty(allCallers)) ? "" : allCallers[0].options.filter(function(user)
  363. { return user.selected; }).map(function(callerName) { return callerName.value; });
  364. selectedCallers = templateSrv._values.Callers.lastIndexOf('}') > 0 ? templateSrv._values.Callers.slice(1,-1) :
  365. templateSrv._values.Callers;
  366. var selectedCaller = selectedCallers.split(',');
  367. _.forEach(selectedCaller, function(processCaller) {
  368. metricsPromises.push(_.map(options.targets, function(target) {
  369. target.nnCaller = processCaller;
  370. target.nnMetric = target.metric.replace('*', target.nnCaller);
  371. return getNnAppIdData(target);
  372. }));
  373. });
  374. }
  375. //Templatized Dashboard for Storm Topologies
  376. if (templateSrv.variables[0].query === "topologies" && !templateSrv.variables[1]) {
  377. var allTopologies = templateSrv.variables.filter(function(variable) { return variable.query === "topologies";});
  378. var selectedTopologies = (_.isEmpty(allTopologies)) ? "" : allTopologies[0].options.filter(function(topo)
  379. { return topo.selected; }).map(function(topoName) { return topoName.value; });
  380. selectedTopologies = templateSrv._values.topologies.lastIndexOf('}') > 0 ? templateSrv._values.topologies.slice(1,-1) :
  381. templateSrv._values.topologies;
  382. var selectedTopology= selectedTopologies.split(',');
  383. _.forEach(selectedTopology, function(processTopology) {
  384. metricsPromises.push(_.map(options.targets, function(target) {
  385. target.sTopology = processTopology;
  386. target.sTopoMetric = target.metric.replace('*', target.sTopology);
  387. return getStormData(target);
  388. }));
  389. });
  390. }
  391. //Templatized Dashboards for Storm Components
  392. if (templateSrv.variables[0].query === "topologies" && templateSrv.variables[1] &&
  393. templateSrv.variables[1].name === "component") {
  394. var selectedTopology = templateSrv._values.topologies;
  395. var selectedComponent = templateSrv._values.component;
  396. metricsPromises.push(_.map(options.targets, function(target) {
  397. target.sTopology = selectedTopology;
  398. target.sComponent = selectedComponent;
  399. target.sTopoMetric = target.metric.replace('*', target.sTopology).replace('*', target.sComponent);
  400. debugger;
  401. return getStormData(target);
  402. }));
  403. }
  404. //Templatized Dashboard for Storm Kafka Offset
  405. if (templateSrv.variables[0].query === "topologies" && templateSrv.variables[1] &&
  406. templateSrv.variables[1].name === "topic") {
  407. var selectedTopology = templateSrv._values.topologies;
  408. var selectedTopic = templateSrv._values.topic;
  409. metricsPromises.push(_.map(options.targets, function(target) {
  410. target.sTopology = selectedTopology;
  411. target.sTopic = selectedTopic;
  412. target.sPartition = options.scopedVars.partition.value;
  413. target.sTopoMetric = target.metric.replace('*', target.sTopology).replace('*', target.sTopic)
  414. .replace('*', target.sPartition);
  415. return getStormData(target);
  416. }));
  417. }
  418. // To speed up querying on templatized dashboards.
  419. if (templateSrv.variables[1] && templateSrv.variables[1].name === "hosts") {
  420. var allHosts = templateSrv._values.hosts.lastIndexOf('}') > 0 ? templateSrv._values.hosts.slice(1,-1) :
  421. templateSrv._values.hosts;
  422. allHosts = templateSrv._texts.hosts === "All" ? '%' : allHosts;
  423. metricsPromises.push(_.map(options.targets, function(target) {
  424. target.templatedHost = allHosts;
  425. return getAllHostData(target);
  426. }));
  427. }
  428. metricsPromises = _.flatten(metricsPromises);
  429. } else {
  430. // Non Templatized Dashboards
  431. metricsPromises = _.map(options.targets, function(target) {
  432. console.debug('target app=' + target.app + ',' +
  433. 'target metric=' + target.metric + ' on host=' + target.tempHost);
  434. if (!!target.hosts) {
  435. return getHostAppIdData(target);
  436. } else {
  437. return getServiceAppIdData(target);
  438. }
  439. });
  440. }
  441. return $q.all(metricsPromises).then(function(metricsDataArray) {
  442. var data = _.map(metricsDataArray, function(metricsData) {
  443. return metricsData.data;
  444. });
  445. var metricsDataResult = {data: _.flatten(data)};
  446. return $q.when(metricsDataResult);
  447. });
  448. };
  449. /**
  450. * AMS Datasource List Series.
  451. */
  452. AmbariMetricsDatasource.prototype.listSeries = function (query) {
  453. // wrap in regex
  454. if (query && query.length > 0 && query[0] !== '/') {
  455. query = '/' + query + '/';
  456. }
  457. return $q.when([]);
  458. };
  459. /**
  460. * AMS Datasource Templating Variables.
  461. */
  462. AmbariMetricsDatasource.prototype.metricFindQuery = function (query) {
  463. var interpolated;
  464. try {
  465. interpolated = templateSrv.replace(query);
  466. } catch (err) {
  467. return $q.reject(err);
  468. }
  469. var tComponents = _.isEmpty(templateSrv.variables) ? '' : templateSrv.variables.filter(function(variable)
  470. { return variable.name === "components"});
  471. var tComponent = _.isEmpty(tComponents) ? '' : tComponents[0].current.value;
  472. // Templated Variable for HBase Users
  473. // It will search the cluster and populate the HBase Users.
  474. if(interpolated === "hbase-users") {
  475. return this.initMetricAppidMapping()
  476. .then(function () {
  477. var hbaseUsers = allMetrics["hbase"];
  478. var extractUsers = hbaseUsers.filter(/./.test.bind(new RegExp("regionserver.Users.", 'g')));
  479. var removeUser = "regionserver.Users.numUsers";
  480. var i = extractUsers.indexOf(removeUser);
  481. if(i !== -1) { extractUsers.splice(i, 1);}
  482. var userPrefix = "regionserver.Users.";
  483. var users = _.map(extractUsers, function(user) {
  484. return user.substring(userPrefix.length);
  485. });
  486. users = _.map(users, function(userName) {
  487. return userName.substring(0,userName.lastIndexOf("_metric"));
  488. });
  489. users = _.sortBy(_.uniq(users));
  490. return _.map(users, function (users) {
  491. return {
  492. text: users
  493. };
  494. });
  495. });
  496. }
  497. // Templated Variable for HBase Tables.
  498. // It will search the cluster and populate the hbase-tables.
  499. if(interpolated === "hbase-tables") {
  500. return this.initMetricAppidMapping()
  501. .then(function () {
  502. var hbaseTables = allMetrics["hbase"];
  503. var extractTables = hbaseTables.filter(/./.test.bind(new RegExp("regionserver.Tables.", 'g')));
  504. var removeTable = "regionserver.Tables.numTables";
  505. var i = extractTables.indexOf(removeTable);
  506. if(i != -1) { extractTables.splice(i, 1);}
  507. var tablePrefix = "regionserver.Tables.";
  508. var tables = _.map(extractTables, function(user) {
  509. return user.substring(tablePrefix.length);
  510. });
  511. tables = _.map(tables, function(userName) {
  512. return userName.substring(0,userName.lastIndexOf("_metric"));
  513. });
  514. tables = _.sortBy(_.uniq(tables));
  515. return _.map(tables, function (tables) {
  516. return {
  517. text: tables
  518. };
  519. });
  520. });
  521. }
  522. // Templated Variable for Kafka Topics.
  523. // It will search the cluster and populate the topics.
  524. if(interpolated === "kafka-topics") {
  525. return this.initMetricAppidMapping()
  526. .then(function () {
  527. var kafkaTopics = allMetrics["kafka_broker"];
  528. var extractTopics = kafkaTopics.filter(/./.test.bind(new RegExp("\\b.log.Log.\\b", 'g')));
  529. var topics =_.map(extractTopics, function (topic) {
  530. var topicPrefix = "topic.";
  531. return topic.substring(topic.lastIndexOf(topicPrefix)+topicPrefix.length, topic.length);
  532. });
  533. topics = _.sortBy(_.uniq(topics));
  534. var i = topics.indexOf("ambari_kafka_service_check");
  535. if(i != -1) { topics.splice(i, 1);}
  536. return _.map(topics, function (topics) {
  537. return {
  538. text: topics
  539. };
  540. });
  541. });
  542. }
  543. //Templated Variables for Call Queue Metrics
  544. if(interpolated === "callers") {
  545. return this.initMetricAppidMapping()
  546. .then(function () {
  547. var nnCallers = allMetrics["namenode"];
  548. var extractCallers = nnCallers.filter(/./.test.bind(new
  549. RegExp("ipc.client.org.apache.hadoop.ipc.DecayRpcScheduler.Caller", 'g')));
  550. var callers = _.sortBy(_.uniq(_.map(extractCallers, function(caller) {
  551. return caller.substring(caller.indexOf('(')+1, caller.indexOf(')')) })));
  552. return _.map(callers, function (callers) {
  553. return {
  554. text: callers
  555. };
  556. });
  557. });
  558. }
  559. var topologies = {};
  560. //Templated Variables for Storm Topologies
  561. if(interpolated === "topologies") {
  562. return this.initMetricAppidMapping()
  563. .then(function () {
  564. var storm = allMetrics["nimbus"];
  565. var extractTopologies = storm.filter(/./.test.bind(new
  566. RegExp("^topology.", 'g')));
  567. _.map(extractTopologies, function(topology){
  568. // Topology naming convention is topology.<topology-name>.component.
  569. topology = topology.split('.').slice(0,3);
  570. if (topologies[topology[1]]){
  571. topologies[topology[1]].push(topology[2]);
  572. } else {
  573. topologies[topology[1]] = [topology[2]];
  574. }
  575. });
  576. return _.map(Object.keys(topologies), function(topologyNames){
  577. return {
  578. text: topologyNames
  579. };
  580. });
  581. });
  582. }
  583. //Templated Variables for Storm Components per Topology
  584. if (interpolated.includes("stormComponent")) {
  585. var componentName = interpolated.substring(0,interpolated.indexOf('.'));
  586. return this.initMetricAppidMapping()
  587. .then(function () {
  588. var storm = allMetrics["nimbus"];
  589. var extractTopologies = storm.filter(/./.test.bind(new
  590. RegExp("^topology.", 'g')));
  591. _.map(extractTopologies, function(topology){
  592. topology = topology.split('.').slice(0,3);
  593. if (topologies[topology[1]]){
  594. topologies[topology[1]].push(topology[2]);
  595. } else {
  596. topologies[topology[1]] = [topology[2]];
  597. }
  598. });
  599. // Retrieve unique component names from the list.
  600. var compName = _.uniq(topologies[componentName]);
  601. // Remove "kafka-topic" from the list of components.
  602. var remove = compName.indexOf('kafka-topic');
  603. if (remove > -1) { compName.splice(remove, 1);}
  604. return _.map(compName, function(components){
  605. return {
  606. text: components
  607. };
  608. });
  609. });
  610. }
  611. var stormEntities = {};
  612. AmbariMetricsDatasource.prototype.getStormEntities = function () {
  613. return this.initMetricAppidMapping()
  614. .then(function () {
  615. var storm = allMetrics["nimbus"];
  616. var extractTopologies = storm.filter(/./.test.bind(new
  617. RegExp("partition", 'g')));
  618. _.map(extractTopologies, function(topology){
  619. topology = topology.split('.').slice(0,5);
  620. var topologyName = topologyN = topology[1]; // Topology
  621. var topologyTopicName = topicN = topology[3]; // Topic
  622. var topologyTopicPartitionName = topology[4]; // Partition
  623. if (stormEntities[topologyName]) {
  624. if (stormEntities[topologyName][topologyTopicName]) {
  625. stormEntities[topologyName][topologyTopicName].push(topologyTopicPartitionName);
  626. } else {
  627. stormEntities[topologyName][topologyTopicName] = [topologyTopicPartitionName];
  628. }
  629. } else {
  630. stormEntities[topologyName] = {};
  631. stormEntities[topologyName][topologyTopicName] = [topologyTopicPartitionName];
  632. }
  633. });
  634. });
  635. };
  636. //Templated Variables for Storm Topics per Topology
  637. if (interpolated.includes("stormTopic")) {
  638. var topicName = interpolated.substring(0,interpolated.indexOf('.'));
  639. return this.getStormEntities().then(function () {
  640. var topicNames = Object.keys(stormEntities[topicName]);
  641. return _.map(topicNames, function(names){
  642. return {
  643. text: names
  644. };
  645. });
  646. });
  647. }
  648. //Templated Variables for Storm Partitions per Topic
  649. if (interpolated.includes("stormPartition")) {
  650. var topicN, topologyN;
  651. return this.getStormEntities().then(function () {
  652. var partitionNames = _.uniq(stormEntities[topologyN][topicN]);
  653. return _.map(partitionNames, function(names){
  654. return {
  655. text: names
  656. };
  657. });
  658. });
  659. }
  660. // Templated Variable for YARN Queues.
  661. // It will search the cluster and populate the queues.
  662. if(interpolated === "yarnqueues") {
  663. return this.initMetricAppidMapping()
  664. .then(function () {
  665. var yarnqueues = allMetrics["resourcemanager"];
  666. var extractQueues = yarnqueues.filter(/./.test.bind(new RegExp(".=root", 'g')));
  667. var queues = _.map(extractQueues, function(metric) {
  668. return metric.substring("yarn.QueueMetrics.Queue=".length);
  669. });
  670. queues = _.map(queues, function(metricName) {
  671. return metricName.substring(metricName.lastIndexOf("."), 0);
  672. });
  673. queues = _.sortBy(_.uniq(queues));
  674. return _.map(queues, function (queues) {
  675. return {
  676. text: queues
  677. };
  678. });
  679. });
  680. }
  681. // Templated Variable that will populate all hosts on the cluster.
  682. // The variable needs to be set to "hosts".
  683. if (!tComponent){
  684. return this.doAmbariRequest({
  685. method: 'GET',
  686. url: '/ws/v1/timeline/metrics/' + interpolated
  687. })
  688. .then(function (results) {
  689. //Remove fakehostname from the list of hosts on the cluster.
  690. var fake = "fakehostname"; delete results.data[fake];
  691. return _.map(_.keys(results.data), function (hostName) {
  692. return {
  693. text: hostName,
  694. expandable: hostName.expandable ? true : false
  695. };
  696. });
  697. });
  698. } else {
  699. // Create a dropdown in templated dashboards for single components.
  700. // This will check for the component set and show hosts only for the
  701. // selected component.
  702. return this.doAmbariRequest({
  703. method: 'GET',
  704. url: '/ws/v1/timeline/metrics/hosts'
  705. })
  706. .then(function(results) {
  707. var compToHostMap = {};
  708. //Remove fakehostname from the list of hosts on the cluster.
  709. var fake = "fakehostname";
  710. delete results.data[fake];
  711. //Query hosts based on component name
  712. _.forEach(results.data, function(comp, hostName) {
  713. comp.forEach(function(component) {
  714. if (!compToHostMap[component]) {
  715. compToHostMap[component] = [];
  716. }
  717. compToHostMap[component].push(hostName);
  718. });
  719. });
  720. var compHosts = compToHostMap[tComponent];
  721. compHosts = _.map(compHosts, function(host) {
  722. return {
  723. text: host,
  724. expandable: host.expandable ? true : false
  725. };
  726. });
  727. compHosts = _.sortBy(compHosts, function(i) {
  728. return i.text.toLowerCase();
  729. });
  730. return $q.when(compHosts);
  731. });
  732. }
  733. };
  734. /**
  735. * AMS Datasource - Test Data Source Connection.
  736. *
  737. * Added Check to see if Datasource is working. Throws up an error in the
  738. * Datasources page if incorrect info is passed on.
  739. */
  740. AmbariMetricsDatasource.prototype.testDatasource = function () {
  741. return backendSrv.datasourceRequest({
  742. url: this.url + '/ws/v1/timeline/metrics/metadata',
  743. method: 'GET'
  744. }).then(function(response) {
  745. console.log(response);
  746. if (response.status === 200) {
  747. return { status: "success", message: "Data source is working", title: "Success" };
  748. }
  749. });
  750. };
  751. /**
  752. * AMS Datasource - Suggest AppId.
  753. *
  754. * Read AppIds from cache.
  755. */
  756. AmbariMetricsDatasource.prototype.suggestApps = function (query) {
  757. console.log(query);
  758. appIds = appIds.sort();
  759. var appId = _.map(appIds, function (k) {
  760. return {text: k};
  761. });
  762. return $q.when(appId);
  763. };
  764. /**
  765. * AMS Datasource - Suggest Metrics.
  766. *
  767. * Read Metrics based on AppId chosen.
  768. */
  769. AmbariMetricsDatasource.prototype.suggestMetrics = function (query, app) {
  770. if (!app) {
  771. return $q.when([]);
  772. }
  773. var keys = [];
  774. keys = _.map(allMetrics[app],function(m) {
  775. return {text: m};
  776. });
  777. keys = _.sortBy(keys, function (i) { return i.text.toLowerCase(); });
  778. return $q.when(keys);
  779. };
  780. /**
  781. * AMS Datasource - Suggest Hosts.
  782. *
  783. * Query Hosts on the cluster.
  784. */
  785. AmbariMetricsDatasource.prototype.suggestHosts = function (query, app) {
  786. console.log(query);
  787. return this.doAmbariRequest({method: 'GET', url: '/ws/v1/timeline/metrics/hosts'})
  788. .then(function (results) {
  789. var compToHostMap = {};
  790. //Remove fakehostname from the list of hosts on the cluster.
  791. var fake = "fakehostname"; delete results.data[fake];
  792. //Query hosts based on component name
  793. _.forEach(results.data, function (comp, hostName) {
  794. comp.forEach(function (component) {
  795. if (!compToHostMap[component]){
  796. compToHostMap[component] = [];
  797. }
  798. compToHostMap[component].push(hostName);
  799. });
  800. });
  801. var compHosts = compToHostMap[app];
  802. compHosts = _.map(compHosts, function (h) {
  803. return {text: h};
  804. });
  805. compHosts = _.sortBy(compHosts, function (i) { return i.text.toLowerCase(); });
  806. return $q.when(compHosts);
  807. });
  808. };
  809. /**
  810. * AMS Datasource Aggregators.
  811. */
  812. var aggregatorsPromise = null;
  813. AmbariMetricsDatasource.prototype.getAggregators = function () {
  814. if (aggregatorsPromise) {
  815. return aggregatorsPromise;
  816. }
  817. aggregatorsPromise = $q.when([
  818. 'none','avg', 'sum', 'min', 'max'
  819. ]);
  820. return aggregatorsPromise;
  821. };
  822. return AmbariMetricsDatasource;
  823. });
  824. }
  825. );