query_ctrl.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. import _ from 'lodash';
  2. import { QueryCtrl } from 'app/plugins/sdk';
  3. // import './css/query_editor.css';
  4. import TimegrainConverter from './time_grain_converter';
  5. import './editor/editor_component';
  6. import { TemplateSrv } from 'app/features/templating/template_srv';
  7. import { auto } from 'angular';
  8. export interface ResultFormat {
  9. text: string;
  10. value: string;
  11. }
  12. export class AzureMonitorQueryCtrl extends QueryCtrl {
  13. static templateUrl = 'partials/query.editor.html';
  14. defaultDropdownValue = 'select';
  15. target: {
  16. refId: string;
  17. queryType: string;
  18. subscription: string;
  19. azureMonitor: {
  20. resourceGroup: string;
  21. resourceName: string;
  22. metricDefinition: string;
  23. metricName: string;
  24. dimensionFilter: string;
  25. timeGrain: string;
  26. timeGrainUnit: string;
  27. timeGrains: any[];
  28. dimensions: any[];
  29. dimension: any;
  30. aggregation: string;
  31. aggOptions: string[];
  32. };
  33. azureLogAnalytics: {
  34. query: string;
  35. resultFormat: string;
  36. workspace: string;
  37. };
  38. appInsights: {
  39. metricName: string;
  40. rawQuery: boolean;
  41. rawQueryString: string;
  42. groupBy: string;
  43. timeGrainType: string;
  44. xaxis: string;
  45. yaxis: string;
  46. spliton: string;
  47. aggOptions: string[];
  48. aggregation: string;
  49. groupByOptions: string[];
  50. timeGrainUnit: string;
  51. timeGrain: string;
  52. };
  53. };
  54. defaults = {
  55. queryType: 'Azure Monitor',
  56. azureMonitor: {
  57. resourceGroup: this.defaultDropdownValue,
  58. metricDefinition: this.defaultDropdownValue,
  59. resourceName: this.defaultDropdownValue,
  60. metricName: this.defaultDropdownValue,
  61. dimensionFilter: '*',
  62. timeGrain: 'auto',
  63. },
  64. azureLogAnalytics: {
  65. query: [
  66. '//change this example to create your own time series query',
  67. '<table name> ' +
  68. '//the table to query (e.g. Usage, Heartbeat, Perf)',
  69. '| where $__timeFilter(TimeGenerated) ' +
  70. '//this is a macro used to show the full chart’s time range, choose the datetime column here',
  71. '| summarize count() by <group by column>, bin(TimeGenerated, $__interval) ' +
  72. '//change “group by column” to a column in your table, such as “Computer”. ' +
  73. 'The $__interval macro is used to auto-select the time grain. Can also use 1h, 5m etc.',
  74. '| order by TimeGenerated asc',
  75. ].join('\n'),
  76. resultFormat: 'time_series',
  77. workspace:
  78. this.datasource && this.datasource.azureLogAnalyticsDatasource
  79. ? this.datasource.azureLogAnalyticsDatasource.defaultOrFirstWorkspace
  80. : '',
  81. },
  82. appInsights: {
  83. metricName: this.defaultDropdownValue,
  84. rawQuery: false,
  85. rawQueryString: '',
  86. groupBy: 'none',
  87. timeGrainType: 'auto',
  88. xaxis: 'timestamp',
  89. yaxis: '',
  90. spliton: '',
  91. },
  92. };
  93. resultFormats: ResultFormat[];
  94. workspaces: any[];
  95. showHelp: boolean;
  96. showLastQuery: boolean;
  97. lastQuery: string;
  98. lastQueryError?: string;
  99. subscriptions: Array<{ text: string; value: string }>;
  100. /** @ngInject */
  101. constructor($scope: any, $injector: auto.IInjectorService, private templateSrv: TemplateSrv) {
  102. super($scope, $injector);
  103. _.defaultsDeep(this.target, this.defaults);
  104. this.migrateTimeGrains();
  105. this.migrateToFromTimes();
  106. this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
  107. this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
  108. this.resultFormats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
  109. this.getSubscriptions();
  110. if (this.target.queryType === 'Azure Log Analytics') {
  111. this.getWorkspaces();
  112. }
  113. }
  114. onDataReceived(dataList) {
  115. this.lastQueryError = undefined;
  116. this.lastQuery = '';
  117. const anySeriesFromQuery: any = _.find(dataList, { refId: this.target.refId });
  118. if (anySeriesFromQuery && anySeriesFromQuery.meta) {
  119. this.lastQuery = anySeriesFromQuery.meta.query;
  120. }
  121. }
  122. onDataError(err) {
  123. this.handleQueryCtrlError(err);
  124. }
  125. handleQueryCtrlError(err) {
  126. if (err.query && err.query.refId && err.query.refId !== this.target.refId) {
  127. return;
  128. }
  129. if (err.error && err.error.data && err.error.data.error && err.error.data.error.innererror) {
  130. if (err.error.data.error.innererror.innererror) {
  131. this.lastQueryError = err.error.data.error.innererror.innererror.message;
  132. } else {
  133. this.lastQueryError = err.error.data.error.innererror.message;
  134. }
  135. } else if (err.error && err.error.data && err.error.data.error) {
  136. this.lastQueryError = err.error.data.error.message;
  137. } else if (err.error && err.error.data) {
  138. this.lastQueryError = err.error.data.message;
  139. } else if (err.data && err.data.error) {
  140. this.lastQueryError = err.data.error.message;
  141. } else if (err.data && err.data.message) {
  142. this.lastQueryError = err.data.message;
  143. } else {
  144. this.lastQueryError = err;
  145. }
  146. }
  147. migrateTimeGrains() {
  148. if (this.target.azureMonitor.timeGrainUnit) {
  149. if (this.target.azureMonitor.timeGrain !== 'auto') {
  150. this.target.azureMonitor.timeGrain = TimegrainConverter.createISO8601Duration(
  151. this.target.azureMonitor.timeGrain,
  152. this.target.azureMonitor.timeGrainUnit
  153. );
  154. }
  155. delete this.target.azureMonitor.timeGrainUnit;
  156. this.onMetricNameChange();
  157. }
  158. }
  159. migrateToFromTimes() {
  160. this.target.azureLogAnalytics.query = this.target.azureLogAnalytics.query.replace(/\$__from\s/gi, '$__timeFrom() ');
  161. this.target.azureLogAnalytics.query = this.target.azureLogAnalytics.query.replace(/\$__to\s/gi, '$__timeTo() ');
  162. }
  163. replace(variable: string) {
  164. return this.templateSrv.replace(variable, this.panelCtrl.panel.scopedVars);
  165. }
  166. onQueryTypeChange() {
  167. if (this.target.queryType === 'Azure Log Analytics') {
  168. return this.getWorkspaces();
  169. }
  170. }
  171. getSubscriptions() {
  172. if (!this.datasource.azureMonitorDatasource.isConfigured()) {
  173. return;
  174. }
  175. return this.datasource.azureMonitorDatasource.getSubscriptions().then(subs => {
  176. this.subscriptions = subs;
  177. if (!this.target.subscription && this.target.queryType === 'Azure Monitor') {
  178. this.target.subscription = this.datasource.azureMonitorDatasource.subscriptionId;
  179. } else if (!this.target.subscription && this.target.queryType === 'Azure Log Analytics') {
  180. this.target.subscription = this.datasource.azureLogAnalyticsDatasource.logAnalyticsSubscriptionId;
  181. }
  182. if (!this.target.subscription && this.subscriptions.length > 0) {
  183. this.target.subscription = this.subscriptions[0].value;
  184. }
  185. return this.subscriptions;
  186. });
  187. }
  188. onSubscriptionChange() {
  189. if (this.target.queryType === 'Azure Log Analytics') {
  190. return this.getWorkspaces();
  191. }
  192. if (this.target.queryType === 'Azure Monitor') {
  193. this.target.azureMonitor.resourceGroup = this.defaultDropdownValue;
  194. this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
  195. this.target.azureMonitor.resourceName = this.defaultDropdownValue;
  196. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  197. this.target.azureMonitor.aggregation = '';
  198. this.target.azureMonitor.timeGrains = [];
  199. this.target.azureMonitor.timeGrain = '';
  200. this.target.azureMonitor.dimensions = [];
  201. this.target.azureMonitor.dimension = '';
  202. }
  203. }
  204. /* Azure Monitor Section */
  205. getResourceGroups(query) {
  206. if (this.target.queryType !== 'Azure Monitor' || !this.datasource.azureMonitorDatasource.isConfigured()) {
  207. return;
  208. }
  209. return this.datasource
  210. .getResourceGroups(
  211. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId)
  212. )
  213. .catch(this.handleQueryCtrlError.bind(this));
  214. }
  215. getMetricDefinitions(query) {
  216. if (
  217. this.target.queryType !== 'Azure Monitor' ||
  218. !this.target.azureMonitor.resourceGroup ||
  219. this.target.azureMonitor.resourceGroup === this.defaultDropdownValue
  220. ) {
  221. return;
  222. }
  223. return this.datasource
  224. .getMetricDefinitions(
  225. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  226. this.replace(this.target.azureMonitor.resourceGroup)
  227. )
  228. .catch(this.handleQueryCtrlError.bind(this));
  229. }
  230. getResourceNames(query) {
  231. if (
  232. this.target.queryType !== 'Azure Monitor' ||
  233. !this.target.azureMonitor.resourceGroup ||
  234. this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
  235. !this.target.azureMonitor.metricDefinition ||
  236. this.target.azureMonitor.metricDefinition === this.defaultDropdownValue
  237. ) {
  238. return;
  239. }
  240. return this.datasource
  241. .getResourceNames(
  242. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  243. this.replace(this.target.azureMonitor.resourceGroup),
  244. this.replace(this.target.azureMonitor.metricDefinition)
  245. )
  246. .catch(this.handleQueryCtrlError.bind(this));
  247. }
  248. getMetricNames(query) {
  249. if (
  250. this.target.queryType !== 'Azure Monitor' ||
  251. !this.target.azureMonitor.resourceGroup ||
  252. this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
  253. !this.target.azureMonitor.metricDefinition ||
  254. this.target.azureMonitor.metricDefinition === this.defaultDropdownValue ||
  255. !this.target.azureMonitor.resourceName ||
  256. this.target.azureMonitor.resourceName === this.defaultDropdownValue
  257. ) {
  258. return;
  259. }
  260. return this.datasource
  261. .getMetricNames(
  262. this.replace(this.target.subscription || this.datasource.azureMonitorDatasource.subscriptionId),
  263. this.replace(this.target.azureMonitor.resourceGroup),
  264. this.replace(this.target.azureMonitor.metricDefinition),
  265. this.replace(this.target.azureMonitor.resourceName)
  266. )
  267. .catch(this.handleQueryCtrlError.bind(this));
  268. }
  269. onResourceGroupChange() {
  270. this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
  271. this.target.azureMonitor.resourceName = this.defaultDropdownValue;
  272. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  273. this.target.azureMonitor.aggregation = '';
  274. this.target.azureMonitor.timeGrains = [];
  275. this.target.azureMonitor.timeGrain = '';
  276. this.target.azureMonitor.dimensions = [];
  277. this.target.azureMonitor.dimension = '';
  278. }
  279. onMetricDefinitionChange() {
  280. this.target.azureMonitor.resourceName = this.defaultDropdownValue;
  281. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  282. this.target.azureMonitor.aggregation = '';
  283. this.target.azureMonitor.timeGrains = [];
  284. this.target.azureMonitor.timeGrain = '';
  285. this.target.azureMonitor.dimensions = [];
  286. this.target.azureMonitor.dimension = '';
  287. }
  288. onResourceNameChange() {
  289. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  290. this.target.azureMonitor.aggregation = '';
  291. this.target.azureMonitor.timeGrains = [];
  292. this.target.azureMonitor.timeGrain = '';
  293. this.target.azureMonitor.dimensions = [];
  294. this.target.azureMonitor.dimension = '';
  295. }
  296. onMetricNameChange() {
  297. if (!this.target.azureMonitor.metricName || this.target.azureMonitor.metricName === this.defaultDropdownValue) {
  298. return;
  299. }
  300. return this.datasource
  301. .getMetricMetadata(
  302. this.replace(this.target.subscription),
  303. this.replace(this.target.azureMonitor.resourceGroup),
  304. this.replace(this.target.azureMonitor.metricDefinition),
  305. this.replace(this.target.azureMonitor.resourceName),
  306. this.replace(this.target.azureMonitor.metricName)
  307. )
  308. .then(metadata => {
  309. this.target.azureMonitor.aggOptions = metadata.supportedAggTypes || [metadata.primaryAggType];
  310. this.target.azureMonitor.aggregation = metadata.primaryAggType;
  311. this.target.azureMonitor.timeGrains = [{ text: 'auto', value: 'auto' }].concat(metadata.supportedTimeGrains);
  312. this.target.azureMonitor.timeGrain = 'auto';
  313. this.target.azureMonitor.dimensions = metadata.dimensions;
  314. if (metadata.dimensions.length > 0) {
  315. this.target.azureMonitor.dimension = metadata.dimensions[0].value;
  316. }
  317. return this.refresh();
  318. })
  319. .catch(this.handleQueryCtrlError.bind(this));
  320. }
  321. getAutoInterval() {
  322. if (this.target.azureMonitor.timeGrain === 'auto') {
  323. return TimegrainConverter.findClosestTimeGrain(
  324. this.templateSrv.getBuiltInIntervalValue(),
  325. _.map(this.target.azureMonitor.timeGrains, o =>
  326. TimegrainConverter.createKbnUnitFromISO8601Duration(o.value)
  327. ) || ['1m', '5m', '15m', '30m', '1h', '6h', '12h', '1d']
  328. );
  329. }
  330. return '';
  331. }
  332. /* Azure Log Analytics */
  333. getWorkspaces = () => {
  334. return this.datasource.azureLogAnalyticsDatasource
  335. .getWorkspaces(this.target.subscription)
  336. .then(list => {
  337. this.workspaces = list;
  338. if (list.length > 0 && !this.target.azureLogAnalytics.workspace) {
  339. this.target.azureLogAnalytics.workspace = list[0].value;
  340. }
  341. })
  342. .catch(this.handleQueryCtrlError.bind(this));
  343. };
  344. getAzureLogAnalyticsSchema = () => {
  345. return this.getWorkspaces()
  346. .then(() => {
  347. return this.datasource.azureLogAnalyticsDatasource.getSchema(this.target.azureLogAnalytics.workspace);
  348. })
  349. .catch(this.handleQueryCtrlError.bind(this));
  350. };
  351. onLogAnalyticsQueryChange = (nextQuery: string) => {
  352. this.target.azureLogAnalytics.query = nextQuery;
  353. };
  354. onLogAnalyticsQueryExecute = () => {
  355. this.panelCtrl.refresh();
  356. };
  357. get templateVariables() {
  358. return this.templateSrv.variables.map(t => '$' + t.name);
  359. }
  360. /* Application Insights Section */
  361. getAppInsightsAutoInterval() {
  362. const interval = this.templateSrv.getBuiltInIntervalValue();
  363. if (interval[interval.length - 1] === 's') {
  364. return '1m';
  365. }
  366. return interval;
  367. }
  368. getAppInsightsMetricNames() {
  369. if (!this.datasource.appInsightsDatasource.isConfigured()) {
  370. return;
  371. }
  372. return this.datasource.getAppInsightsMetricNames().catch(this.handleQueryCtrlError.bind(this));
  373. }
  374. getAppInsightsColumns() {
  375. return this.datasource.getAppInsightsColumns(this.target.refId);
  376. }
  377. onAppInsightsColumnChange() {
  378. return this.refresh();
  379. }
  380. onAppInsightsMetricNameChange() {
  381. if (!this.target.appInsights.metricName || this.target.appInsights.metricName === this.defaultDropdownValue) {
  382. return;
  383. }
  384. return this.datasource
  385. .getAppInsightsMetricMetadata(this.replace(this.target.appInsights.metricName))
  386. .then(aggData => {
  387. this.target.appInsights.aggOptions = aggData.supportedAggTypes;
  388. this.target.appInsights.groupByOptions = aggData.supportedGroupBy;
  389. this.target.appInsights.aggregation = aggData.primaryAggType;
  390. return this.refresh();
  391. })
  392. .catch(this.handleQueryCtrlError.bind(this));
  393. }
  394. onAppInsightsQueryChange = (nextQuery: string) => {
  395. this.target.appInsights.rawQueryString = nextQuery;
  396. };
  397. onAppInsightsQueryExecute = () => {
  398. return this.refresh();
  399. };
  400. getAppInsightsQuerySchema = () => {
  401. return this.datasource.appInsightsDatasource.getQuerySchema().catch(this.handleQueryCtrlError.bind(this));
  402. };
  403. getAppInsightsGroupBySegments(query) {
  404. return _.map(this.target.appInsights.groupByOptions, option => {
  405. return { text: option, value: option };
  406. });
  407. }
  408. resetAppInsightsGroupBy() {
  409. this.target.appInsights.groupBy = 'none';
  410. this.refresh();
  411. }
  412. updateTimeGrainType() {
  413. if (this.target.appInsights.timeGrainType === 'specific') {
  414. this.target.appInsights.timeGrain = '1';
  415. this.target.appInsights.timeGrainUnit = 'minute';
  416. } else {
  417. this.target.appInsights.timeGrain = '';
  418. }
  419. this.refresh();
  420. }
  421. toggleEditorMode() {
  422. this.target.appInsights.rawQuery = !this.target.appInsights.rawQuery;
  423. }
  424. }