-
Notifications
You must be signed in to change notification settings - Fork 48
Migrate from Azure.Monitor.Query (deprecated) to Azure.Monitor.Query.Metrics #5147
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
Changes from 3 commits
647c11b
da6b0e0
d0705d6
2f4a153
cfafbe8
5d19bd3
351ac5c
2185c64
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,8 +12,8 @@ namespace ServiceControl.Transports.ASBS; | |
| using Azure.Core; | ||
| using Azure.Core.Pipeline; | ||
| using Azure.Identity; | ||
| using Azure.Monitor.Query; | ||
| using Azure.Monitor.Query.Models; | ||
| using Azure.Monitor.Query.Metrics; | ||
| using Azure.Monitor.Query.Metrics.Models; | ||
| using Azure.ResourceManager; | ||
| using Azure.ResourceManager.Resources; | ||
| using Azure.ResourceManager.ServiceBus; | ||
|
|
@@ -26,10 +26,13 @@ public class AzureQuery(ILogger<AzureQuery> logger, TimeProvider timeProvider, T | |
| : BrokerThroughputQuery(logger, "AzureServiceBus") | ||
| { | ||
| string serviceBusName = string.Empty; | ||
| MetricsQueryClient? client; | ||
| MetricsClient? client; | ||
| ArmClient? armClient; | ||
| TokenCredential? credential; | ||
| Uri? metricsEndpoint; | ||
| string? resourceId; | ||
| ArmEnvironment armEnvironment; | ||
| MetricsClientAudience metricsQueryAudience; | ||
|
|
||
| protected override void InitializeCore(ReadOnlyDictionary<string, string> settings) | ||
| { | ||
|
|
@@ -102,7 +105,7 @@ protected override void InitializeCore(ReadOnlyDictionary<string, string> settin | |
| Diagnostics.AppendLine("Client secret set"); | ||
| } | ||
|
|
||
| (armEnvironment, var metricsQueryAudience) = GetEnvironment(); | ||
| (armEnvironment, metricsQueryAudience) = GetEnvironment(); | ||
|
|
||
| if (managementUrl == null) | ||
| { | ||
|
|
@@ -118,28 +121,17 @@ protected override void InitializeCore(ReadOnlyDictionary<string, string> settin | |
| return; | ||
| } | ||
|
|
||
| TokenCredential clientCredentials; | ||
| if (connectionSettings.AuthenticationMethod is TokenCredentialAuthentication tokenCredentialAuthentication) | ||
| { | ||
| Diagnostics.AppendLine("Attempting to use managed identity"); | ||
| clientCredentials = tokenCredentialAuthentication.Credential; | ||
| credential = tokenCredentialAuthentication.Credential; | ||
| } | ||
| else | ||
| { | ||
| clientCredentials = new ClientSecretCredential(tenantId, clientId, clientSecret); | ||
| credential = new ClientSecretCredential(tenantId, clientId, clientSecret); | ||
| } | ||
|
|
||
| client = new MetricsQueryClient(armEnvironment.Endpoint, clientCredentials, | ||
| new MetricsQueryClientOptions | ||
| { | ||
| Audience = metricsQueryAudience, | ||
| Transport = new HttpClientTransport( | ||
| new HttpClient(new SocketsHttpHandler | ||
| { | ||
| PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) | ||
| })) | ||
| }); | ||
| armClient = new ArmClient(clientCredentials, subscriptionId, | ||
| armClient = new ArmClient(credential, subscriptionId, | ||
| new ArmClientOptions | ||
| { | ||
| Environment = armEnvironment, | ||
|
|
@@ -152,31 +144,31 @@ protected override void InitializeCore(ReadOnlyDictionary<string, string> settin | |
|
|
||
| return; | ||
|
|
||
| (ArmEnvironment armEnvironment, MetricsQueryAudience metricsQueryAudience) GetEnvironment() | ||
| (ArmEnvironment armEnvironment, MetricsClientAudience metricsQueryAudience) GetEnvironment() | ||
| { | ||
| if (managementUrlParsed == null) | ||
| { | ||
| return (ArmEnvironment.AzurePublicCloud, MetricsQueryAudience.AzurePublicCloud); | ||
| return (ArmEnvironment.AzurePublicCloud, MetricsClientAudience.AzurePublicCloud); | ||
| } | ||
|
|
||
| if (managementUrlParsed == ArmEnvironment.AzurePublicCloud.Endpoint) | ||
| { | ||
| return (ArmEnvironment.AzurePublicCloud, MetricsQueryAudience.AzurePublicCloud); | ||
| return (ArmEnvironment.AzurePublicCloud, MetricsClientAudience.AzurePublicCloud); | ||
| } | ||
|
|
||
| if (managementUrlParsed == ArmEnvironment.AzureChina.Endpoint) | ||
| { | ||
| return (ArmEnvironment.AzureChina, MetricsQueryAudience.AzureChina); | ||
| return (ArmEnvironment.AzureChina, MetricsClientAudience.AzureChina); | ||
| } | ||
|
|
||
| if (managementUrlParsed == ArmEnvironment.AzureGermany.Endpoint) | ||
| { | ||
| return (ArmEnvironment.AzureGermany, MetricsQueryAudience.AzurePublicCloud); | ||
| return (ArmEnvironment.AzureGermany, MetricsClientAudience.AzurePublicCloud); | ||
| } | ||
|
|
||
| if (managementUrlParsed == ArmEnvironment.AzureGovernment.Endpoint) | ||
| { | ||
| return (ArmEnvironment.AzureGovernment, MetricsQueryAudience.AzureGovernment); | ||
| return (ArmEnvironment.AzureGovernment, MetricsClientAudience.AzureGovernment); | ||
| } | ||
|
|
||
| string options = string.Join(", ", | ||
|
|
@@ -187,7 +179,7 @@ protected override void InitializeCore(ReadOnlyDictionary<string, string> settin | |
| }.Select(armEnvironment => $"\"{armEnvironment.Endpoint}\"")); | ||
| InitialiseErrors.Add($"Management url configuration is invalid, available options are {options}"); | ||
|
|
||
| return (ArmEnvironment.AzurePublicCloud, MetricsQueryAudience.AzurePublicCloud); | ||
| return (ArmEnvironment.AzurePublicCloud, MetricsClientAudience.AzurePublicCloud); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -229,7 +221,6 @@ public override async IAsyncEnumerable<QueueThroughput> GetThroughputPerDay(IBro | |
| while (currentDate <= endDate) | ||
| { | ||
| data.Add(currentDate, new QueueThroughput { TotalThroughput = 0, DateUTC = currentDate }); | ||
|
|
||
| currentDate = currentDate.AddDays(1); | ||
| } | ||
|
|
||
|
|
@@ -247,20 +238,22 @@ public override async IAsyncEnumerable<QueueThroughput> GetThroughputPerDay(IBro | |
| async Task<IReadOnlyList<MetricValue>> GetMetrics(string queueName, DateOnly startTime, DateOnly endTime, | ||
| CancellationToken cancellationToken = default) | ||
| { | ||
| var response = await client!.QueryResourceAsync(resourceId, | ||
| new[] { "CompleteMessage" }, | ||
| new MetricsQueryOptions | ||
| var response = await client!.QueryResourcesAsync( | ||
| [new ResourceIdentifier(resourceId!)], | ||
| ["CompleteMessage"], | ||
| "Microsoft.ServiceBus/namespaces", | ||
| new MetricsQueryResourcesOptions | ||
| { | ||
| Filter = $"EntityName eq '{queueName}'", | ||
| TimeRange = new QueryTimeRange(startTime.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), endTime.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc)), | ||
| TimeRange = new MetricsQueryTimeRange(startTime.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), endTime.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc)), | ||
| Granularity = TimeSpan.FromDays(1) | ||
| }, | ||
| cancellationToken); | ||
|
|
||
| var metricValues = | ||
| response.Value.Metrics.FirstOrDefault()?.TimeSeries.FirstOrDefault()?.Values ?? []; | ||
| response.Value.Values.FirstOrDefault()?.Metrics.FirstOrDefault()?.TimeSeries.FirstOrDefault()?.Values ?? []; | ||
|
|
||
| return metricValues; | ||
| return metricValues.AsReadOnly(); | ||
jasontaylordev marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| public override async IAsyncEnumerable<IBrokerQueue> GetQueueNames( | ||
|
|
@@ -272,12 +265,37 @@ public override async IAsyncEnumerable<IBrokerQueue> GetQueueNames( | |
| var namespaces = | ||
| subscription.GetServiceBusNamespacesAsync(cancellationToken); | ||
|
|
||
| await foreach (var serviceBusNamespaceResource in namespaces.WithCancellation( | ||
| cancellationToken)) | ||
| await foreach (var serviceBusNamespaceResource in namespaces.WithCancellation(cancellationToken)) | ||
| { | ||
| if (validNamespaces.Contains(serviceBusNamespaceResource.Data.Name)) | ||
| { | ||
| resourceId = serviceBusNamespaceResource.Id; | ||
|
|
||
| // Determine the region of the namespace | ||
| var regionName = serviceBusNamespaceResource.Data.Location.Name; | ||
|
|
||
| // Build the regional Azure Monitor Metrics endpoint from the audience | ||
| var newEndpoint = BuildMetricsEndpointFromAudience(metricsQueryAudience, regionName); | ||
|
|
||
| // Create or refresh the MetricsClient if it's missing or points to a different region | ||
| if (client is null || metricsEndpoint?.ToString() != newEndpoint.ToString()) | ||
jasontaylordev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| metricsEndpoint = newEndpoint; | ||
|
|
||
| client = new MetricsClient( | ||
| metricsEndpoint, | ||
| credential!, | ||
| new MetricsClientOptions | ||
| { | ||
| Audience = metricsQueryAudience, | ||
| Transport = new HttpClientTransport( | ||
| new HttpClient(new SocketsHttpHandler | ||
| { | ||
| PooledConnectionIdleTimeout = TimeSpan.FromMinutes(2) | ||
| })) | ||
| }); | ||
|
||
| } | ||
|
|
||
| await foreach (var queue in serviceBusNamespaceResource.GetServiceBusQueues() | ||
| .WithCancellation(cancellationToken)) | ||
| { | ||
|
|
@@ -301,6 +319,21 @@ public override async IAsyncEnumerable<IBrokerQueue> GetQueueNames( | |
| { ArmEnvironment.AzureChina, "servicebus.chinacloudapi.cn" }, | ||
| }; | ||
|
|
||
| // Build metrics endpoint host directly from the configured audience. | ||
| Uri BuildMetricsEndpointFromAudience(MetricsClientAudience audience, string regionName) | ||
| { | ||
| var region = regionName.ToLowerInvariant(); | ||
|
|
||
| var audienceUri = new Uri(audience.ToString()); | ||
| var audienceHost = audienceUri.Host; // e.g., "metrics.monitor.azure.com" | ||
|
|
||
| var regionalHost = audienceHost.StartsWith("metrics.", StringComparison.OrdinalIgnoreCase) | ||
| ? audienceHost.Replace("metrics.", $"{region}.metrics.") | ||
| : $"{region}.metrics.{audienceHost}"; | ||
|
|
||
| return new Uri($"https://{regionalHost}"); | ||
jasontaylordev marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| async Task<HashSet<string>> GetValidNamespaceNames(CancellationToken cancellationToken = default) | ||
| { | ||
| var validNamespaces = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { serviceBusName }; | ||
|
|
@@ -372,4 +405,4 @@ public static class AzureServiceBusSettings | |
| public static readonly string ManagementUrl = "ASB/ManagementUrl"; | ||
| public static readonly string ManagementUrlDescription = "Azure management URL"; | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.