From a57716f8689ae5cfb8a0cebf2df0720bbdbfd26f Mon Sep 17 00:00:00 2001 From: Andres Martinez Gotor Date: Wed, 13 Apr 2022 06:56:32 -0700 Subject: [PATCH] AzureMonitor: Include macros and template variables as suggestions (#47689) --- .../azure_log_analytics_datasource.test.ts | 22 ++++ .../azure_log_analytics_datasource.ts | 2 +- .../azure_log_analytics/response_parser.ts | 100 ++++++++++++++---- .../components/LogsQueryEditor/QueryField.tsx | 1 + 4 files changed, 103 insertions(+), 22 deletions(-) diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.test.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.test.ts index 35a26d345c2..9f3a7fd0903 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.test.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.test.ts @@ -28,6 +28,7 @@ describe('AzureLogAnalyticsDatasource', () => { beforeEach(() => { templateSrv.init([singleVariable]); + templateSrv.getVariables = jest.fn().mockReturnValue([singleVariable]); ctx.instanceSettings = { jsonData: { subscriptionId: 'xxx' }, url: 'http://azureloganalyticsapi', @@ -120,6 +121,27 @@ describe('AzureLogAnalyticsDatasource', () => { await ctx.ds.azureLogAnalyticsDatasource.getKustoSchema('myWorkspace/$var1'); expect(ctx.mockGetResource).lastCalledWith('loganalytics/v1myWorkspace/var1-foo/metadata'); }); + + it('should include macros as suggested functions', async () => { + const result = await ctx.ds.azureLogAnalyticsDatasource.getKustoSchema('myWorkspace'); + expect(result.database.functions.map((f: { name: string }) => f.name)).toEqual([ + 'Func1', + '_AzureBackup_GetVaults', + '$__timeFilter', + '$__timeFrom', + '$__timeTo', + '$__escapeMulti', + '$__contains', + ]); + }); + + it('should include template variables as global parameters', async () => { + const result = await ctx.ds.azureLogAnalyticsDatasource.getKustoSchema('myWorkspace'); + expect(result.globalParameters.map((f: { name: string }) => f.name)).toEqual([ + `$${singleVariable.name}`, + '$__timeFilter', + ]); + }); }); describe('When performing annotationQuery', () => { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.ts index c98aac12ece..6f1ece771ba 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/azure_log_analytics_datasource.ts @@ -112,7 +112,7 @@ export default class AzureLogAnalyticsDatasource extends DataSourceWithBackend< const templateSrv = getTemplateSrv(); const interpolatedUri = templateSrv.replace(resourceUri, {}, interpolateVariable); const metadata = await this.getMetadata(interpolatedUri); - return transformMetadataToKustoSchema(metadata, interpolatedUri); + return transformMetadataToKustoSchema(metadata, interpolatedUri, templateSrv.getVariables()); } applyTemplateVariables(target: AzureMonitorQuery, scopedVars: ScopedVars): AzureMonitorQuery { diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/response_parser.ts b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/response_parser.ts index 412eb8f1e7a..bce81329529 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/response_parser.ts +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/azure_log_analytics/response_parser.ts @@ -1,4 +1,4 @@ -import { AnnotationEvent, dateTime, TimeSeries } from '@grafana/data'; +import { AnnotationEvent, dateTime, TimeSeries, VariableModel } from '@grafana/data'; import { concat, find, flattenDeep, forEach, get, map } from 'lodash'; import { AzureLogsTableData, AzureLogsVariable } from '../types'; @@ -213,7 +213,11 @@ function transformMetadataFunction(sourceSchema: AzureLogAnalyticsMetadata) { }); } -export function transformMetadataToKustoSchema(sourceSchema: AzureLogAnalyticsMetadata, nameOrIdOrSomething: string) { +export function transformMetadataToKustoSchema( + sourceSchema: AzureLogAnalyticsMetadata, + nameOrIdOrSomething: string, + templateVariables: VariableModel[] +) { const database = { name: nameOrIdOrSomething, tables: sourceSchema.tables, @@ -222,25 +226,78 @@ export function transformMetadataToKustoSchema(sourceSchema: AzureLogAnalyticsMe minorVersion: 0, }; - // TODO: We should define macros here as functions so they are interpreted as valid - // But we cannot do so for the issues listed here: https://github.com/Azure/monaco-kusto/issues/189 - // For example: - // database.functions.push( - // { - // name: '$__timeFilter', - // body: '', - // inputParameters: [ - // { - // name: 'timeColumn', - // type: 'System.String', - // cslType: 'string', - // cslDefaultValue: 'Timestamp', - // }, - // ], - // docString: 'Filter by a time column', - // functionKind: 'Unknown', - // }, - // ); + // Adding macros as known functions + database.functions.push( + { + name: '$__timeFilter', + body: '{ true }', + inputParameters: [ + { + name: 'timeColumn', + type: 'System.String', + defaultValue: 'TimeGenerated', + cslDefaultValue: 'TimeGenerated', + }, + ], + }, + { + name: '$__timeFrom', + body: '{ datetime(2018-06-05T18:09:58.907Z) }', + inputParameters: [], + }, + { + name: '$__timeTo', + body: '{ datetime(2018-06-05T20:09:58.907Z) }', + inputParameters: [], + }, + { + name: '$__escapeMulti', + body: `{ @'\\grafana-vm\Network(eth0)\Total', @'\\hello!'}`, + inputParameters: [ + { + name: '$myVar', + type: 'System.String', + defaultValue: '$myVar', + cslDefaultValue: '$myVar', + }, + ], + }, + { + name: '$__contains', + body: `{ colName in ('value1','value2') }`, + inputParameters: [ + { + name: 'colName', + type: 'System.String', + defaultValue: 'colName', + cslDefaultValue: 'colName', + }, + { + name: '$myVar', + type: 'System.String', + defaultValue: '$myVar', + cslDefaultValue: '$myVar', + }, + ], + } + ); + + // Adding macros as global parameters + const globalParameters = templateVariables.map((v) => { + return { + name: `$${v.name}`, + type: 'dynamic', + }; + }); + + // It's not possible to define optional paramaters in Kusto + // and it's not possible to define the same function twice so + // we are defining $__timeFilter also as a parameter when used + // with no arguments as a workaround + globalParameters.push({ + name: `$__timeFilter`, + type: 'boolean', + }); return { clusterType: 'Engine', @@ -249,5 +306,6 @@ export function transformMetadataToKustoSchema(sourceSchema: AzureLogAnalyticsMe databases: [database], }, database: database, + globalParameters, }; } diff --git a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/QueryField.tsx b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/QueryField.tsx index df33e362b61..b435ca4955f 100644 --- a/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/QueryField.tsx +++ b/public/app/plugins/datasource/grafana-azure-monitor-datasource/components/LogsQueryEditor/QueryField.tsx @@ -1,6 +1,7 @@ import { CodeEditor, Monaco, MonacoEditor } from '@grafana/ui'; import { Deferred } from 'app/core/utils/deferred'; import React, { useCallback, useEffect, useRef } from 'react'; + import { AzureQueryEditorFieldProps } from '../../types'; import { setKustoQuery } from './setQueryValue';