mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: support workspaces function for template variables (#22882)
* azuremonitor: adds support for workspaces query macro... ...for Azure Logs template variable queries * docs: azure logs workspaces templating function * Update docs/sources/features/datasources/azuremonitor.md Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com> * docs: convert list into table * docs: fixes prettier formatting problem Prettier adds a slash before dollar signs in markdown. Disabling it for this table with a prettier comment. https://prettier.io/docs/en/ignore.html Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
This commit is contained in:
parent
ec9167e972
commit
3b9a4e6444
@ -274,6 +274,45 @@ There are also some Grafana variables that can be used in Azure Log Analytics qu
|
|||||||
|
|
||||||
- `$__interval` - Grafana calculates the minimum time grain that can be used to group by time in queries. More details on how it works [here]({{< relref "../../reference/templating.md#interval-variables" >}}). It returns a time grain like `5m` or `1h` that can be used in the bin function. E.g. `summarize count() by bin(TimeGenerated, $__interval)`
|
- `$__interval` - Grafana calculates the minimum time grain that can be used to group by time in queries. More details on how it works [here]({{< relref "../../reference/templating.md#interval-variables" >}}). It returns a time grain like `5m` or `1h` that can be used in the bin function. E.g. `summarize count() by bin(TimeGenerated, $__interval)`
|
||||||
|
|
||||||
|
### Templating with Variables for Azure Log Analytics
|
||||||
|
|
||||||
|
Any Log Analytics query that returns a list of values can be used in the `Query` field in the Variable edit view. There is also one Grafana function for Log Analytics that returns a list of workspaces.
|
||||||
|
|
||||||
|
Refer to the [Variables]({{< relref "../../reference/templating.md" >}}) documentation for an introduction to the templating feature and the different
|
||||||
|
types of template variables.
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||||
|
| _workspaces()_ | Returns a list of workspaces for the default subscription. |
|
||||||
|
| _workspaces(12345678-aaaa-bbbb-cccc-123456789aaa)_ | Returns a list of workspaces for the specified subscription (the parameter can be quoted or unquoted). |
|
||||||
|
|
||||||
|
Example variable queries:
|
||||||
|
|
||||||
|
<!-- prettier-ignore-start -->
|
||||||
|
| Query | Description |
|
||||||
|
| --------------------------------------------------------------------------------------- | --------------------------------------------------------- |
|
||||||
|
| _subscriptions()_ | Returns a list of Azure subscriptions |
|
||||||
|
| _workspaces()_ | Returns a list of workspaces for default subscription |
|
||||||
|
| _workspaces("12345678-aaaa-bbbb-cccc-123456789aaa")_ | Returns a list of workspaces for a specified subscription |
|
||||||
|
| _workspaces("$subscription")_ | With template variable for the subscription parameter |
|
||||||
|
| _workspace("myWorkspace").Heartbeat \| distinct Computer_ | Returns a list of Virtual Machines |
|
||||||
|
| _workspace("$workspace").Heartbeat \| distinct Computer_ | Returns a list of Virtual Machines with template variable |
|
||||||
|
| _workspace("$workspace").Perf \| distinct ObjectName_ | Returns a list of objects from the Perf table |
|
||||||
|
| _workspace("$workspace").Perf \| where ObjectName == "$object" \| distinct CounterName_ | Returns a list of metric names from the Perf table |
|
||||||
|
|
||||||
|
<!-- prettier-ignore-end -->
|
||||||
|
|
||||||
|
Example of a time series query using variables:
|
||||||
|
|
||||||
|
```
|
||||||
|
Perf
|
||||||
|
| where ObjectName == "$object" and CounterName == "$metric"
|
||||||
|
| where TimeGenerated >= $__timeFrom() and TimeGenerated <= $__timeTo()
|
||||||
|
| where $__contains(Computer, $computer)
|
||||||
|
| summarize avg(CounterValue) by bin(TimeGenerated, $__interval), Computer
|
||||||
|
| order by TimeGenerated asc
|
||||||
|
```
|
||||||
|
|
||||||
### Azure Log Analytics Alerting
|
### Azure Log Analytics Alerting
|
||||||
|
|
||||||
Not implemented yet.
|
Not implemented yet.
|
||||||
|
@ -2,7 +2,7 @@ import AzureMonitorDatasource from '../datasource';
|
|||||||
import FakeSchemaData from './__mocks__/schema';
|
import FakeSchemaData from './__mocks__/schema';
|
||||||
|
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
import { KustoSchema } from '../types';
|
import { KustoSchema, AzureLogsVariable } from '../types';
|
||||||
import { toUtc } from '@grafana/data';
|
import { toUtc } from '@grafana/data';
|
||||||
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
import { backendSrv } from 'app/core/services/backend_srv'; // will use the version in __mocks__
|
||||||
|
|
||||||
@ -283,53 +283,129 @@ describe('AzureLogAnalyticsDatasource', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('When performing metricFindQuery', () => {
|
describe('When performing metricFindQuery', () => {
|
||||||
const tableResponseWithOneColumn = {
|
let queryResults: AzureLogsVariable[];
|
||||||
tables: [
|
|
||||||
{
|
|
||||||
name: 'PrimaryResult',
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
name: 'Category',
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
rows: [['Administrative'], ['Policy']],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const workspaceResponse = {
|
const workspacesResponse = {
|
||||||
value: [
|
value: [
|
||||||
{
|
{
|
||||||
name: 'aworkspace',
|
name: 'workspace1',
|
||||||
properties: {
|
properties: {
|
||||||
source: 'Azure',
|
customerId: 'eeee4fde-1aaa-4d60-9974-eeee562ffaa1',
|
||||||
customerId: 'abc1b44e-3e57-4410-b027-6cc0ae6dee67',
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'workspace2',
|
||||||
|
properties: {
|
||||||
|
customerId: 'eeee4fde-1aaa-4d60-9974-eeee562ffaa2',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
let queryResults: any[];
|
describe('and is the workspaces() macro', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
datasourceRequestMock.mockImplementation((options: { url: string }) => {
|
||||||
|
expect(options.url).toContain('xxx');
|
||||||
|
return Promise.resolve({ data: workspacesResponse, status: 200 });
|
||||||
|
});
|
||||||
|
|
||||||
beforeEach(async () => {
|
queryResults = await ctx.ds.metricFindQuery('workspaces()');
|
||||||
datasourceRequestMock.mockImplementation((options: { url: string }) => {
|
|
||||||
if (options.url.indexOf('Microsoft.OperationalInsights/workspaces') > -1) {
|
|
||||||
return Promise.resolve({ data: workspaceResponse, status: 200 });
|
|
||||||
} else {
|
|
||||||
return Promise.resolve({ data: tableResponseWithOneColumn, status: 200 });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
queryResults = await ctx.ds.metricFindQuery('workspace("aworkspace").AzureActivity | distinct Category');
|
it('should return a list of workspaces', () => {
|
||||||
|
expect(queryResults.length).toBe(2);
|
||||||
|
expect(queryResults[0].text).toBe('workspace1');
|
||||||
|
expect(queryResults[0].value).toBe('eeee4fde-1aaa-4d60-9974-eeee562ffaa1');
|
||||||
|
expect(queryResults[1].text).toBe('workspace2');
|
||||||
|
expect(queryResults[1].value).toBe('eeee4fde-1aaa-4d60-9974-eeee562ffaa2');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a list of categories in the correct format', () => {
|
describe('and is the workspaces() macro with the subscription parameter', () => {
|
||||||
expect(queryResults.length).toBe(2);
|
beforeEach(async () => {
|
||||||
expect(queryResults[0].text).toBe('Administrative');
|
datasourceRequestMock.mockImplementation((options: { url: string }) => {
|
||||||
expect(queryResults[0].value).toBe('Administrative');
|
expect(options.url).toContain('11112222-eeee-4949-9b2d-9106972f9123');
|
||||||
expect(queryResults[1].text).toBe('Policy');
|
return Promise.resolve({ data: workspacesResponse, status: 200 });
|
||||||
expect(queryResults[1].value).toBe('Policy');
|
});
|
||||||
|
|
||||||
|
queryResults = await ctx.ds.metricFindQuery('workspaces(11112222-eeee-4949-9b2d-9106972f9123)');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a list of workspaces', () => {
|
||||||
|
expect(queryResults.length).toBe(2);
|
||||||
|
expect(queryResults[0].text).toBe('workspace1');
|
||||||
|
expect(queryResults[0].value).toBe('eeee4fde-1aaa-4d60-9974-eeee562ffaa1');
|
||||||
|
expect(queryResults[1].text).toBe('workspace2');
|
||||||
|
expect(queryResults[1].value).toBe('eeee4fde-1aaa-4d60-9974-eeee562ffaa2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and is the workspaces() macro with the subscription parameter quoted', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
datasourceRequestMock.mockImplementation((options: { url: string }) => {
|
||||||
|
expect(options.url).toContain('11112222-eeee-4949-9b2d-9106972f9123');
|
||||||
|
return Promise.resolve({ data: workspacesResponse, status: 200 });
|
||||||
|
});
|
||||||
|
|
||||||
|
queryResults = await ctx.ds.metricFindQuery('workspaces("11112222-eeee-4949-9b2d-9106972f9123")');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a list of workspaces', () => {
|
||||||
|
expect(queryResults.length).toBe(2);
|
||||||
|
expect(queryResults[0].text).toBe('workspace1');
|
||||||
|
expect(queryResults[0].value).toBe('eeee4fde-1aaa-4d60-9974-eeee562ffaa1');
|
||||||
|
expect(queryResults[1].text).toBe('workspace2');
|
||||||
|
expect(queryResults[1].value).toBe('eeee4fde-1aaa-4d60-9974-eeee562ffaa2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and is a custom query', () => {
|
||||||
|
const tableResponseWithOneColumn = {
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
name: 'PrimaryResult',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: 'Category',
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
rows: [['Administrative'], ['Policy']],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const workspaceResponse = {
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
name: 'aworkspace',
|
||||||
|
properties: {
|
||||||
|
source: 'Azure',
|
||||||
|
customerId: 'abc1b44e-3e57-4410-b027-6cc0ae6dee67',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
datasourceRequestMock.mockImplementation((options: { url: string }) => {
|
||||||
|
if (options.url.indexOf('Microsoft.OperationalInsights/workspaces') > -1) {
|
||||||
|
return Promise.resolve({ data: workspaceResponse, status: 200 });
|
||||||
|
} else {
|
||||||
|
return Promise.resolve({ data: tableResponseWithOneColumn, status: 200 });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
queryResults = await ctx.ds.metricFindQuery('workspace("aworkspace").AzureActivity | distinct Category');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a list of categories in the correct format', () => {
|
||||||
|
expect(queryResults.length).toBe(2);
|
||||||
|
expect(queryResults[0].text).toBe('Administrative');
|
||||||
|
expect(queryResults[0].value).toBe('Administrative');
|
||||||
|
expect(queryResults[1].text).toBe('Policy');
|
||||||
|
expect(queryResults[1].value).toBe('Policy');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import LogAnalyticsQuerystringBuilder from '../log_analytics/querystring_builder';
|
import LogAnalyticsQuerystringBuilder from '../log_analytics/querystring_builder';
|
||||||
import ResponseParser from './response_parser';
|
import ResponseParser from './response_parser';
|
||||||
import { AzureMonitorQuery, AzureDataSourceJsonData } from '../types';
|
import { AzureMonitorQuery, AzureDataSourceJsonData, AzureLogsVariable } from '../types';
|
||||||
import { DataQueryRequest, DataSourceInstanceSettings } from '@grafana/data';
|
import { DataQueryRequest, DataSourceInstanceSettings } from '@grafana/data';
|
||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv } from '@grafana/runtime';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
@ -47,7 +47,7 @@ export default class AzureLogAnalyticsDatasource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getWorkspaces(subscription: string) {
|
getWorkspaces(subscription: string): Promise<AzureLogsVariable[]> {
|
||||||
const subscriptionId = this.templateSrv.replace(subscription || this.subscriptionId);
|
const subscriptionId = this.templateSrv.replace(subscription || this.subscriptionId);
|
||||||
|
|
||||||
const workspaceListUrl =
|
const workspaceListUrl =
|
||||||
@ -118,6 +118,16 @@ export default class AzureLogAnalyticsDatasource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
metricFindQuery(query: string) {
|
metricFindQuery(query: string) {
|
||||||
|
const workspacesQuery = query.match(/^workspaces\(\)/i);
|
||||||
|
if (workspacesQuery) {
|
||||||
|
return this.getWorkspaces(this.subscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const workspacesQueryWithSub = query.match(/^workspaces\(["']?([^\)]+?)["']?\)/i);
|
||||||
|
if (workspacesQueryWithSub) {
|
||||||
|
return this.getWorkspaces((workspacesQueryWithSub[1] || '').trim());
|
||||||
|
}
|
||||||
|
|
||||||
return this.getDefaultOrFirstWorkspace().then((workspace: any) => {
|
return this.getDefaultOrFirstWorkspace().then((workspace: any) => {
|
||||||
const queries: any[] = this.buildQuery(query, null, workspace);
|
const queries: any[] = this.buildQuery(query, null, workspace);
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ describe('AzureMonitorDatasource', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
datasourceRequestMock.mockImplementation((options: { url: string }) => Promise.resolve(response));
|
datasourceRequestMock.mockImplementation(() => Promise.resolve(response));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a list of subscriptions', () => {
|
it('should return a list of subscriptions', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user