Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monitor query readme #16791

Merged
merged 31 commits into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
7113672
update samples for logsQueryBatch
KarishmaGhiya Aug 5, 2021
1809836
update samples for logsQueryBatch
KarishmaGhiya Aug 5, 2021
740a227
add samples on readme
KarishmaGhiya Aug 6, 2021
2eb826a
multiple workspaces
KarishmaGhiya Aug 6, 2021
7fc5859
add samples
KarishmaGhiya Aug 6, 2021
044c65c
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
a60e250
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
99d2d06
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
d6d8491
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
d7386d1
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
6db03eb
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
a118b45
Update sdk/monitor/monitor-query/samples-dev/logsQueryBatch.ts
KarishmaGhiya Aug 6, 2021
bb19fbb
Update sdk/monitor/monitor-query/samples/v1/javascript/logsQueryBatch.js
KarishmaGhiya Aug 6, 2021
2bdf330
Update sdk/monitor/monitor-query/samples/v1/typescript/src/logsQueryB…
KarishmaGhiya Aug 6, 2021
e2fc823
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
d2c0d0f
update readme with Metrics Query Object hierarchy
KarishmaGhiya Aug 6, 2021
abb5e55
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
a53eb11
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
4f685b2
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
34fa769
Update sdk/monitor/monitor-query/README.md
KarishmaGhiya Aug 6, 2021
e142ae3
add correct language coloring
KarishmaGhiya Aug 7, 2021
0375d61
Merge branch 'monitor-query-readme' of https://github.com/KarishmaGhi…
KarishmaGhiya Aug 7, 2021
98d217b
updated changelog
KarishmaGhiya Aug 7, 2021
2b2fb6b
update the logsBatch
KarishmaGhiya Aug 7, 2021
418f036
regenerate samples
KarishmaGhiya Aug 7, 2021
9544ebb
update the api
KarishmaGhiya Aug 7, 2021
a63aa9b
fix unit test
KarishmaGhiya Aug 7, 2021
c8d9775
update querylogsresult and querylogsbachresult
KarishmaGhiya Aug 7, 2021
d542ffe
update querylogsresult and querylogsbachresult
KarishmaGhiya Aug 7, 2021
0ddeae5
update the readme with logs response
KarishmaGhiya Aug 9, 2021
9252a43
update the readme with logs response
KarishmaGhiya Aug 9, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
244 changes: 244 additions & 0 deletions sdk/monitor/monitor-query/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,250 @@ run().catch((err) => console.log("ERROR:", err));
}
```

### Batch logs query

The following example demonstrates sending multiple queries at the same time using batch query API. The queries can be represented as a list of `BatchQuery` objects.
KarishmaGhiya marked this conversation as resolved.
Show resolved Hide resolved

```javascript
export async function main() {
if (!monitorWorkspaceId) {
throw new Error("MONITOR_WORKSPACE_ID must be set in the environment for this sample");
}

const tokenCredential = new DefaultAzureCredential();
const logsQueryClient = new LogsQueryClient(tokenCredential);

const queriesBatch: BatchQuery[] = [
{
workspaceId: monitorWorkspaceId,
query: "AppEvents | project TimeGenerated, Name, AppRoleInstance | limit 1",
timespan: "P1D"
},
{
workspaceId: monitorWorkspaceId,
query: "AzureActivity | summarize count()",
timespan: "PT1H"
},
{
workspaceId: monitorWorkspaceId,
query:
"AppRequests | take 10 | summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId",
timespan: "PT1H"
},
{
workspaceId: monitorWorkspaceId,
query: "AppRequests | take 2",
timespan: "PT1H"
}
];

const result = await logsQueryClient.queryLogsBatch({
queries: queriesBatch
});

if (result.results == null) {
throw new Error("No response for query");
}

let i = 0;
for (const response of result.results) {
console.log(`Results for query with id: ${response.id}`);

if (response.error) {
console.log(`Query had errors:`, response.error);
} else {
if (response.tables == null) {
console.log(`No results for query`);
} else {
console.log(
`Printing results from query '${queriesBatch[i].query}' for '${queriesBatch[i].timespan}'`
);

for (const table of response.tables) {
const columnHeaderString = table.columns
.map((column) => `${column.name}(${column.type}) `)
.join("| ");
console.log(columnHeaderString);

for (const row of table.rows) {
const columnValuesString = row.map((columnValue) => `'${columnValue}' `).join("| ");
console.log(columnValuesString);
}
}
}
}
// next query
i++;
}
}
```

### Query metrics

The following example gets metrics for an [Azure Metrics Advisor](https://docs.microsoft.com/azure/applied-ai-services/metrics-advisor/overview) subscription. The resource URI is that of a Metrics Advisor resource.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix link and link name to use Azure Monitor instead of Metrics Advisor

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is used as an example to get the resource URI. Python used eventgrid as the example.


The resource URI must be that of the resource for which metrics are being queried. It's normally of the format `/subscriptions/<id>/resourceGroups/<rg-name>/providers/<source>/topics/<resource-name>`.

To find the resource URI:

1. Navigate to your resource's page in the Azure portal.
2. From the **Overview** blade, select the **JSON View** link.
3. In the resulting JSON, copy the value of the `id` property.

```javascript
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, Metric, MetricsQueryClient } from "@azure/monitor-query";
import * as dotenv from "dotenv";

