Skip to content

Commit

Permalink
Readme and xmlk docs for Azure.Monitor.Query (#20731)
Browse files Browse the repository at this point in the history
  • Loading branch information
pakrym authored Apr 29, 2021
1 parent 1b559a9 commit ed55a68
Show file tree
Hide file tree
Showing 18 changed files with 570 additions and 25 deletions.
1 change: 0 additions & 1 deletion eng/.docsettings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,6 @@ known_content_issues:
- ['sdk/core/Microsoft.Azure.Core.Spatial/README.md', '#15423']
- ['sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/README.md', '#15423']
- ['sdk/servicebus/Microsoft.Azure.WebJobs.Extensions.ServiceBus/README.md', '#15423']
- ['sdk/monitor/Azure.Monitor.Query/README.md', '#15423']

# .net climbs upwards. placing these to prevent assigning readmes to the wrong project
package_indexing_exclusion_list:
Expand Down
161 changes: 157 additions & 4 deletions sdk/monitor/Azure.Monitor.Query/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,62 @@
# Azure Monitor Query client library for .NET

TODO
The `Azure.Monitor.Query` package provides an ability to query [Azure Monitor Logs](https://docs.microsoft.com/azure/azure-monitor/logs/data-platform-logs) and [Azure Monitor Metrics](https://docs.microsoft.com/azure/azure-monitor/essentials/data-platform-metrics) data.

[Azure Monitor Logs](https://docs.microsoft.com/azure/azure-monitor/logs/data-platform-logs) is a feature of Azure Monitor that collects and organizes log and performance data from monitored resources. Data from different sources such as platform logs from Azure services, log and performance data from virtual machines agents, and usage and performance data from applications can be consolidated into a single workspace so they can be analyzed together using a sophisticated query language that's capable of quickly analyzing millions of records.

## Samples
[Azure Monitor Metrics](https://docs.microsoft.com/azure/azure-monitor/essentials/data-platform-metrics) is a feature of Azure Monitor that collects numeric data from monitored resources into a time series database. Metrics are numerical values that are collected at regular intervals and describe some aspect of a system at a particular time. Metrics in Azure Monitor are lightweight and capable of supporting near real-time scenarios making them particularly useful for alerting and fast detection of issues.

[Source code][query_client_src] | [Package (NuGet)][query_client_nuget_package]

## Getting started

### Install the package
Install the Azure Monitor Query client library for .NET with [NuGet][query_client_nuget_package]:

```
dotnet add package Azure.Monitor.Query --prerelease
```

### Prerequisites
* An [Azure subscription][azure_sub].
* To be able to query logs you would need an existing Log Analytics workspace. You can create it in one of the following approaches:
* [Azure Portal](https://docs.microsoft.com/azure/azure-monitor/logs/quick-create-workspace)
* [Azure CLI](https://docs.microsoft.com/azure/azure-monitor/logs/quick-create-workspace-cli)
* [PowerShell](https://docs.microsoft.com/azure/azure-monitor/logs/powershell-workspace-configuration)

* To be able to query metrics all you need is an Azure resource of any kind (Storage Account, KeyVault, CosmosDB etc.)

### Authenticate the Client

In order to interact with the Azure Monitor service, you will need to create an instance of a [TokenCredential](https://docs.microsoft.com/dotnet/api/azure.core.tokencredential?view=azure-dotnet) class and pass it to the constructor of your `LogsClient` or `MetricsClient` class.

## Key concepts

- `LogsClient` - Client that provides methods to query logs from Azure Monitor Logs.
- `MetricsClient` - Client that provides methods to query metrics from Azure Monitor Metrics.

### Thread safety
We guarantee that all client instance methods are thread-safe and independent of each other ([guideline](https://azure.github.io/azure-sdk/dotnet_introduction.html#dotnet-service-methods-thread-safety)). This ensures that the recommendation of reusing client instances is always safe, even across threads.

### Additional concepts
<!-- CLIENT COMMON BAR -->
[Client options](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/README.md#configuring-service-clients-using-clientoptions) |
[Accessing the response](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/README.md#accessing-http-response-details-using-responset) |
[Long-running operations](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/README.md#consuming-long-running-operations-using-operationt) |
[Handling failures](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/README.md#reporting-errors-requestfailedexception) |
[Diagnostics](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/samples/Diagnostics.md) |
[Mocking](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/core/Azure.Core/README.md#mocking) |
[Client lifetime](https://devblogs.microsoft.com/azure-sdk/lifetime-management-and-thread-safety-guarantees-of-azure-sdk-net-clients/)
<!-- CLIENT COMMON BAR -->

## Examples

- [Query logs](#query-logs)
- [Query logs as model](#query-logs-as-model)
- [Query logs as primitive](#query-logs-as-primitive)
- [Batch query](#batch-query)
- [Query dynamic table](#query-dynamic-table)
- [Increase query timeout](#increase-query-timeout)

### Query logs

Expand Down Expand Up @@ -92,7 +145,7 @@ foreach (var logEntryModel in topEntries)
}
```

### Query dynamic table
### Query dynamic table

You can also dynamically inspect the list of columns. The following example prints the result of the query as a table:

Expand Down Expand Up @@ -120,4 +173,104 @@ foreach (var row in table.Rows)

Console.WriteLine();
}
```
```

### Increase query timeout

Some queries take longer to execute than the default service timeout allows. You can use the `LogsQueryOptions` parameter to specify the service timeout.

```C# Snippet:QueryLogsPrintTable
LogsClient client = new LogsClient(new DefaultAzureCredential());
string workspaceId = "<workspace_id>";
Response<LogsQueryResult> response = await client.QueryAsync(workspaceId, "AzureActivity | top 10 by TimeGenerated");

LogsQueryResultTable table = response.Value.PrimaryTable;

foreach (var column in table.Columns)
{
Console.Write(column.Name + ";");
}

Console.WriteLine();

var columnCount = table.Columns.Count;
foreach (var row in table.Rows)
{
for (int i = 0; i < columnCount; i++)
{
Console.Write(row[i] + ";");
}

Console.WriteLine();
}
```

## Troubleshooting

### General

When you interact with the Azure Monitor Query client library using the .NET SDK, errors returned by the service correspond to the same HTTP status codes returned for [REST API][monitor_rest_api] requests.

For example, if you submit an invalid query a `400` error is returned, indicating "Bad Request".

```C# Snippet:BadRequest
string workspaceId = "<workspace_id>";
LogsClient client = new LogsClient(new DefaultAzureCredential());
try
{
await client.QueryAsync(workspaceId, "My Not So Valid Query");
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
```

The exception also contains some additional information like the full error content.

```
Azure.RequestFailedException : The request had some invalid properties
Status: 400 (Bad Request)
ErrorCode: BadArgumentError
Content:
{"error":{"message":"The request had some invalid properties","code":"BadArgumentError","correlationId":"34f5f93a-6007-48a4-904f-487ca4e62a82","innererror":{"code":"SyntaxError","message":"A recognition error occurred in the query.","innererror":{"code":"SYN0002","message":"Query could not be parsed at 'Not' on line [1,3]","line":1,"pos":3,"token":"Not"}}}}
```

### Setting up console logging

The simplest way to see the logs is to enable the console logging.
To create an Azure SDK log listener that outputs messages to console use AzureEventSourceListener.CreateConsoleLogger method.

```C#
// Setup a listener to monitor logged events.
using AzureEventSourceListener listener = AzureEventSourceListener.CreateConsoleLogger();
```

To learn more about other logging mechanisms see [here][logging].

## Next steps

## Contributing

This project welcomes contributions and suggestions. Most contributions require
you to agree to a Contributor License Agreement (CLA) declaring that you have
the right to, and actually do, grant us the rights to use your contribution. For
details, visit [cla.microsoft.com][cla].

This project has adopted the [Microsoft Open Source Code of Conduct][coc].
For more information see the [Code of Conduct FAQ][coc_faq] or contact
[[email protected]][coc_contact] with any additional questions or comments.

[query_client_src]: https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/monitor/Azure.Monitor.Query/src
[query_client_nuget_package]: https://www.nuget.org/packages?q=Azure.Monitor.Query
[monitor_rest_api]: https://docs.microsoft.com/rest/api/monitor/
[azure_cli]: https://docs.microsoft.com/cli/azure
[azure_sub]: https://azure.microsoft.com/free/
[cla]: https://cla.microsoft.com
[coc]: https://opensource.microsoft.com/codeofconduct/
[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/
[coc_contact]: mailto:[email protected]

![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fmonitor%2FAzure.Monitor.Query%2FREADME.png)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<Version>1.0.0-beta.1</Version>
<PackageTags>Azure Monitor Query</PackageTags>
<TargetFrameworks>$(RequiredTargetFrameworks)</TargetFrameworks>
<NoWarn>$(NoWarn);AZC0001;CS1591</NoWarn>
<NoWarn>$(NoWarn);AZC0001</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
58 changes: 56 additions & 2 deletions sdk/monitor/Azure.Monitor.Query/src/LogsClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -13,17 +12,29 @@

namespace Azure.Monitor.Query
{
/// <summary>
/// The <see cref="LogsClient"/> allows to query the Azure Monitor Logs service.
/// </summary>
public class LogsClient
{
private readonly QueryRestClient _queryClient;
private readonly ClientDiagnostics _clientDiagnostics;
private readonly HttpPipeline _pipeline;
private readonly RowBinder _rowBinder;

/// <summary>
/// Initializes a new instance of <see cref="LogsClient"/>.
/// </summary>
/// <param name="credential">The <see cref="TokenCredential"/> instance to use for authentication.</param>
public LogsClient(TokenCredential credential) : this(credential, null)
{
}

/// <summary>
/// Initializes a new instance of <see cref="LogsClient"/>.
/// </summary>
/// <param name="credential">The <see cref="TokenCredential"/> instance to use for authentication.</param>
/// <param name="options">The <see cref="LogsClientOptions"/> instance to use as client configuration.</param>
public LogsClient(TokenCredential credential, LogsClientOptions options)
{
Argument.AssertNotNull(credential, nameof(credential));
Expand All @@ -36,24 +47,54 @@ public LogsClient(TokenCredential credential, LogsClientOptions options)
_rowBinder = new RowBinder();
}

/// <summary>
/// Initializes a new instance of <see cref="LogsClient"/> for mocking.
/// </summary>
protected LogsClient()
{
}

/// <summary>
/// Executes the logs query.
/// </summary>
/// <param name="workspaceId">The workspace to include in the query.</param>
/// <param name="query">The query text to execute.</param>
/// <param name="timeSpan">The timespan over which to query data. Logs would be filtered to include entries produced starting at <c>Now - timeSpan</c>. </param>
/// <param name="options">The <see cref="LogsQueryOptions"/> to configure the query.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
/// <returns>Query results mapped to a type <typeparamref name="T"/>.</returns>
public virtual Response<IReadOnlyList<T>> Query<T>(string workspaceId, string query, TimeSpan? timeSpan = null, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
Response<LogsQueryResult> response = Query(workspaceId, query, timeSpan, options, cancellationToken);

return Response.FromValue(_rowBinder.BindResults<T>(response), response.GetRawResponse());
}

/// <summary>
/// Executes the logs query.
/// </summary>
/// <param name="workspaceId">The workspace to include in the query.</param>
/// <param name="query">The query text to execute.</param>
/// <param name="timeSpan">The timespan over which to query data. Logs would be filtered to include entries produced starting at <c>Now - timeSpan</c>. </param>
/// <param name="options">The <see cref="LogsQueryOptions"/> to configure the query.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
/// <returns>Query results mapped to a type <typeparamref name="T"/>.</returns>
public virtual async Task<Response<IReadOnlyList<T>>> QueryAsync<T>(string workspaceId, string query, TimeSpan? timeSpan = null, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
Response<LogsQueryResult> response = await QueryAsync(workspaceId, query, timeSpan, options, cancellationToken).ConfigureAwait(false);

return Response.FromValue(_rowBinder.BindResults<T>(response), response.GetRawResponse());
}

/// <summary>
/// Executes the logs query.
/// </summary>
/// <param name="workspaceId">The workspace to include in the query.</param>
/// <param name="query">The query text to execute.</param>
/// <param name="timeSpan">The timespan over which to query data. Logs would be filtered to include entries produced starting at <c>Now - timeSpan</c>. </param>
/// <param name="options">The <see cref="LogsQueryOptions"/> to configure the query.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
/// <returns>The <see cref="LogsQueryResult"/> containing the query results.</returns>
public virtual Response<LogsQueryResult> Query(string workspaceId, string query, TimeSpan? timeSpan = null, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(LogsClient)}.{nameof(Query)}");
Expand All @@ -69,6 +110,15 @@ public virtual Response<LogsQueryResult> Query(string workspaceId, string query,
}
}

/// <summary>
/// Executes the logs query.
/// </summary>
/// <param name="workspaceId">The workspace to include in the query.</param>
/// <param name="query">The query text to execute.</param>
/// <param name="timeSpan">The timespan over which to query data. Logs would be filtered to include entries produced starting at <c>Now - timeSpan</c>. </param>
/// <param name="options">The <see cref="LogsQueryOptions"/> to configure the query.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to use.</param>
/// <returns>The <see cref="LogsQueryResult"/> with the query results.</returns>
public virtual async Task<Response<LogsQueryResult>> QueryAsync(string workspaceId, string query, TimeSpan? timeSpan = null, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(LogsClient)}.{nameof(Query)}");
Expand All @@ -84,6 +134,10 @@ public virtual async Task<Response<LogsQueryResult>> QueryAsync(string workspace
}
}

/// <summary>
/// Creates an instance of <see cref="LogsBatchQuery"/> that allows executing multiple queries at once.
/// </summary>
/// <returns>The <see cref="LogsBatchQuery"/> instance that allows building a list of queries and submitting them.</returns>
public virtual LogsBatchQuery CreateBatchQuery()
{
return new LogsBatchQuery(_clientDiagnostics, _queryClient, _rowBinder);
Expand Down Expand Up @@ -161,4 +215,4 @@ await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellat
}
}
}
}
}
8 changes: 7 additions & 1 deletion sdk/monitor/Azure.Monitor.Query/src/LogsClientOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

namespace Azure.Monitor.Query
{
/// <summary>
/// Provides the client configuration options for connecting to Azure Monitor Logs service.
/// </summary>
public class LogsClientOptions: ClientOptions
{
private readonly ServiceVersion _version;
Expand All @@ -27,11 +30,14 @@ public LogsClientOptions(ServiceVersion version = LatestVersion)
}

/// <summary>
/// The versions of Azure Monitor Query service supported by this client
/// The versions of Azure Monitor Logs service supported by this client
/// library.
/// </summary>
public enum ServiceVersion
{
/// <summary>
/// The V1 version of the service
/// </summary>
V1
}
}
Expand Down
13 changes: 13 additions & 0 deletions sdk/monitor/Azure.Monitor.Query/src/LogsQueryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,25 @@
// Licensed under the MIT License.

using System;
using Azure.Monitor.Query.Models;

namespace Azure.Monitor.Query
{
/// <summary>
/// Options for <see cref="LogsClient.QueryAsync"/> and <see cref="LogsBatchQuery.AddQuery"/> methods.
/// </summary>
public class LogsQueryOptions
{
/// <summary>
/// Gets or sets the value indicating the service timeout for the query. Defaults to <c>null</c>.
/// </summary>
public TimeSpan? Timeout { get; set; }

/// <summary>
/// Gets or sets the value indicating whether to include query execution statistics as part of the response.
/// Statistics can be retrieved via the <see cref="LogsQueryResult.Statistics"/> property.
/// Defaults to <c>false</c>.
/// </summary>
public bool IncludeStatistics { get; set; }
}
}
Loading

0 comments on commit ed55a68

Please sign in to comment.