diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs
index 9d72260abb0b..01c5204be296 100644
--- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs
+++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs
@@ -199,6 +199,7 @@ public ResponseError(string? code, string? message, Azure.Core.ResponseInnerErro
public Azure.Core.ResponseInnerError? InnerError { get { throw null; } }
public string? Message { get { throw null; } }
public string? Target { get { throw null; } }
+ public override string ToString() { throw null; }
}
public sealed partial class ResponseInnerError
{
@@ -206,5 +207,6 @@ internal ResponseInnerError() { }
public string? Code { get { throw null; } }
public Azure.Core.ResponseInnerError? InnerError { get { throw null; } }
public string? Message { get { throw null; } }
+ public override string ToString() { throw null; }
}
}
diff --git a/sdk/core/Azure.Core.Experimental/src/ResponseError.cs b/sdk/core/Azure.Core.Experimental/src/ResponseError.cs
index 344f25f7a98b..a7137e76c23e 100644
--- a/sdk/core/Azure.Core.Experimental/src/ResponseError.cs
+++ b/sdk/core/Azure.Core.Experimental/src/ResponseError.cs
@@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -119,5 +121,35 @@ public override void Write(Utf8JsonWriter writer, ResponseError? value, JsonSeri
throw new NotImplementedException();
}
}
+
+ ///
+ public override string ToString()
+ {
+ var builder = new StringBuilder();
+
+ builder.AppendFormat(CultureInfo.InvariantCulture, "{0}: {1}{2}", Code, Message, Environment.NewLine);
+
+ if (Target != null)
+ {
+ builder.AppendFormat(CultureInfo.InvariantCulture, "Target: {0}{1}", Target, Environment.NewLine);
+ }
+
+ if (InnerError != null)
+ {
+ builder.AppendLine("Inner Error:");
+ builder.Append(InnerError);
+ }
+
+ if (Details.Count > 0)
+ {
+ builder.AppendLine("Details:");
+ foreach (var detail in Details)
+ {
+ builder.Append(detail);
+ }
+ }
+
+ return builder.ToString();
+ }
}
}
\ No newline at end of file
diff --git a/sdk/core/Azure.Core.Experimental/src/ResponseInnerError.cs b/sdk/core/Azure.Core.Experimental/src/ResponseInnerError.cs
index 822bcb5dbf45..bbd6591820ee 100644
--- a/sdk/core/Azure.Core.Experimental/src/ResponseInnerError.cs
+++ b/sdk/core/Azure.Core.Experimental/src/ResponseInnerError.cs
@@ -2,6 +2,8 @@
// Licensed under the MIT License.
using System;
+using System.Globalization;
+using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -77,5 +79,20 @@ public override void Write(Utf8JsonWriter writer, ResponseInnerError? value, Jso
throw new NotImplementedException();
}
}
+
+ ///
+ public override string ToString()
+ {
+ var builder = new StringBuilder();
+
+ builder.AppendFormat(CultureInfo.InvariantCulture, "{0}: {1}{2}", Code, Message, Environment.NewLine);
+ if (InnerError != null)
+ {
+ builder.AppendLine("Inner Error:");
+ builder.Append(InnerError);
+ }
+
+ return builder.ToString();
+ }
}
}
\ No newline at end of file
diff --git a/sdk/core/Azure.Core.Experimental/tests/ResponseErrorTests.cs b/sdk/core/Azure.Core.Experimental/tests/ResponseErrorTests.cs
index 4e3002c574a5..11b835b37557 100644
--- a/sdk/core/Azure.Core.Experimental/tests/ResponseErrorTests.cs
+++ b/sdk/core/Azure.Core.Experimental/tests/ResponseErrorTests.cs
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
+using System;
using System.Text.Json;
using NUnit.Framework;
@@ -35,6 +36,11 @@ public void CanDeserializeSimple()
Assert.AreEqual("MoreDetailedBadError", error.InnerError.Code);
Assert.AreEqual("Inner message", error.InnerError.Message);
Assert.Null(error.InnerError.InnerError);
+ Assert.AreEqual("BadError: Something wasn't awesome" + Environment.NewLine +
+ "Target: Error target" + Environment.NewLine +
+ "Inner Error:" + Environment.NewLine +
+ "MoreDetailedBadError: Inner message" + Environment.NewLine,
+ error.ToString());
}
[Test]
@@ -80,6 +86,16 @@ public void CanDeserializeComplex()
Assert.AreEqual(2, error.Details.Count);
Assert.Null(error.InnerError.InnerError.InnerError);
+
+ Assert.AreEqual("BadError: Something wasn't awesome" + Environment.NewLine +
+ "Target: Error target" + Environment.NewLine +
+ "Inner Error:" + Environment.NewLine +
+ "MoreDetailedBadError: Inner message" + Environment.NewLine +
+ "Inner Error:" + Environment.NewLine +
+ "InnerMoreDetailedBadError: Inner Inner message" + Environment.NewLine +
+ "Details:" + Environment.NewLine +
+ "Code 1: Message 1" + Environment.NewLine +
+ "Code 2: Message 2" + Environment.NewLine, error.ToString());
}
}
}
\ No newline at end of file
diff --git a/sdk/monitor/Azure.Monitor.Query/README.md b/sdk/monitor/Azure.Monitor.Query/README.md
index 243bb97d6c19..fa9000e7cde8 100644
--- a/sdk/monitor/Azure.Monitor.Query/README.md
+++ b/sdk/monitor/Azure.Monitor.Query/README.md
@@ -63,10 +63,10 @@ We guarantee that all client instance methods are thread-safe and independent of
You can query logs using the `LogsClient.QueryAsync`. The result would be returned as a table with a collection of rows:
```C# Snippet:QueryLogsAsTable
-Uri endpoint = new Uri("https://api.loganalytics.io");
+var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
-LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
Response response = await client.QueryAsync(workspaceId, "AzureActivity | top 10 by TimeGenerated", TimeSpan.FromDays(1));
LogsQueryResultTable table = response.Value.PrimaryTable;
@@ -90,7 +90,7 @@ public class MyLogEntryModel
```
```C# Snippet:QueryLogsAsModels
-LogsQueryClient client = new LogsQueryClient(TestEnvironment.LogsEndpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(TestEnvironment.LogsEndpoint, new DefaultAzureCredential());
string workspaceId = "";
// Query TOP 10 resource groups by event count
@@ -109,10 +109,10 @@ foreach (var logEntryModel in response.Value)
If your query return a single column (or a single value) of a primitive type you can use `LogsClient.QueryAsync` overload to deserialize it:
```C# Snippet:QueryLogsAsPrimitive
-Uri endpoint = new Uri("https://api.loganalytics.io");
+var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
-LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
// Query TOP 10 resource groups by event count
Response> response = await client.QueryAsync(workspaceId,
@@ -130,14 +130,15 @@ foreach (var resourceGroup in response.Value)
You can execute multiple queries in on request using the `LogsClient.CreateBatchQuery`:
```C# Snippet:BatchQuery
-Uri endpoint = new Uri("https://api.loganalytics.io");
+var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
-LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
// Query TOP 10 resource groups by event count
// And total event count
-LogsBatchQuery batch = new LogsBatchQuery();
+var batch = new LogsBatchQuery();
+
string countQueryId = batch.AddQuery(workspaceId, "AzureActivity | count", TimeSpan.FromDays(1));
string topQueryId = batch.AddQuery(workspaceId, "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count", TimeSpan.FromDays(1));
@@ -158,10 +159,10 @@ foreach (var logEntryModel in topEntries)
You can also dynamically inspect the list of columns. The following example prints the result of the query as a table:
```C# Snippet:QueryLogsPrintTable
-Uri endpoint = new Uri("https://api.loganalytics.io");
+var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
-LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
Response response = await client.QueryAsync(workspaceId, "AzureActivity | top 10 by TimeGenerated", TimeSpan.FromDays(1));
LogsQueryResultTable table = response.Value.PrimaryTable;
@@ -190,10 +191,10 @@ foreach (var row in table.Rows)
Some Logs queries take longer than 3 minutes to execute. The default server timeout is 3 minutes. You can increase the server timeout to a maximum of 10 minutes. In the following example, the `LogsQueryOptions` object's `ServerTimeout` property is used to set the server timeout to 10 minutes:
```C# Snippet:QueryLogsWithTimeout
-Uri endpoint = new Uri("https://api.loganalytics.io");
+var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
-LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
// Query TOP 10 resource groups by event count
Response> response = await client.QueryAsync(workspaceId,
@@ -215,7 +216,7 @@ foreach (var resourceGroup in response.Value)
You can query metrics using the `MetricsClient.QueryAsync`. For every requested metric a set of aggregated values would be returned inside the `TimeSeries` collection.
```C# Snippet:QueryMetrics
-Uri endpoint = new Uri("https://management.azure.com");
+var endpoint = new Uri("https://management.azure.com");
string resourceId =
"/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/";
@@ -250,10 +251,10 @@ When you interact with the Azure Monitor Query client library using the .NET SDK
For example, if you submit an invalid query a `400` error is returned, indicating "Bad Request".
```C# Snippet:BadRequest
-Uri endpoint = new Uri("https://api.loganalytics.io");
+var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
-LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
try
{
diff --git a/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs b/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs
index 655e95d263fc..175b7effa031 100644
--- a/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs
+++ b/sdk/monitor/Azure.Monitor.Query/api/Azure.Monitor.Query.netstandard2.0.cs
@@ -13,12 +13,12 @@ public LogsQueryClient(Azure.Core.TokenCredential credential, Azure.Monitor.Quer
public LogsQueryClient(System.Uri endpoint, Azure.Core.TokenCredential credential) { }
public LogsQueryClient(System.Uri endpoint, Azure.Core.TokenCredential credential, Azure.Monitor.Query.LogsQueryClientOptions options) { }
public static string CreateQuery(System.FormattableString filter) { throw null; }
- public virtual Azure.Response Query(string workspace, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
- public virtual System.Threading.Tasks.Task> QueryAsync(string workspace, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
- public virtual System.Threading.Tasks.Task>> QueryAsync(string workspace, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public virtual Azure.Response Query(string workspaceId, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public virtual System.Threading.Tasks.Task> QueryAsync(string workspaceId, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public virtual System.Threading.Tasks.Task>> QueryAsync(string workspaceId, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual Azure.Response QueryBatch(Azure.Monitor.Query.LogsBatchQuery batch, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public virtual System.Threading.Tasks.Task> QueryBatchAsync(Azure.Monitor.Query.LogsBatchQuery batch, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
- public virtual Azure.Response> Query(string workspace, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
+ public virtual Azure.Response> Query(string workspaceId, string query, Azure.Core.DateTimeRange timeRange, Azure.Monitor.Query.LogsQueryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
}
public partial class LogsQueryClientOptions : Azure.Core.ClientOptions
{
@@ -124,15 +124,16 @@ public partial class LogsQueryResult
internal LogsQueryResult() { }
public Azure.Core.ResponseError Error { get { throw null; } }
public Azure.Monitor.Query.Models.LogsQueryResultTable PrimaryTable { get { throw null; } }
- public System.BinaryData Statistics { get { throw null; } }
public System.Collections.Generic.IReadOnlyList Tables { get { throw null; } }
- public System.BinaryData Visualization { get { throw null; } }
+ public System.BinaryData GetStatistics() { throw null; }
+ public System.BinaryData GetVisualization() { throw null; }
}
public partial class LogsQueryResultColumn
{
internal LogsQueryResultColumn() { }
public string Name { get { throw null; } }
public Azure.Monitor.Query.Models.LogsColumnType Type { get { throw null; } }
+ public override string ToString() { throw null; }
}
public partial class LogsQueryResultRow
{
@@ -164,6 +165,7 @@ internal LogsQueryResultRow() { }
public System.TimeSpan GetTimeSpan(string name) { throw null; }
public bool IsNull(int index) { throw null; }
public bool IsNull(string name) { throw null; }
+ public override string ToString() { throw null; }
}
public partial class LogsQueryResultTable
{
@@ -172,6 +174,7 @@ internal LogsQueryResultTable() { }
public string Name { get { throw null; } }
public System.Collections.Generic.IReadOnlyList Rows { get { throw null; } }
public System.Collections.Generic.IReadOnlyList Deserialize() { throw null; }
+ public override string ToString() { throw null; }
}
public partial class Metric
{
diff --git a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs
index 8f45527931c8..01b0ad053425 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryClient.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
@@ -79,33 +79,61 @@ protected LogsQueryClient()
}
///
- /// Executes the logs query.
+ /// Executes the logs query. Deserializes the result into a strongly typed model class or a primitive type if the query returns a single column.
+ ///
+ /// Example of querying a model:
+ ///
+ /// Response<IReadOnlyList<MyLogEntryModel>> response = await client.QueryAsync<MyLogEntryModel>(workspaceId,
+ /// "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count",
+ /// TimeSpan.FromDays(1));
+ ///
+ ///
+ /// Example of querying a primitive:
+ ///
+ /// Response<IReadOnlyList<string>> response = await client.QueryAsync<string>(workspaceId,
+ /// "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count | project ResourceGroup",
+ /// TimeSpan.FromDays(1));
+ ///
///
- /// The workspace to include in the query.
+ /// The workspace id to include in the query (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
/// The query text to execute.
/// The timespan over which to query data. Logs would be filtered to include entries produced starting at Now - timeSpan.
/// The to configure the query.
/// The to use.
/// Query results mapped to a type .
- public virtual Response> Query(string workspace, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
+ public virtual Response> Query(string workspaceId, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
- Response response = Query(workspace, query, timeRange, options, cancellationToken);
+ Response response = Query(workspaceId, query, timeRange, options, cancellationToken);
return Response.FromValue(RowBinder.Shared.BindResults(response.Value.Tables), response.GetRawResponse());
}
///
- /// Executes the logs query.
+ /// Executes the logs query. Deserializes the result into a strongly typed model class or a primitive type if the query returns a single column.
+ ///
+ /// Example of querying a model:
+ ///
+ /// Response<IReadOnlyList<MyLogEntryModel>> response = await client.QueryAsync<MyLogEntryModel>(workspaceId,
+ /// "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count",
+ /// TimeSpan.FromDays(1));
+ ///
+ ///
+ /// Example of querying a primitive:
+ ///
+ /// Response<IReadOnlyList<string>> response = await client.QueryAsync<string>(workspaceId,
+ /// "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count | project ResourceGroup",
+ /// TimeSpan.FromDays(1));
+ ///
///
- /// The workspace to include in the query.
+ /// The workspace id to include in the query (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
/// The query text to execute.
/// The timespan over which to query data. Logs would be filtered to include entries produced starting at Now - timeSpan.
/// The to configure the query.
/// The to use.
/// Query results mapped to a type .
- public virtual async Task>> QueryAsync(string workspace, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
+ public virtual async Task>> QueryAsync(string workspaceId, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
- Response response = await QueryAsync(workspace, query, timeRange, options, cancellationToken).ConfigureAwait(false);
+ Response response = await QueryAsync(workspaceId, query, timeRange, options, cancellationToken).ConfigureAwait(false);
return Response.FromValue(RowBinder.Shared.BindResults(response.Value.Tables), response.GetRawResponse());
}
@@ -113,19 +141,19 @@ public virtual async Task>> QueryAsync(string works
///
/// Executes the logs query.
///
- /// The workspace to include in the query.
+ /// The workspace id to include in the query (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
/// The query text to execute.
/// The timespan over which to query data. Logs would be filtered to include entries produced starting at Now - timeSpan.
/// The to configure the query.
/// The to use.
/// The containing the query results.
- public virtual Response Query(string workspace, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
+ public virtual Response Query(string workspaceId, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(LogsQueryClient)}.{nameof(Query)}");
scope.Start();
try
{
- return ExecuteAsync(workspace, query, timeRange, options, false, cancellationToken).EnsureCompleted();
+ return ExecuteAsync(workspaceId, query, timeRange, options, false, cancellationToken).EnsureCompleted();
}
catch (Exception e)
{
@@ -137,19 +165,19 @@ public virtual Response Query(string workspace, string query, D
///
/// Executes the logs query.
///
- /// The workspace to include in the query.
+ /// The workspace id to include in the query (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
/// The query text to execute.
/// The timespan over which to query data. Logs would be filtered to include entries produced starting at Now - timeSpan.
/// The to configure the query.
/// The to use.
/// The with the query results.
- public virtual async Task> QueryAsync(string workspace, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
+ public virtual async Task> QueryAsync(string workspaceId, string query, DateTimeRange timeRange, LogsQueryOptions options = null, CancellationToken cancellationToken = default)
{
using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(LogsQueryClient)}.{nameof(Query)}");
scope.Start();
try
{
- return await ExecuteAsync(workspace, query, timeRange, options, true, cancellationToken).ConfigureAwait(false);
+ return await ExecuteAsync(workspaceId, query, timeRange, options, true, cancellationToken).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -159,7 +187,31 @@ public virtual async Task> QueryAsync(string workspace
}
///
- /// Submits the batch query.
+ /// Submits the batch query. Use the to compose a batch query.
+ ///
+ /// var endpoint = new Uri("https://api.loganalytics.io");
+ /// string workspaceId = "<workspace_id>";
+ ///
+ /// var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ ///
+ /// // Query TOP 10 resource groups by event count
+ /// // And total event count
+ /// var batch = new LogsBatchQuery();
+ ///
+ /// string countQueryId = batch.AddQuery(workspaceId, "AzureActivity | count", TimeSpan.FromDays(1));
+ /// string topQueryId = batch.AddQuery(workspaceId, "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count", TimeSpan.FromDays(1));
+ ///
+ /// Response<LogsBatchQueryResults> response = await client.QueryBatchAsync(batch);
+ ///
+ /// var count = response.Value.GetResult<int>(countQueryId).Single();
+ /// var topEntries = response.Value.GetResult<MyLogEntryModel>(topQueryId);
+ ///
+ /// Console.WriteLine($"AzureActivity has total {count} events");
+ /// foreach (var logEntryModel in topEntries)
+ /// {
+ /// Console.WriteLine($"{logEntryModel.ResourceGroup} had {logEntryModel.Count} events");
+ /// }
+ ///
///
/// The batch of queries to send.
/// The to use.
@@ -183,7 +235,31 @@ public virtual Response QueryBatch(LogsBatchQuery batch,
}
///
- /// Submits the batch query.
+ /// Submits the batch query. Use the to compose a batch query.
+ ///
+ /// var endpoint = new Uri("https://api.loganalytics.io");
+ /// string workspaceId = "<workspace_id>";
+ ///
+ /// var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ ///
+ /// // Query TOP 10 resource groups by event count
+ /// // And total event count
+ /// var batch = new LogsBatchQuery();
+ ///
+ /// string countQueryId = batch.AddQuery(workspaceId, "AzureActivity | count", TimeSpan.FromDays(1));
+ /// string topQueryId = batch.AddQuery(workspaceId, "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count", TimeSpan.FromDays(1));
+ ///
+ /// Response<LogsBatchQueryResults> response = await client.QueryBatchAsync(batch);
+ ///
+ /// var count = response.Value.GetResult<int>(countQueryId).Single();
+ /// var topEntries = response.Value.GetResult<MyLogEntryModel>(topQueryId);
+ ///
+ /// Console.WriteLine($"AzureActivity has total {count} events");
+ /// foreach (var logEntryModel in topEntries)
+ /// {
+ /// Console.WriteLine($"{logEntryModel.ResourceGroup} had {logEntryModel.Count} events");
+ /// }
+ ///
///
/// The batch of queries to send.
/// The to use.
diff --git a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryOptions.cs b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryOptions.cs
index d64fcb665d47..ea8c602cfd8d 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/LogsQueryOptions.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/LogsQueryOptions.cs
@@ -20,14 +20,14 @@ public class LogsQueryOptions
///
/// Gets or sets the value indicating whether to include query execution statistics as part of the response.
- /// Statistics can be retrieved via the property.
+ /// Statistics can be retrieved via the method.
/// Defaults to false.
///
public bool IncludeStatistics { get; set; }
///
/// Gets or sets the value indicating whether to include query visualization as part of the response.
- /// Visualization can be retrieved via the property.
+ /// Visualization can be retrieved via the method.
/// Defaults to false.
///
public bool IncludeVisualization { get; set; }
diff --git a/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs b/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs
index 28bf77ef0432..4733317509ae 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/MetricsQueryClient.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
@@ -24,7 +24,7 @@ public class MetricsQueryClient
///
/// Initializes a new instance of .
///
- /// The service endpoint to use.
+ /// The resource manager service endpoint to use. For example, https://management.azure.com/ for public cloud.
/// The instance to use for authentication.
public MetricsQueryClient(Uri endpoint, TokenCredential credential) : this(endpoint, credential, null)
{
@@ -33,7 +33,7 @@ public MetricsQueryClient(Uri endpoint, TokenCredential credential) : this(endpo
///
/// Initializes a new instance of .
///
- /// The service endpoint to use.
+ /// The resource manager service endpoint to use. For example https://management.azure.com/ for public cloud.
/// The instance to use for authentication.
/// The instance to as client configuration.
public MetricsQueryClient(Uri endpoint, TokenCredential credential, MetricsQueryClientOptions options)
@@ -59,6 +59,32 @@ protected MetricsQueryClient()
///
/// Queries metrics for a resource.
+ ///
+ /// var endpoint = new Uri("https://management.azure.com");
+ /// string resourceId =
+ /// "/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.OperationalInsights/workspaces/<workspace_name>";
+ ///
+ /// var metricsClient = new MetricsQueryClient(endpoint, new DefaultAzureCredential());
+ ///
+ /// Response<MetricQueryResult> results = await metricsClient.QueryAsync(
+ /// resourceId,
+ /// new[] {"Microsoft.OperationalInsights/workspaces"}
+ /// );
+ ///
+ /// foreach (var metric in results.Value.Metrics)
+ /// {
+ /// Console.WriteLine(metric.Name);
+ /// foreach (var element in metric.TimeSeries)
+ /// {
+ /// Console.WriteLine("Dimensions: " + string.Join(",", element.Metadata));
+ ///
+ /// foreach (var metricValue in element.Data)
+ /// {
+ /// Console.WriteLine(metricValue);
+ /// }
+ /// }
+ /// }
+ ///
///
/// The resource name.
/// For example: /subscriptions/[subscription_id]/resourceGroups/[resource_group_name]/providers/Microsoft.OperationalInsights/workspaces/[workspace_name].
@@ -92,6 +118,32 @@ public virtual Response Query(string resourceId, IEnumerable<
///
/// Queries metrics for a resource.
+ ///
+ /// var endpoint = new Uri("https://management.azure.com");
+ /// string resourceId =
+ /// "/subscriptions/<subscription_id>/resourceGroups/<resource_group_name>/providers/Microsoft.OperationalInsights/workspaces/<workspace_name>";
+ ///
+ /// var metricsClient = new MetricsQueryClient(endpoint, new DefaultAzureCredential());
+ ///
+ /// Response<MetricQueryResult> results = await metricsClient.QueryAsync(
+ /// resourceId,
+ /// new[] {"Microsoft.OperationalInsights/workspaces"}
+ /// );
+ ///
+ /// foreach (var metric in results.Value.Metrics)
+ /// {
+ /// Console.WriteLine(metric.Name);
+ /// foreach (var element in metric.TimeSeries)
+ /// {
+ /// Console.WriteLine("Dimensions: " + string.Join(",", element.Metadata));
+ ///
+ /// foreach (var metricValue in element.Data)
+ /// {
+ /// Console.WriteLine(metricValue);
+ /// }
+ /// }
+ /// }
+ ///
///
/// The resource name.
/// For example: /subscriptions/[subscription_id]/resourceGroups/[resource_group_name]/providers/Microsoft.OperationalInsights/workspaces/[workspace_name].
@@ -232,4 +284,4 @@ private static string GetAggregation(MetricsQueryOptions options)
return string.Join(",", options.Aggregations);
}
}
-}
\ No newline at end of file
+}
diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQuery.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQuery.cs
index eaaa8497535c..77bd05b00c3b 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQuery.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQuery.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System.Collections.Generic;
@@ -25,6 +25,15 @@ public LogsBatchQuery()
///
/// Adds the specified query to the batch. Results can be retrieved after the query is submitted via the call.
+ ///
+ /// string countQueryId = batch.AddQuery(workspaceId, "AzureActivity | count", TimeSpan.FromDays(1));
+ /// string topQueryId = batch.AddQuery(workspaceId, "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count", TimeSpan.FromDays(1));
+ ///
+ /// Response<LogsBatchQueryResults> response = await client.QueryBatchAsync(batch);
+ ///
+ /// var count = response.Value.GetResult<int>(countQueryId).Single();
+ /// var topEntries = response.Value.GetResult<MyLogEntryModel>(topQueryId);
+ ///
///
/// The workspace to include in the query.
/// The query text to execute.
diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQueryResults.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQueryResults.cs
index c4a630746c77..d3fe9422ebef 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQueryResults.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsBatchQueryResults.cs
@@ -23,6 +23,15 @@ public partial class LogsBatchQueryResults
///
/// Gets the result for the query that was a part of the batch.
///
+ ///
+ /// string countQueryId = batch.AddQuery(workspaceId, "AzureActivity | count", TimeSpan.FromDays(1));
+ /// string topQueryId = batch.AddQuery(workspaceId, "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count", TimeSpan.FromDays(1));
+ ///
+ /// Response<LogsBatchQueryResults> response = await client.QueryBatchAsync(batch);
+ ///
+ /// var count = response.Value.GetResult<int>(countQueryId).Single();
+ /// var topEntries = response.Value.GetResult<MyLogEntryModel>(topQueryId);
+ ///
/// The query identifier returned from the .
/// The with the query results.
/// When the query with was not part of the batch.
@@ -39,7 +48,8 @@ public LogsQueryResult GetResult(string queryId)
if (result.Body.HasFailed)
{
- throw new RequestFailedException(result.Status ?? 0, result.Body.Error.Message, result.Body.Error.Code, null);
+ var message = $"Batch query with id '{queryId}' failed.{Environment.NewLine}{result.Body.Error}";
+ throw new RequestFailedException(result.Status ?? 0, message, result.Body.Error.Code, null);
}
return result.Body;
diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultRow.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultRow.cs
index 2378ff9c75ee..76d563235d85 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultRow.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultRow.cs
@@ -271,5 +271,11 @@ public object GetObject(int index)
public object this[string name] => GetObject(name);
internal bool TryGetColumn(string name, out int column) => _columnMap.TryGetValue(name, out column);
+
+ ///
+ public override string ToString()
+ {
+ return _row.ToString();
+ }
}
}
\ No newline at end of file
diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultTable.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultTable.cs
index ce228865fb9d..6e2b119edb10 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultTable.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResultTable.cs
@@ -48,5 +48,11 @@ public IReadOnlyList Deserialize()
{
return RowBinder.Shared.BindResults(new[] { this });
}
+
+ ///
+ public override string ToString()
+ {
+ return $"{Name}: {Rows.Count} rows, {Columns.Count} columns";
+ }
}
}
\ No newline at end of file
diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResults.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResults.cs
index fcde12061b17..f5fce17dd131 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResults.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/Models/LogsQueryResults.cs
@@ -29,12 +29,12 @@ public partial class LogsQueryResult
///
/// Returns the query statistics if the is set to true. Null otherwise.
///
- public BinaryData Statistics => _statistics.ValueKind == JsonValueKind.Undefined ? null : new BinaryData(_statistics.ToString());
+ public BinaryData GetStatistics() => _statistics.ValueKind == JsonValueKind.Undefined ? null : new BinaryData(_statistics.ToString());
///
/// Returns the query visualization if the is set to true. Null otherwise.
///
- public BinaryData Visualization => _visualization.ValueKind == JsonValueKind.Undefined ? null : new BinaryData(_visualization.ToString());
+ public BinaryData GetVisualization() => _visualization.ValueKind == JsonValueKind.Undefined ? null : new BinaryData(_visualization.ToString());
///
/// Get's the error that occured during query processing. The value would be null if the query succeeds.
diff --git a/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs b/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs
index 4f217431104e..0e1796323e3d 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/Models/QueryResultColumn.cs
@@ -8,5 +8,10 @@ namespace Azure.Monitor.Query.Models
[CodeGenModel("Column")]
public partial class LogsQueryResultColumn
{
+ ///
+ public override string ToString()
+ {
+ return $"{Name} ({Type})";
+ }
}
}
\ No newline at end of file
diff --git a/sdk/monitor/Azure.Monitor.Query/src/RowBinder.cs b/sdk/monitor/Azure.Monitor.Query/src/RowBinder.cs
index 780dfffd3457..98f098faf9c8 100644
--- a/sdk/monitor/Azure.Monitor.Query/src/RowBinder.cs
+++ b/sdk/monitor/Azure.Monitor.Query/src/RowBinder.cs
@@ -97,7 +97,8 @@ protected override bool TryGet(BoundMemberInfo memberInfo, LogsQueryResultRow
else
{
- throw new NotSupportedException($"The {typeof(T)} type is not supported as a deserialization target.");
+ throw new NotSupportedException($"The {typeof(T)} type is not supported as a deserialization target. " +
+ "Supported types are string, bool, long, decimal, double, object, Guid, DateTimeOffset, TimeSpan, BinaryData.");
}
return true;
diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsClientSamples.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsClientSamples.cs
index 68e1d48d2f81..4b372eafb60f 100644
--- a/sdk/monitor/Azure.Monitor.Query/tests/LogsClientSamples.cs
+++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsClientSamples.cs
@@ -18,14 +18,14 @@ public async Task QueryLogsAsTable()
{
#region Snippet:QueryLogsAsTable
#if SNIPPET
- Uri endpoint = new Uri("https://api.loganalytics.io");
+ var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
#else
Uri endpoint = TestEnvironment.LogsEndpoint;
string workspaceId = TestEnvironment.WorkspaceId;
#endif
- LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
Response response = await client.QueryAsync(workspaceId, "AzureActivity | top 10 by TimeGenerated", TimeSpan.FromDays(1));
LogsQueryResultTable table = response.Value.PrimaryTable;
@@ -44,14 +44,14 @@ public async Task QueryLogsAsTablePrintAll()
#region Snippet:QueryLogsPrintTable
#if SNIPPET
- Uri endpoint = new Uri("https://api.loganalytics.io");
+ var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
#else
Uri endpoint = TestEnvironment.LogsEndpoint;
string workspaceId = TestEnvironment.WorkspaceId;
#endif
- LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
Response response = await client.QueryAsync(workspaceId, "AzureActivity | top 10 by TimeGenerated", TimeSpan.FromDays(1));
LogsQueryResultTable table = response.Value.PrimaryTable;
@@ -83,19 +83,21 @@ public async Task QueryLogsAsPrimitive()
#region Snippet:QueryLogsAsPrimitive
#if SNIPPET
- Uri endpoint = new Uri("https://api.loganalytics.io");
+ var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
#else
Uri endpoint = TestEnvironment.LogsEndpoint;
string workspaceId = TestEnvironment.WorkspaceId;
#endif
- LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
// Query TOP 10 resource groups by event count
+ #region Snippet:QueryLogsAsPrimitiveCall
Response> response = await client.QueryAsync(workspaceId,
"AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count | project ResourceGroup",
TimeSpan.FromDays(1));
+ #endregion
foreach (var resourceGroup in response.Value)
{
@@ -110,7 +112,7 @@ public async Task QueryLogsAsModels()
{
#region Snippet:QueryLogsAsModels
- LogsQueryClient client = new LogsQueryClient(TestEnvironment.LogsEndpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(TestEnvironment.LogsEndpoint, new DefaultAzureCredential());
#if SNIPPET
string workspaceId = "";
#else
@@ -118,9 +120,11 @@ public async Task QueryLogsAsModels()
#endif
// Query TOP 10 resource groups by event count
+ #region Snippet:QueryLogsAsModelCall
Response> response = await client.QueryAsync(workspaceId,
"AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count",
TimeSpan.FromDays(1));
+ #endregion
foreach (var logEntryModel in response.Value)
{
@@ -136,18 +140,20 @@ public async Task BatchQuery()
#region Snippet:BatchQuery
#if SNIPPET
- Uri endpoint = new Uri("https://api.loganalytics.io");
+ var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
#else
Uri endpoint = TestEnvironment.LogsEndpoint;
string workspaceId = TestEnvironment.WorkspaceId;
#endif
- LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
// Query TOP 10 resource groups by event count
// And total event count
- LogsBatchQuery batch = new LogsBatchQuery();
+ var batch = new LogsBatchQuery();
+
+ #region Snippet:BatchQueryAddAndGet
string countQueryId = batch.AddQuery(workspaceId, "AzureActivity | count", TimeSpan.FromDays(1));
string topQueryId = batch.AddQuery(workspaceId, "AzureActivity | summarize Count = count() by ResourceGroup | top 10 by Count", TimeSpan.FromDays(1));
@@ -155,6 +161,7 @@ public async Task BatchQuery()
var count = response.Value.GetResult(countQueryId).Single();
var topEntries = response.Value.GetResult(topQueryId);
+ #endregion
Console.WriteLine($"AzureActivity has total {count} events");
foreach (var logEntryModel in topEntries)
@@ -170,14 +177,14 @@ public async Task QueryLogsWithTimeout()
{
#region Snippet:QueryLogsWithTimeout
#if SNIPPET
- Uri endpoint = new Uri("https://api.loganalytics.io");
+ var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
#else
Uri endpoint = TestEnvironment.LogsEndpoint;
string workspaceId = TestEnvironment.WorkspaceId;
#endif
- LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
// Query TOP 10 resource groups by event count
Response> response = await client.QueryAsync(workspaceId,
@@ -201,14 +208,14 @@ public async Task BadRequest()
{
#region Snippet:BadRequest
#if SNIPPET
- Uri endpoint = new Uri("https://api.loganalytics.io");
+ var endpoint = new Uri("https://api.loganalytics.io");
string workspaceId = "";
#else
Uri endpoint = TestEnvironment.LogsEndpoint;
string workspaceId = TestEnvironment.WorkspaceId;
#endif
- LogsQueryClient client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
+ var client = new LogsQueryClient(endpoint, new DefaultAzureCredential());
try
{
diff --git a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs
index 69d34e1ea6c3..bcb152418871 100644
--- a/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs
+++ b/sdk/monitor/Azure.Monitor.Query/tests/LogsQueryClientClientLiveTests.cs
@@ -487,7 +487,7 @@ public async Task ThrowsExceptionWhenQueryFailsBatch()
var exception = Assert.Throws(() => batchResult.Value.GetResult(queryId));
Assert.AreEqual("BadArgumentError", exception.ErrorCode);
- StringAssert.StartsWith("The request had some invalid properties", exception.Message);
+ StringAssert.StartsWith("Batch query with id '0' failed.", exception.Message);
}
[RecordedTest]
@@ -520,12 +520,12 @@ public async Task CanQueryWithStatistics(bool include)
if (include)
{
- using JsonDocument document = JsonDocument.Parse(response.Value.Statistics);
+ using JsonDocument document = JsonDocument.Parse(response.Value.GetStatistics());
Assert.Greater(document.RootElement.GetProperty("query").GetProperty("executionTime").GetDouble(), 0);
}
else
{
- Assert.AreEqual(default, response.Value.Statistics);
+ Assert.AreEqual(default, response.Value.GetStatistics());
}
}
@@ -543,12 +543,12 @@ public async Task CanQueryWithVisualization(bool include)
if (include)
{
- using JsonDocument document = JsonDocument.Parse(response.Value.Visualization);
+ using JsonDocument document = JsonDocument.Parse(response.Value.GetVisualization());
Assert.AreNotEqual(JsonValueKind.Undefined, document.RootElement.GetProperty("visualization").ValueKind);
}
else
{
- Assert.AreEqual(default, response.Value.Visualization);
+ Assert.AreEqual(default, response.Value.GetVisualization());
}
}
@@ -569,12 +569,12 @@ public async Task CanQueryWithStatisticsBatch(bool include)
if (include)
{
- using JsonDocument document = JsonDocument.Parse(result.Statistics);
+ using JsonDocument document = JsonDocument.Parse(result.GetStatistics());
Assert.Greater(document.RootElement.GetProperty("query").GetProperty("executionTime").GetDouble(), 0);
}
else
{
- Assert.AreEqual(default, result.Statistics);
+ Assert.AreEqual(default, result.GetStatistics());
}
}
diff --git a/sdk/monitor/Azure.Monitor.Query/tests/MetricsClientSamples.cs b/sdk/monitor/Azure.Monitor.Query/tests/MetricsClientSamples.cs
index 355c55042f34..9d6d32b58e1e 100644
--- a/sdk/monitor/Azure.Monitor.Query/tests/MetricsClientSamples.cs
+++ b/sdk/monitor/Azure.Monitor.Query/tests/MetricsClientSamples.cs
@@ -18,7 +18,7 @@ public async Task QueryMetrics()
#region Snippet:QueryMetrics
#if SNIPPET
- Uri endpoint = new Uri("https://management.azure.com");
+ var endpoint = new Uri("https://management.azure.com");
string resourceId =
"/subscriptions//resourceGroups//providers/Microsoft.OperationalInsights/workspaces/";
#else