query_ctrl.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  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 './monaco/kusto_monaco_editor';
  6. import './editor/editor_component';
  7. export interface ResultFormat {
  8. text: string;
  9. value: string;
  10. }
  11. export class AzureMonitorQueryCtrl extends QueryCtrl {
  12. static templateUrl = 'partials/query.editor.html';
  13. defaultDropdownValue = 'select';
  14. target: {
  15. refId: string;
  16. queryType: 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. /** @ngInject */
  98. constructor($scope, $injector, private templateSrv) {
  99. super($scope, $injector);
  100. _.defaultsDeep(this.target, this.defaults);
  101. this.migrateTimeGrains();
  102. this.panelCtrl.events.on('data-received', this.onDataReceived.bind(this), $scope);
  103. this.panelCtrl.events.on('data-error', this.onDataError.bind(this), $scope);
  104. this.resultFormats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
  105. if (this.target.queryType === 'Azure Log Analytics') {
  106. this.getWorkspaces();
  107. }
  108. }
  109. onDataReceived(dataList) {
  110. this.lastQueryError = undefined;
  111. this.lastQuery = '';
  112. const anySeriesFromQuery: any = _.find(dataList, { refId: this.target.refId });
  113. if (anySeriesFromQuery) {
  114. this.lastQuery = anySeriesFromQuery.query;
  115. }
  116. }
  117. onDataError(err) {
  118. this.handleQueryCtrlError(err);
  119. }
  120. handleQueryCtrlError(err) {
  121. if (err.query && err.query.refId && err.query.refId !== this.target.refId) {
  122. return;
  123. }
  124. if (err.error && err.error.data && err.error.data.error && err.error.data.error.innererror) {
  125. if (err.error.data.error.innererror.innererror) {
  126. this.lastQueryError = err.error.data.error.innererror.innererror.message;
  127. } else {
  128. this.lastQueryError = err.error.data.error.innererror.message;
  129. }
  130. } else if (err.error && err.error.data && err.error.data.error) {
  131. this.lastQueryError = err.error.data.error.message;
  132. } else if (err.error && err.error.data) {
  133. this.lastQueryError = err.error.data.message;
  134. } else if (err.data && err.data.error) {
  135. this.lastQueryError = err.data.error.message;
  136. } else if (err.data && err.data.message) {
  137. this.lastQueryError = err.data.message;
  138. } else {
  139. this.lastQueryError = err;
  140. }
  141. }
  142. migrateTimeGrains() {
  143. if (this.target.azureMonitor.timeGrainUnit) {
  144. if (this.target.azureMonitor.timeGrain !== 'auto') {
  145. this.target.azureMonitor.timeGrain = TimegrainConverter.createISO8601Duration(
  146. this.target.azureMonitor.timeGrain,
  147. this.target.azureMonitor.timeGrainUnit
  148. );
  149. }
  150. delete this.target.azureMonitor.timeGrainUnit;
  151. this.onMetricNameChange();
  152. }
  153. }
  154. replace(variable: string) {
  155. return this.templateSrv.replace(variable, this.panelCtrl.panel.scopedVars);
  156. }
  157. onQueryTypeChange() {
  158. if (this.target.queryType === 'Azure Log Analytics') {
  159. return this.getWorkspaces();
  160. }
  161. }
  162. /* Azure Monitor Section */
  163. getResourceGroups(query) {
  164. if (this.target.queryType !== 'Azure Monitor' || !this.datasource.azureMonitorDatasource.isConfigured()) {
  165. return;
  166. }
  167. return this.datasource.getResourceGroups().catch(this.handleQueryCtrlError.bind(this));
  168. }
  169. getMetricDefinitions(query) {
  170. if (
  171. this.target.queryType !== 'Azure Monitor' ||
  172. !this.target.azureMonitor.resourceGroup ||
  173. this.target.azureMonitor.resourceGroup === this.defaultDropdownValue
  174. ) {
  175. return;
  176. }
  177. return this.datasource
  178. .getMetricDefinitions(this.replace(this.target.azureMonitor.resourceGroup))
  179. .catch(this.handleQueryCtrlError.bind(this));
  180. }
  181. getResourceNames(query) {
  182. if (
  183. this.target.queryType !== 'Azure Monitor' ||
  184. !this.target.azureMonitor.resourceGroup ||
  185. this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
  186. !this.target.azureMonitor.metricDefinition ||
  187. this.target.azureMonitor.metricDefinition === this.defaultDropdownValue
  188. ) {
  189. return;
  190. }
  191. return this.datasource
  192. .getResourceNames(
  193. this.replace(this.target.azureMonitor.resourceGroup),
  194. this.replace(this.target.azureMonitor.metricDefinition)
  195. )
  196. .catch(this.handleQueryCtrlError.bind(this));
  197. }
  198. getMetricNames(query) {
  199. if (
  200. this.target.queryType !== 'Azure Monitor' ||
  201. !this.target.azureMonitor.resourceGroup ||
  202. this.target.azureMonitor.resourceGroup === this.defaultDropdownValue ||
  203. !this.target.azureMonitor.metricDefinition ||
  204. this.target.azureMonitor.metricDefinition === this.defaultDropdownValue ||
  205. !this.target.azureMonitor.resourceName ||
  206. this.target.azureMonitor.resourceName === this.defaultDropdownValue
  207. ) {
  208. return;
  209. }
  210. return this.datasource
  211. .getMetricNames(
  212. this.replace(this.target.azureMonitor.resourceGroup),
  213. this.replace(this.target.azureMonitor.metricDefinition),
  214. this.replace(this.target.azureMonitor.resourceName)
  215. )
  216. .catch(this.handleQueryCtrlError.bind(this));
  217. }
  218. onResourceGroupChange() {
  219. this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
  220. this.target.azureMonitor.resourceName = this.defaultDropdownValue;
  221. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  222. this.target.azureMonitor.dimensions = [];
  223. this.target.azureMonitor.dimension = '';
  224. }
  225. onMetricDefinitionChange() {
  226. this.target.azureMonitor.resourceName = this.defaultDropdownValue;
  227. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  228. this.target.azureMonitor.dimensions = [];
  229. this.target.azureMonitor.dimension = '';
  230. }
  231. onResourceNameChange() {
  232. this.target.azureMonitor.metricName = this.defaultDropdownValue;
  233. this.target.azureMonitor.dimensions = [];
  234. this.target.azureMonitor.dimension = '';
  235. }
  236. onMetricNameChange() {
  237. if (!this.target.azureMonitor.metricName || this.target.azureMonitor.metricName === this.defaultDropdownValue) {
  238. return;
  239. }
  240. return this.datasource
  241. .getMetricMetadata(
  242. this.replace(this.target.azureMonitor.resourceGroup),
  243. this.replace(this.target.azureMonitor.metricDefinition),
  244. this.replace(this.target.azureMonitor.resourceName),
  245. this.replace(this.target.azureMonitor.metricName)
  246. )
  247. .then(metadata => {
  248. this.target.azureMonitor.aggOptions = metadata.supportedAggTypes || [metadata.primaryAggType];
  249. this.target.azureMonitor.aggregation = metadata.primaryAggType;
  250. this.target.azureMonitor.timeGrains = [{ text: 'auto', value: 'auto' }].concat(metadata.supportedTimeGrains);
  251. this.target.azureMonitor.dimensions = metadata.dimensions;
  252. if (metadata.dimensions.length > 0) {
  253. this.target.azureMonitor.dimension = metadata.dimensions[0].value;
  254. }
  255. return this.refresh();
  256. })
  257. .catch(this.handleQueryCtrlError.bind(this));
  258. }
  259. getAutoInterval() {
  260. if (this.target.azureMonitor.timeGrain === 'auto') {
  261. return TimegrainConverter.findClosestTimeGrain(
  262. this.templateSrv.builtIns.__interval.value,
  263. _.map(this.target.azureMonitor.timeGrains, o =>
  264. TimegrainConverter.createKbnUnitFromISO8601Duration(o.value)
  265. ) || ['1m', '5m', '15m', '30m', '1h', '6h', '12h', '1d']
  266. );
  267. }
  268. return '';
  269. }
  270. /* Azure Log Analytics */
  271. getWorkspaces = () => {
  272. return this.datasource.azureLogAnalyticsDatasource
  273. .getWorkspaces()
  274. .then(list => {
  275. this.workspaces = list;
  276. if (list.length > 0 && !this.target.azureLogAnalytics.workspace) {
  277. this.target.azureLogAnalytics.workspace = list[0].value;
  278. }
  279. })
  280. .catch(this.handleQueryCtrlError.bind(this));
  281. };
  282. getAzureLogAnalyticsSchema = () => {
  283. return this.getWorkspaces()
  284. .then(() => {
  285. return this.datasource.azureLogAnalyticsDatasource.getSchema(this.target.azureLogAnalytics.workspace);
  286. })
  287. .catch(this.handleQueryCtrlError.bind(this));
  288. };
  289. onLogAnalyticsQueryChange = (nextQuery: string) => {
  290. this.target.azureLogAnalytics.query = nextQuery;
  291. };
  292. onLogAnalyticsQueryExecute = () => {
  293. this.panelCtrl.refresh();
  294. };
  295. get templateVariables() {
  296. return this.templateSrv.variables.map(t => '$' + t.name);
  297. }
  298. /* Application Insights Section */
  299. getAppInsightsAutoInterval() {
  300. const interval = this.templateSrv.builtIns.__interval.value;
  301. if (interval[interval.length - 1] === 's') {
  302. return '1m';
  303. }
  304. return interval;
  305. }
  306. getAppInsightsMetricNames() {
  307. if (!this.datasource.appInsightsDatasource.isConfigured()) {
  308. return;
  309. }
  310. return this.datasource.getAppInsightsMetricNames().catch(this.handleQueryCtrlError.bind(this));
  311. }
  312. getAppInsightsColumns() {
  313. return this.datasource.getAppInsightsColumns(this.target.refId);
  314. }
  315. onAppInsightsColumnChange() {
  316. return this.refresh();
  317. }
  318. onAppInsightsMetricNameChange() {
  319. if (!this.target.appInsights.metricName || this.target.appInsights.metricName === this.defaultDropdownValue) {
  320. return;
  321. }
  322. return this.datasource
  323. .getAppInsightsMetricMetadata(this.replace(this.target.appInsights.metricName))
  324. .then(aggData => {
  325. this.target.appInsights.aggOptions = aggData.supportedAggTypes;
  326. this.target.appInsights.groupByOptions = aggData.supportedGroupBy;
  327. this.target.appInsights.aggregation = aggData.primaryAggType;
  328. return this.refresh();
  329. })
  330. .catch(this.handleQueryCtrlError.bind(this));
  331. }
  332. onAppInsightsQueryChange = (nextQuery: string) => {
  333. this.target.appInsights.rawQueryString = nextQuery;
  334. };
  335. onAppInsightsQueryExecute = () => {
  336. return this.refresh();
  337. };
  338. getAppInsightsQuerySchema = () => {
  339. return this.datasource.appInsightsDatasource.getQuerySchema().catch(this.handleQueryCtrlError.bind(this));
  340. };
  341. getAppInsightsGroupBySegments(query) {
  342. return _.map(this.target.appInsights.groupByOptions, option => {
  343. return { text: option, value: option };
  344. });
  345. }
  346. resetAppInsightsGroupBy() {
  347. this.target.appInsights.groupBy = 'none';
  348. this.refresh();
  349. }
  350. updateTimeGrainType() {
  351. if (this.target.appInsights.timeGrainType === 'specific') {
  352. this.target.appInsights.timeGrain = '1';
  353. this.target.appInsights.timeGrainUnit = 'minute';
  354. } else {
  355. this.target.appInsights.timeGrain = '';
  356. }
  357. this.refresh();
  358. }
  359. toggleEditorMode() {
  360. this.target.appInsights.rawQuery = !this.target.appInsights.rawQuery;
  361. }
  362. }