query_ctrl.ts 14 KB

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