query_ctrl.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. import _ from 'lodash';
  2. import { QueryCtrl } from 'app/plugins/sdk';
  3. import kbn from 'app/core/utils/kbn';
  4. import { TemplateSrv } from 'app/features/templating/template_srv';
  5. import { auto } from 'angular';
  6. import { DataFrame } from '@grafana/data';
  7. import { Resource } from './types';
  8. import { migrateTargetSchema } from './migrations';
  9. import TimegrainConverter from './time_grain_converter';
  10. import './editor/editor_component';
  11. import './multi-select.directive';
  12. export interface ResultFormat {
  13. text: string;
  14. value: string;
  15. }
  16. interface AzureMonitor {
  17. resourceGroup: string;
  18. resourceGroups: string[];
  19. resourceName: string;
  20. metricDefinition: string;
  21. metricNamespace: string;
  22. metricName: string;
  23. dimensionFilter: string;
  24. timeGrain: string;
  25. timeGrainUnit: string;
  26. timeGrains: Option[];
  27. allowedTimeGrainsMs: number[];
  28. dimensions: any[];
  29. dimension: any;
  30. aggregation: string;
  31. aggOptions: string[];
  32. locations: string[];
  33. queryMode: string;
  34. }
  35. interface Option {
  36. value: string;
  37. text: string;
  38. displayName?: string;
  39. }
  40. export class AzureMonitorQueryCtrl extends QueryCtrl {
  41. static templateUrl = 'partials/query.editor.html';
  42. static defaultQueryMode = 'singleResource';
  43. defaultDropdownValue = 'select';
  44. target: {
  45. refId: string;
  46. queryType: string;
  47. subscription: string;
  48. subscriptions: string[];
  49. azureMonitor: {
  50. queryMode: string;
  51. data: { [queryMode: string]: AzureMonitor };
  52. };
  53. azureLogAnalytics: {
  54. query: string;
  55. resultFormat: string;
  56. workspace: string;
  57. };
  58. appInsights: {
  59. metricName: string;
  60. rawQuery: boolean;
  61. rawQueryString: string;
  62. groupBy: string;
  63. timeGrainType: string;
  64. xaxis: string;
  65. yaxis: string;
  66. spliton: string;
  67. aggOptions: string[];
  68. aggregation: string;
  69. groupByOptions: string[];
  70. timeGrainUnit: string;
  71. timeGrain: string;
  72. };
  73. };
  74. defaults = {
  75. queryType: 'Azure Monitor',
  76. subscriptions: new Array<string>(),
  77. azureMonitor: {
  78. queryMode: 'singleResource',
  79. data: {
  80. singleResource: {
  81. resourceGroups: new Array<string>(),
  82. resourceGroup: this.defaultDropdownValue,
  83. metricDefinition: this.defaultDropdownValue,
  84. metricNamespace: this.defaultDropdownValue,
  85. metricName: this.defaultDropdownValue,
  86. resourceName: this.defaultDropdownValue,
  87. dimensionFilter: '*',
  88. timeGrain: 'auto',
  89. },
  90. crossResource: {
  91. resourceGroups: new Array<string>(),
  92. locations: new Array<string>(),
  93. metricDefinition: this.defaultDropdownValue,
  94. resourceName: this.defaultDropdownValue,
  95. metricName: this.defaultDropdownValue,
  96. dimensionFilter: '*',
  97. timeGrain: 'auto',
  98. },
  99. },
  100. },
  101. azureLogAnalytics: {
  102. query: [
  103. '//change this example to create your own time series query',
  104. '<table name> ' +
  105. '//the table to query (e.g. Usage, Heartbeat, Perf)',
  106. '| where $__timeFilter(TimeGenerated) ' +
  107. '//this is a macro used to show the full chart’s time range, choose the datetime column here',
  108. '| summarize count() by <group by column>, bin(TimeGenerated, $__interval) ' +
  109. '//change “group by column” to a column in your table, such as “Computer”. ' +
  110. 'The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.',
  111. '| order by TimeGenerated asc',
  112. ].join('\n'),
  113. resultFormat: 'time_series',
  114. workspace:
  115. this.datasource && this.datasource.azureLogAnalyticsDatasource
  116. ? this.datasource.azureLogAnalyticsDatasource.defaultOrFirstWorkspace
  117. : '',
  118. },
  119. appInsights: {
  120. metricName: this.defaultDropdownValue,
  121. rawQuery: false,
  122. rawQueryString: '',
  123. groupBy: 'none',
  124. timeGrainType: 'auto',
  125. xaxis: 'timestamp',
  126. yaxis: '',
  127. spliton: '',
  128. },
  129. };
  130. resultFormats: ResultFormat[];
  131. workspaces: any[];
  132. showHelp: boolean;
  133. showLastQuery: boolean;
  134. lastQuery: string;
  135. lastQueryError?: string;
  136. subscriptions: Option[];
  137. subscriptionValues: string[];
  138. resources: Resource[];
  139. locations: Option[];
  140. resourceGroups: Option[];
  141. /** @ngInject */
  142. constructor($scope: any, $injector: auto.IInjectorService, private templateSrv: TemplateSrv) {
  143. super($scope, $injector);
  144. this.target = migrateTargetSchema(this.target);
  145. _.defaultsDeep(this.target, this.defaults);
  146. this.migrateTimeGrains();
  147. this.migrateToFromTimes();
  148. this.migrateToDefaultNamespace();
  149. this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
  150. this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
  151. this.resultFormats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
  152. this.resources = new Array<Resource>();
  153. this.subscriptionValues = [];
  154. this.init();
  155. if (this.target.queryType === 'Azure Log Analytics') {
  156. this.getWorkspaces();
  157. }
  158. }
  159. async init() {
  160. const subscriptions = await this.getSubscriptions();
  161. this.datasource.getResources(subscriptions.map((s: Option) => s.value)).then(async (resources: Resource[]) => {
  162. if (!this.target.subscriptions.length) {
  163. this.target.subscriptions = this.subscriptions.map(s => s.value);
  164. }
  165. this.resources = resources;
  166. this.updateLocations();
  167. this.updateCrossResourceGroups();
  168. });
  169. }
  170. updateLocations() {
  171. this.locations = this.getLocations().map(l => ({ text: l, value: l }));
  172. }
  173. updateCrossResourceGroups() {
  174. this.resourceGroups = this.getCrossResourceGroups().map(rg => ({ text: rg, value: rg }));
  175. }
  176. onDataReceived(dataList: DataFrame[]) {
  177. this.lastQueryError = undefined;
  178. this.lastQuery = '';
  179. const anySeriesFromQuery: any = _.find(dataList, { refId: this.target.refId });
  180. if (anySeriesFromQuery && anySeriesFromQuery.meta) {
  181. this.lastQuery = anySeriesFromQuery.meta.query;
  182. }
  183. }
  184. onDataError(err: any) {
  185. this.handleQueryCtrlError(err);
  186. }
  187. handleQueryCtrlError(err: any) {
  188. if (err.query && err.query.refId && err.query.refId !== this.target.refId) {
  189. return;
  190. }
  191. if (err.error && err.error.data && err.error.data.error && err.error.data.error.innererror) {
  192. if (err.error.data.error.innererror.innererror) {
  193. this.lastQueryError = err.error.data.error.innererror.innererror.message;
  194. } else {
  195. this.lastQueryError = err.error.data.error.innererror.message;
  196. }
  197. } else if (err.error && err.error.data && err.error.data.error) {
  198. this.lastQueryError = err.error.data.error.message;
  199. } else if (err.error && err.error.data) {
  200. this.lastQueryError = err.error.data.message;
  201. } else if (err.data && err.data.error) {
  202. this.lastQueryError = err.data.error.message;
  203. } else if (err.data && err.data.message) {
  204. this.lastQueryError = err.data.message;
  205. } else {
  206. this.lastQueryError = err;
  207. }
  208. }
  209. migrateTimeGrains() {
  210. const { queryMode } = this.target.azureMonitor;
  211. if (this.target.azureMonitor.data[queryMode].timeGrainUnit) {
  212. if (this.target.azureMonitor.data[queryMode].timeGrain !== 'auto') {
  213. this.target.azureMonitor.data[queryMode].timeGrain = TimegrainConverter.createISO8601Duration(
  214. this.target.azureMonitor.data[queryMode].timeGrain,
  215. this.target.azureMonitor.data[queryMode].timeGrainUnit
  216. );
  217. }
  218. delete this.target.azureMonitor.data[queryMode].timeGrainUnit;
  219. this.onMetricNameChange();
  220. }
  221. if (
  222. this.target.azureMonitor.data[queryMode].timeGrains &&
  223. this.target.azureMonitor.data[queryMode].timeGrains.length > 0 &&
  224. (!this.target.azureMonitor.data[queryMode].allowedTimeGrainsMs ||
  225. this.target.azureMonitor.data[queryMode].allowedTimeGrainsMs.length === 0)
  226. ) {
  227. this.target.azureMonitor.data[queryMode].allowedTimeGrainsMs = this.convertTimeGrainsToMs(
  228. this.target.azureMonitor.data[queryMode].timeGrains
  229. );
  230. }
  231. }
  232. migrateToFromTimes() {
  233. this.target.azureLogAnalytics.query = this.target.azureLogAnalytics.query.replace(/\$__from\s/gi, '$__timeFrom() ');
  234. this.target.azureLogAnalytics.query = this.target.azureLogAnalytics.query.replace(/\$__to\s/gi, '$__timeTo() ');
  235. }
  236. async migrateToDefaultNamespace() {
  237. const { queryMode } = this.target.azureMonitor;
  238. if (
  239. this.target.azureMonitor.data[queryMode].metricNamespace &&
  240. this.target.azureMonitor.data[queryMode].metricNamespace !== this.defaultDropdownValue &&
  241. this.target.azureMonitor.data[queryMode].metricDefinition
  242. ) {
  243. return;
  244. }
  245. this.target.azureMonitor.data[queryMode].metricNamespace = this.target.azureMonitor.data[
  246. queryMode
  247. ].metricDefinition;
  248. }
  249. replace(variable: string) {
  250. return this.templateSrv.replace(variable, this.panelCtrl.panel.scopedVars);
  251. }
  252. onQueryTypeChange() {
  253. if (this.target.queryType === 'Azure Log Analytics') {
  254. return this.getWorkspaces();
  255. }
  256. }
  257. async getSubscriptions() {
  258. if (!this.datasource.azureMonitorDatasource.isConfigured()) {
  259. return;
  260. }
  261. return this.datasource.azureMonitorDatasource.getSubscriptions().then((subs: any) => {
  262. this.subscriptions = subs;
  263. this.subscriptionValues = subs.map((s: Option) => ({ value: s.value, text: s.displayName }));
  264. if (!this.target.subscriptions.length) {
  265. this.target.subscriptions = subs.map((s: Option) => s.value);
  266. }
  267. if (!this.target.subscription && this.target.queryType === 'Azure Monitor') {
  268. this.target.subscription = this.datasource.azureMonitorDatasource.subscriptionId;
  269. } else if (!this.target.subscription && this.target.queryType === 'Azure Log Analytics') {
  270. this.target.subscription = this.datasource.azureLogAnalyticsDatasource.logAnalyticsSubscriptionId;
  271. }
  272. if (!this.target.subscription && this.subscriptions.length > 0) {
  273. this.target.subscription = this.subscriptions[0].value;
  274. }
  275. return this.subscriptions;
  276. });
  277. }
  278. onSubscriptionChange() {
  279. if (this.target.queryType === 'Azure Log Analytics') {
  280. return this.getWorkspaces();
  281. }
  282. const { queryMode } = this.target.azureMonitor;
  283. if (this.target.queryType === 'Azure Monitor') {
  284. this.target.azureMonitor.data[queryMode].resourceGroup = this.defaultDropdownValue;
  285. this.target.azureMonitor.data[queryMode].metricDefinition = this.defaultDropdownValue;
  286. this.target.azureMonitor.data[queryMode].resourceName = this.defaultDropdownValue;
  287. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  288. this.target.azureMonitor.data[queryMode].aggregation = '';
  289. this.target.azureMonitor.data[queryMode].timeGrains = [];
  290. this.target.azureMonitor.data[queryMode].timeGrain = '';
  291. this.target.azureMonitor.data[queryMode].dimensions = [];
  292. this.target.azureMonitor.data[queryMode].dimension = '';
  293. }
  294. }
  295. async onSubscriptionsChange(values: any) {
  296. if (!_.isEqual(this.target.subscriptions.sort(), values.sort())) {
  297. this.target.subscriptions = values;
  298. this.resources = await this.datasource.getResources(this.target.subscriptions);
  299. const { queryMode } = this.target.azureMonitor;
  300. this.target.azureMonitor.data[queryMode].resourceGroup = this.defaultDropdownValue;
  301. this.target.azureMonitor.data[queryMode].metricDefinition = this.defaultDropdownValue;
  302. this.target.azureMonitor.data[queryMode].resourceName = this.defaultDropdownValue;
  303. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  304. this.target.azureMonitor.data[queryMode].aggregation = '';
  305. this.target.azureMonitor.data[queryMode].timeGrains = [];
  306. this.target.azureMonitor.data[queryMode].timeGrain = '';
  307. this.target.azureMonitor.data[queryMode].dimensions = [];
  308. this.target.azureMonitor.data[queryMode].dimension = '';
  309. this.updateLocations();
  310. this.updateCrossResourceGroups();
  311. }
  312. }
  313. /* Azure Monitor Section */
  314. getResourceGroups(query: any) {
  315. if (this.target.queryType !== 'Azure Monitor' || !this.datasource.azureMonitorDatasource.isConfigured()) {
  316. return;
  317. }
  318. return this.datasource
  319. .getResourceGroups(
  320. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId)
  321. )
  322. .catch(this.handleQueryCtrlError.bind(this));
  323. }
  324. getCrossResourceGroups() {
  325. if (this.target.queryType !== 'Azure Monitor' || !this.datasource.azureMonitorDatasource.isConfigured()) {
  326. return [];
  327. }
  328. return this.resources
  329. .filter(({ location, subscriptionId }) => {
  330. if (this.target.azureMonitor.data.crossResource.locations.length) {
  331. return (
  332. this.target.azureMonitor.data.crossResource.locations.includes(location) &&
  333. this.target.subscriptions.includes(subscriptionId)
  334. );
  335. }
  336. return this.target.subscriptions.includes(subscriptionId);
  337. })
  338. .reduce((options, { group }: Resource) => (options.some(o => o === group) ? options : [...options, group]), []);
  339. }
  340. async getCrossResourceMetricDefinitions(query: any) {
  341. const { locations, resourceGroups } = this.target.azureMonitor.data.crossResource;
  342. return this.resources
  343. .filter(({ location, group }) => locations.includes(location) && resourceGroups.includes(group))
  344. .reduce(
  345. (options: Option[], { type }: Resource) =>
  346. options.some(o => o.value === type) ? options : [...options, { text: type, value: type }],
  347. []
  348. );
  349. }
  350. getLocations() {
  351. return this.resources
  352. .filter(({ subscriptionId }) => this.target.subscriptions.includes(subscriptionId))
  353. .reduce(
  354. (options: string[], { location }: Resource) =>
  355. options.some(o => o === location) ? options : [...options, location],
  356. []
  357. );
  358. }
  359. getMetricDefinitions(query: any) {
  360. const { queryMode } = this.target.azureMonitor;
  361. if (
  362. this.target.queryType !== 'Azure Monitor' ||
  363. !this.target.azureMonitor.data[queryMode].resourceGroup ||
  364. this.target.azureMonitor.data[queryMode].resourceGroup === this.defaultDropdownValue
  365. ) {
  366. return;
  367. }
  368. return this.datasource
  369. .getMetricDefinitions(
  370. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  371. this.replace(this.target.azureMonitor.data[queryMode].resourceGroup)
  372. )
  373. .catch(this.handleQueryCtrlError.bind(this));
  374. }
  375. getResourceNames(query: any) {
  376. const { queryMode } = this.target.azureMonitor;
  377. if (
  378. this.target.queryType !== 'Azure Monitor' ||
  379. !this.target.azureMonitor.data[queryMode].resourceGroup ||
  380. this.target.azureMonitor.data[queryMode].resourceGroup === this.defaultDropdownValue ||
  381. !this.target.azureMonitor.data[queryMode].metricDefinition ||
  382. this.target.azureMonitor.data[queryMode].metricDefinition === this.defaultDropdownValue
  383. ) {
  384. return;
  385. }
  386. return this.datasource
  387. .getResourceNames(
  388. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  389. this.replace(this.target.azureMonitor.data[queryMode].resourceGroup),
  390. this.replace(this.target.azureMonitor.data[queryMode].metricDefinition)
  391. )
  392. .catch(this.handleQueryCtrlError.bind(this));
  393. }
  394. getMetricNamespaces() {
  395. const { queryMode } = this.target.azureMonitor;
  396. if (
  397. this.target.queryType !== 'Azure Monitor' ||
  398. !this.target.azureMonitor.data[queryMode].resourceGroup ||
  399. this.target.azureMonitor.data[queryMode].resourceGroup === this.defaultDropdownValue ||
  400. !this.target.azureMonitor.data[queryMode].metricDefinition ||
  401. this.target.azureMonitor.data[queryMode].metricDefinition === this.defaultDropdownValue ||
  402. !this.target.azureMonitor.data[queryMode].resourceName ||
  403. this.target.azureMonitor.data[queryMode].resourceName === this.defaultDropdownValue
  404. ) {
  405. return;
  406. }
  407. return this.datasource
  408. .getMetricNamespaces(
  409. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  410. this.replace(this.target.azureMonitor.data[queryMode].resourceGroup),
  411. this.replace(this.target.azureMonitor.data[queryMode].metricDefinition),
  412. this.replace(this.target.azureMonitor.data[queryMode].resourceName)
  413. )
  414. .catch(this.handleQueryCtrlError.bind(this));
  415. }
  416. async getCrossResourceMetricNames() {
  417. const { locations, resourceGroups, metricDefinition } = this.target.azureMonitor.data.crossResource;
  418. const resources = this.resources.filter(
  419. ({ type, location, name, group }) =>
  420. resourceGroups.includes(group) && type === metricDefinition && locations.includes(location)
  421. );
  422. const uniqueResources = _.uniqBy(resources, ({ subscriptionId, name, type, group }: Resource) =>
  423. [subscriptionId, name, locations, group].join()
  424. );
  425. const responses = await Promise.all(
  426. uniqueResources.map(({ subscriptionId, group, type, name }) =>
  427. this.datasource
  428. .getMetricNames(subscriptionId, group, type, name)
  429. .then((metrics: any) => metrics.map((m: any) => ({ ...m, subscriptionIds: [subscriptionId] })), [
  430. { text: this.defaultDropdownValue, value: this.defaultDropdownValue },
  431. ])
  432. )
  433. );
  434. return _.uniqBy(responses.reduce((result, resources) => [...result, ...resources], []), ({ value }) => value);
  435. }
  436. getMetricNames() {
  437. const { queryMode } = this.target.azureMonitor;
  438. if (
  439. this.target.queryType !== 'Azure Monitor' ||
  440. !this.target.azureMonitor.data[queryMode].resourceGroup ||
  441. this.target.azureMonitor.data[queryMode].resourceGroup === this.defaultDropdownValue ||
  442. !this.target.azureMonitor.data[queryMode].metricDefinition ||
  443. this.target.azureMonitor.data[queryMode].metricDefinition === this.defaultDropdownValue ||
  444. !this.target.azureMonitor.data[queryMode].resourceName ||
  445. this.target.azureMonitor.data[queryMode].resourceName === this.defaultDropdownValue ||
  446. !this.target.azureMonitor.data[queryMode].metricNamespace ||
  447. this.target.azureMonitor.data[queryMode].metricNamespace === this.defaultDropdownValue
  448. ) {
  449. return;
  450. }
  451. return this.datasource
  452. .getMetricNames(
  453. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  454. this.replace(this.target.azureMonitor.data[queryMode].resourceGroup),
  455. this.replace(this.target.azureMonitor.data[queryMode].metricDefinition),
  456. this.replace(this.target.azureMonitor.data[queryMode].resourceName),
  457. this.replace(this.target.azureMonitor.data[queryMode].metricNamespace)
  458. )
  459. .catch(this.handleQueryCtrlError.bind(this));
  460. }
  461. onResourceGroupChange() {
  462. const { queryMode } = this.target.azureMonitor;
  463. this.target.azureMonitor.data[queryMode].metricDefinition = this.defaultDropdownValue;
  464. this.target.azureMonitor.data[queryMode].resourceName = this.defaultDropdownValue;
  465. this.target.azureMonitor.data[queryMode].metricNamespace = this.defaultDropdownValue;
  466. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  467. this.target.azureMonitor.data[queryMode].aggregation = '';
  468. this.target.azureMonitor.data[queryMode].timeGrains = [];
  469. this.target.azureMonitor.data[queryMode].timeGrain = '';
  470. this.target.azureMonitor.data[queryMode].dimensions = [];
  471. this.target.azureMonitor.data[queryMode].dimension = '';
  472. this.refresh();
  473. }
  474. onCrossResourceGroupChange(values: string[]) {
  475. if (!_.isEqual(this.target.azureMonitor.data.crossResource.resourceGroups.sort(), values.sort())) {
  476. this.target.azureMonitor.data.crossResource.resourceGroups = values;
  477. const { queryMode } = this.target.azureMonitor;
  478. this.target.azureMonitor.data[queryMode].metricDefinition = '';
  479. this.target.azureMonitor.data[queryMode].metricName = '';
  480. this.refresh();
  481. }
  482. }
  483. onCrossResourceMetricDefinitionChange() {
  484. const { queryMode } = this.target.azureMonitor;
  485. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  486. this.target.azureMonitor.data[queryMode].aggregation = '';
  487. this.target.azureMonitor.data[queryMode].timeGrains = [];
  488. this.target.azureMonitor.data[queryMode].timeGrain = '';
  489. this.target.azureMonitor.data[queryMode].dimensions = [];
  490. this.target.azureMonitor.data[queryMode].dimension = '';
  491. this.refresh();
  492. }
  493. async onLocationsChange(values: string[]) {
  494. if (!_.isEqual(this.target.azureMonitor.data.crossResource.locations.sort(), values.sort())) {
  495. this.target.azureMonitor.data.crossResource.locations = values;
  496. const { queryMode } = this.target.azureMonitor;
  497. this.target.azureMonitor.data[queryMode].metricDefinition = '';
  498. this.target.azureMonitor.data[queryMode].resourceGroup = '';
  499. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  500. this.target.azureMonitor.data[queryMode].aggregation = '';
  501. this.target.azureMonitor.data[queryMode].timeGrains = [];
  502. this.target.azureMonitor.data[queryMode].timeGrain = '';
  503. this.target.azureMonitor.data[queryMode].dimensions = [];
  504. this.target.azureMonitor.data[queryMode].dimension = '';
  505. this.updateCrossResourceGroups();
  506. this.refresh();
  507. }
  508. }
  509. onMetricDefinitionChange() {
  510. const { queryMode } = this.target.azureMonitor;
  511. this.target.azureMonitor.data[queryMode].resourceName = this.defaultDropdownValue;
  512. this.target.azureMonitor.data[queryMode].metricNamespace = this.defaultDropdownValue;
  513. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  514. this.target.azureMonitor.data[queryMode].aggregation = '';
  515. this.target.azureMonitor.data[queryMode].timeGrains = [];
  516. this.target.azureMonitor.data[queryMode].timeGrain = '';
  517. this.target.azureMonitor.data[queryMode].dimensions = [];
  518. this.target.azureMonitor.data[queryMode].dimension = '';
  519. }
  520. onResourceNameChange() {
  521. const { queryMode } = this.target.azureMonitor;
  522. this.target.azureMonitor.data[queryMode].metricNamespace = this.defaultDropdownValue;
  523. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  524. this.target.azureMonitor.data[queryMode].aggregation = '';
  525. this.target.azureMonitor.data[queryMode].timeGrains = [];
  526. this.target.azureMonitor.data[queryMode].timeGrain = '';
  527. this.target.azureMonitor.data[queryMode].dimensions = [];
  528. this.target.azureMonitor.data[queryMode].dimension = '';
  529. this.refresh();
  530. }
  531. onMetricNamespacesChange() {
  532. const { queryMode } = this.target.azureMonitor;
  533. this.target.azureMonitor.data[queryMode].metricName = this.defaultDropdownValue;
  534. this.target.azureMonitor.data[queryMode].dimensions = [];
  535. this.target.azureMonitor.data[queryMode].dimension = '';
  536. }
  537. setMetricMetadata(metadata: any) {
  538. const { queryMode } = this.target.azureMonitor;
  539. this.target.azureMonitor.data[queryMode].aggOptions = metadata.supportedAggTypes || [metadata.primaryAggType];
  540. this.target.azureMonitor.data[queryMode].aggregation = metadata.primaryAggType;
  541. this.target.azureMonitor.data[queryMode].timeGrains = [{ text: 'auto', value: 'auto' }].concat(
  542. metadata.supportedTimeGrains
  543. );
  544. this.target.azureMonitor.data[queryMode].timeGrain = 'auto';
  545. this.target.azureMonitor.data[queryMode].allowedTimeGrainsMs = this.convertTimeGrainsToMs(
  546. metadata.supportedTimeGrains || []
  547. );
  548. this.target.azureMonitor.data[queryMode].dimensions = metadata.dimensions;
  549. if (metadata.dimensions.length > 0) {
  550. this.target.azureMonitor.data[queryMode].dimension = metadata.dimensions[0].value;
  551. }
  552. return this.refresh();
  553. }
  554. onCrossResourceMetricNameChange() {
  555. const { queryMode } = this.target.azureMonitor;
  556. if (
  557. !this.target.azureMonitor.data[queryMode].metricName ||
  558. this.target.azureMonitor.data[queryMode].metricName === this.defaultDropdownValue
  559. ) {
  560. return;
  561. }
  562. const { resourceGroups, metricDefinition, metricName } = this.target.azureMonitor.data[queryMode];
  563. const resource = this.resources.find(
  564. ({ type, group }) => type === metricDefinition && resourceGroups.includes(group)
  565. );
  566. return this.datasource
  567. .getMetricMetadata(
  568. this.replace(this.target.subscriptions[0]),
  569. resource.group,
  570. metricDefinition,
  571. resource.name,
  572. metricName
  573. )
  574. .then(this.setMetricMetadata.bind(this))
  575. .then(() => this.refresh())
  576. .catch(this.handleQueryCtrlError.bind(this));
  577. }
  578. onMetricNameChange() {
  579. const { queryMode } = this.target.azureMonitor;
  580. if (
  581. !this.target.azureMonitor.data[queryMode].metricName ||
  582. this.target.azureMonitor.data[queryMode].metricName === this.defaultDropdownValue
  583. ) {
  584. return;
  585. }
  586. return this.datasource
  587. .getMetricMetadata(
  588. this.replace(this.target.subscription),
  589. this.replace(this.target.azureMonitor.data[queryMode].resourceGroup),
  590. this.replace(this.target.azureMonitor.data[queryMode].metricDefinition),
  591. this.replace(this.target.azureMonitor.data[queryMode].resourceName),
  592. this.replace(this.target.azureMonitor.data[queryMode].metricName),
  593. this.replace(this.target.azureMonitor.data[queryMode].metricNamespace)
  594. )
  595. .then(this.setMetricMetadata.bind(this))
  596. .catch(this.handleQueryCtrlError.bind(this));
  597. }
  598. convertTimeGrainsToMs(timeGrains: Option[]) {
  599. const allowedTimeGrainsMs: number[] = [];
  600. timeGrains.forEach((tg: any) => {
  601. if (tg.value !== 'auto') {
  602. allowedTimeGrainsMs.push(kbn.interval_to_ms(TimegrainConverter.createKbnUnitFromISO8601Duration(tg.value)));
  603. }
  604. });
  605. return allowedTimeGrainsMs;
  606. }
  607. getAutoInterval() {
  608. const { queryMode } = this.target.azureMonitor;
  609. if (this.target.azureMonitor.data[queryMode].timeGrain === 'auto') {
  610. return TimegrainConverter.findClosestTimeGrain(
  611. this.templateSrv.getBuiltInIntervalValue(),
  612. _.map(this.target.azureMonitor.data[queryMode].timeGrains, o =>
  613. TimegrainConverter.createKbnUnitFromISO8601Duration(o.value)
  614. ) || ['1m', '5m', '15m', '30m', '1h', '6h', '12h', '1d']
  615. );
  616. }
  617. return '';
  618. }
  619. /* Azure Log Analytics */
  620. getWorkspaces = () => {
  621. return this.datasource.azureLogAnalyticsDatasource
  622. .getWorkspaces(this.target.subscription)
  623. .then((list: any[]) => {
  624. this.workspaces = list;
  625. if (list.length > 0 && !this.target.azureLogAnalytics.workspace) {
  626. this.target.azureLogAnalytics.workspace = list[0].value;
  627. }
  628. })
  629. .catch(this.handleQueryCtrlError.bind(this));
  630. };
  631. getAzureLogAnalyticsSchema = () => {
  632. return this.getWorkspaces()
  633. .then(() => {
  634. return this.datasource.azureLogAnalyticsDatasource.getSchema(this.target.azureLogAnalytics.workspace);
  635. })
  636. .catch(this.handleQueryCtrlError.bind(this));
  637. };
  638. onLogAnalyticsQueryChange = (nextQuery: string) => {
  639. this.target.azureLogAnalytics.query = nextQuery;
  640. };
  641. onLogAnalyticsQueryExecute = () => {
  642. this.panelCtrl.refresh();
  643. };
  644. get templateVariables() {
  645. return this.templateSrv.variables.map(t => '$' + t.name);
  646. }
  647. /* Application Insights Section */
  648. getAppInsightsAutoInterval() {
  649. const interval = this.templateSrv.getBuiltInIntervalValue();
  650. if (interval[interval.length - 1] === 's') {
  651. return '1m';
  652. }
  653. return interval;
  654. }
  655. getAppInsightsMetricNames() {
  656. if (!this.datasource.appInsightsDatasource.isConfigured()) {
  657. return;
  658. }
  659. return this.datasource.getAppInsightsMetricNames().catch(this.handleQueryCtrlError.bind(this));
  660. }
  661. getAppInsightsColumns() {
  662. return this.datasource.getAppInsightsColumns(this.target.refId);
  663. }
  664. onAppInsightsColumnChange() {
  665. return this.refresh();
  666. }
  667. onAppInsightsMetricNameChange() {
  668. if (!this.target.appInsights.metricName || this.target.appInsights.metricName === this.defaultDropdownValue) {
  669. return;
  670. }
  671. return this.datasource
  672. .getAppInsightsMetricMetadata(this.replace(this.target.appInsights.metricName))
  673. .then((aggData: { supportedAggTypes: string[]; supportedGroupBy: string[]; primaryAggType: string }) => {
  674. this.target.appInsights.aggOptions = aggData.supportedAggTypes;
  675. this.target.appInsights.groupByOptions = aggData.supportedGroupBy;
  676. this.target.appInsights.aggregation = aggData.primaryAggType;
  677. return this.refresh();
  678. })
  679. .catch(this.handleQueryCtrlError.bind(this));
  680. }
  681. onAppInsightsQueryChange = (nextQuery: string) => {
  682. this.target.appInsights.rawQueryString = nextQuery;
  683. };
  684. onAppInsightsQueryExecute = () => {
  685. return this.refresh();
  686. };
  687. getAppInsightsQuerySchema = () => {
  688. return this.datasource.appInsightsDatasource.getQuerySchema().catch(this.handleQueryCtrlError.bind(this));
  689. };
  690. getAppInsightsGroupBySegments(query: any) {
  691. return _.map(this.target.appInsights.groupByOptions, option => {
  692. return { text: option, value: option };
  693. });
  694. }
  695. resetAppInsightsGroupBy() {
  696. this.target.appInsights.groupBy = 'none';
  697. this.refresh();
  698. }
  699. updateTimeGrainType() {
  700. if (this.target.appInsights.timeGrainType === 'specific') {
  701. this.target.appInsights.timeGrain = '1';
  702. this.target.appInsights.timeGrainUnit = 'minute';
  703. } else {
  704. this.target.appInsights.timeGrain = '';
  705. }
  706. this.refresh();
  707. }
  708. toggleEditorMode() {
  709. this.target.appInsights.rawQuery = !this.target.appInsights.rawQuery;
  710. }
  711. }