dotenv.config();

const metricsResourceId = process.env.METRICS_RESOURCE_ID;

export async function main() {
const tokenCredential = new DefaultAzureCredential();
const metricsQueryClient = new MetricsQueryClient(tokenCredential);

if (!metricsResourceId) {
throw new Error("METRICS_RESOURCE_ID must be set in the environment for this sample");
}

const result = await metricsQueryClient.getMetricDefinitions(metricsResourceId);

for (const definition of result.definitions) {
console.log(`Definition = ${definition.name}`);
}

const firstMetric = result.definitions[0];

console.log(`Picking an example metric to query: ${firstMetric.name}`);

const metricsResponse = await metricsQueryClient.queryMetrics(
metricsResourceId,
Durations.last5Minutes,
{
metricNames: [firstMetric.name!],
interval: "PT1M"
}
);

console.log(
`Query cost: ${metricsResponse.cost}, interval: ${metricsResponse.interval}, time span: ${metricsResponse.timespan}`
);

const metrics: Metric[] = metricsResponse.metrics;
console.log(`Metrics:`, JSON.stringify(metrics, undefined, 2));
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
process.exit(1);
});
```

### Handle metrics response

The metrics query API returns a `QueryMetricsResult` object. The `QueryMetricsResult` object contains properties such as a list of `Metric`-typed objects, `interval`, `namespace`, and `timespan`. The `Metric` objects list can be accessed using the `metrics` param. Each `Metric` object in this list contains a list of `TimeSeriesElement` objects. Each `TimeSeriesElement` contains `data` and `metadataValues` properties. In visual form, the object hierarchy of the response resembles the following structure:
KarishmaGhiya marked this conversation as resolved.
Show resolved Hide resolved

```
QueryMetricsResult
|---cost
|---timespan
|---interval
|---namespace
|---resourceRegion
|---metrics (list of `Metric` objects)
|---id
|---type
|---name
|---unit
|---displayDescription
|---errorCode
|---timeseries (list of `TimeSeriesElement` objects)
|---metadataValues
|---data (list of data points represented by `MetricValue` objects)
```

#### Example of handling response

```javascript
import { DefaultAzureCredential } from "@azure/identity";
import { Durations, Metric, MetricsQueryClient } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();

const metricsResourceId = process.env.METRICS_RESOURCE_ID;
export async function main() {
const tokenCredential = new DefaultAzureCredential();
const metricsQueryClient = new MetricsQueryClient(tokenCredential);

if (!metricsResourceId) {
throw new Error("METRICS_RESOURCE_ID must be set in the environment for this sample");
}

console.log(`Picking an example metric to query: ${firstMetric.name}`);

const metricsResponse = await metricsQueryClient.queryMetrics(
metricsResourceId,
Durations.last5Minutes,
{
metricNames: ["MatchedEventCount"],
interval: "PT1M",
aggregations: ["Count"]
KarishmaGhiya marked this conversation as resolved.
Show resolved Hide resolved
}
);

console.log(
`Query cost: ${metricsResponse.cost}, interval: ${metricsResponse.interval}, time span: ${metricsResponse.timespan}`
);

const metrics: Metric[] = metricsResponse.metrics;
for(const metric of metrics){
console.log(metric.name);
for(const timeseriesElement of metric.timeseries){
for(const metricValue of timeseriesElement.data!){
if(metricValue.count!==0){
console.log(`There are ${metricValue.count} matched events at ${metricValue.timeStamp}`);
}
}
}
}

KarishmaGhiya marked this conversation as resolved.
Show resolved Hide resolved
}

main().catch((err) => {
console.error("The sample encountered an error:", err);
process.exit(1);
});
```

### Advanced scenarios

#### Query multiple workspaces

The same log query can be executed across multiple Log Analytics workspaces. In addition to the KQL query, the following parameters are required:

- `workspaceId` - The first (primary) workspace ID.
- `additionalWorkspaces` - A list of workspaces, excluding the workspace provided in the `workspaceId` parameter. The parameter's list items may consist of the following identifier formats:
- Qualified workspace names
- Workspace IDs
- Azure resource IDs

For example, the following query executes in three workspaces:

```javascript
const queryLogsOptions: QueryLogsOptions = {
additionalWorkspaces: ["<workspace2>", "<workspace3>"]
};

const kustoQuery = "AppEvents | limit 1";
const result = await logsQueryClient.queryLogs(
azureLogAnalyticsWorkspaceId,
kustoQuery,
Durations.last24Hours,
queryLogsOptions
);
```

For more samples see here: [samples][samples].

## Troubleshooting
Expand Down
51 changes: 39 additions & 12 deletions sdk/monitor/monitor-query/samples-dev/logsQueryBatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { DefaultAzureCredential } from "@azure/identity";
import { LogsQueryClient } from "@azure/monitor-query";
import { LogsQueryClient, QueryLogsBatchOptions } from "@azure/monitor-query";
import * as dotenv from "dotenv";
dotenv.config();

Expand All @@ -21,21 +21,44 @@ export async function main() {
const logsQueryClient = new LogsQueryClient(tokenCredential);

const kqlQuery = "AppEvents | project TimeGenerated, Name, AppRoleInstance | limit 1";

const result = await logsQueryClient.queryLogsBatch({
queries: [
{
workspaceId: monitorWorkspaceId,
query: kqlQuery,
timespan: "P1D"
}
]
});
const queriesBatch = [
{
workspaceId: monitorWorkspaceId,
query: kqlQuery,
timespan: "P1D"
},
{
workspaceId: monitorWorkspaceId,
query: "AzureActivity | summarize count()",
timespan: "PT1H"
},
{
workspaceId: monitorWorkspaceId,
query:
"AppRequests | take 10 | summarize avgRequestDuration=avg(DurationMs) by bin(TimeGenerated, 10m), _ResourceId",
timespan: "PT1H"
},
{
workspaceId: monitorWorkspaceId,
query: "AppRequests | take 2",
timespan: "PT1H"
}
];
const queryOptions: QueryLogsBatchOptions = {
includeQueryStatistics: true
};
const result = await logsQueryClient.queryLogsBatch(
{
queries: queriesBatch
},
queryOptions
);

if (result.results == null) {
throw new Error("No response for query");
}

let i = 0;
for (const response of result.results) {
console.log(`Results for query with id: ${response.id}`);

Expand All @@ -45,7 +68,9 @@ export async function main() {
if (response.tables == null) {
console.log(`No results for query`);
} else {
console.log(`Printing results from query '${kqlQuery}' for 1 day.`);
console.log(
`Printing results from query '${queriesBatch[i].query}' for '${queriesBatch[i].timespan}'`
);

for (const table of response.tables) {
const columnHeaderString = table.columns
Expand All @@ -60,6 +85,8 @@ export async function main() {
}
}
}
// next query
i++;
}
}

Expand Down
Loading