Skip to content

Commit 64ce03f

Browse files
authored
Merge pull request #1104 from Particular/pi-998
Replace deprecated Azure.Monitor.Query package with Azure.Monitor.Query.Metrics
2 parents 57a939e + 29f49a1 commit 64ce03f

File tree

4 files changed

+49
-57
lines changed

4 files changed

+49
-57
lines changed

src/AppCommon/Commands/AzureServiceBusCommand.cs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,34 @@ public static Command CreateCommand()
2323
IsRequired = false
2424
};
2525

26+
var regionArg = new Option<string>(
27+
name: "--region",
28+
description: "The Azure region where the Service Bus namespace is located, which is listed as the location in the Properties page in the Azure Portal.")
29+
{
30+
IsRequired = true
31+
};
32+
33+
var metricsDomainArg = new Option<string>("--metricsDomain",
34+
description: "The Azure Monitor Metrics domain. Defaults to 'metrics.monitor.azure.com' and only must be specified for Azure customers using non-standard domains like government cloud customers.")
35+
{
36+
IsRequired = false
37+
};
38+
2639
serviceBusDomainArg.SetDefaultValue("servicebus.windows.net");
40+
metricsDomainArg.SetDefaultValue("metrics.monitor.azure.com");
2741

2842
command.AddOption(resourceIdArg);
2943
command.AddOption(serviceBusDomainArg);
44+
command.AddOption(regionArg);
45+
command.AddOption(metricsDomainArg);
3046

3147
command.SetHandler(async context =>
3248
{
3349
var shared = SharedOptions.Parse(context);
3450
var resourceId = context.ParseResult.GetValueForOption(resourceIdArg);
3551
var serviceBusDomain = context.ParseResult.GetValueForOption(serviceBusDomainArg);
52+
var region = context.ParseResult.GetValueForOption(regionArg);
53+
var metricsDomain = context.ParseResult.GetValueForOption(metricsDomainArg);
3654
var cancellationToken = context.GetCancellationToken();
3755

3856
#if DEBUG
@@ -44,7 +62,7 @@ public static Command CreateCommand()
4462
}
4563
#endif
4664

47-
var runner = new AzureServiceBusCommand(shared, resourceId, serviceBusDomain);
65+
var runner = new AzureServiceBusCommand(shared, resourceId, serviceBusDomain, region, metricsDomain);
4866
await runner.Run(cancellationToken);
4967
});
5068

@@ -55,10 +73,10 @@ public static Command CreateCommand()
5573

5674
string[] queueNames;
5775

58-
public AzureServiceBusCommand(SharedOptions shared, string resourceId, string serviceBusDomain)
76+
public AzureServiceBusCommand(SharedOptions shared, string resourceId, string serviceBusDomain, string region, string metricsDomain)
5977
: base(shared)
6078
{
61-
azure = new AzureClient(resourceId, serviceBusDomain, Out.WriteLine);
79+
azure = new AzureClient(resourceId, serviceBusDomain, region, metricsDomain, Out.WriteLine);
6280
RunInfo.Add("AzureServiceBusNamespace", azure.FullyQualifiedNamespace);
6381
}
6482

src/Directory.Packages.props

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
<Project>
2-
32
<PropertyGroup>
43
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
54
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
65
</PropertyGroup>
7-
86
<ItemGroup>
97
<PackageVersion Include="AWSSDK.CloudWatch" Version="4.0.4.6" />
108
<PackageVersion Include="AWSSDK.SecurityToken" Version="4.0.2.9" />
119
<PackageVersion Include="AWSSDK.SQS" Version="4.0.1.11" />
12-
<PackageVersion Include="Azure.Identity" Version="1.14.0" />
10+
<PackageVersion Include="Azure.Identity" Version="1.17.0" />
1311
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.20.1" />
14-
<PackageVersion Include="Azure.Monitor.Query" Version="1.6.0" />
12+
<PackageVersion Include="Azure.Monitor.Query.Metrics" Version="1.0.0" />
1513
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
1614
<PackageVersion Include="ICSharpCode.Decompiler" Version="8.2.0.7535" />
1715
<PackageVersion Include="Microsoft.Data.SqlClient" Version="5.2.3" />
@@ -29,9 +27,7 @@
2927
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
3028
<PackageVersion Include="System.Threading.RateLimiting" Version="8.0.0" />
3129
</ItemGroup>
32-
3330
<ItemGroup Label="Pinned transitive dependencies">
3431
<PackageVersion Include="System.Private.Uri" Version="4.3.2" />
3532
</ItemGroup>
36-
37-
</Project>
33+
</Project>

src/Query/AzureServiceBus/AzureClient.cs

Lines changed: 24 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88
using Azure.Core;
99
using Azure.Identity;
1010
using Azure.Messaging.ServiceBus.Administration;
11-
using Azure.Monitor.Query;
12-
using Azure.Monitor.Query.Models;
11+
using Azure.Monitor.Query.Metrics;
12+
using Azure.Monitor.Query.Metrics.Models;
1313

1414
public class AzureClient
1515
{
16-
readonly string resourceId;
16+
readonly ResourceIdentifier resourceId;
1717
readonly AuthenticatedClientSet[] connections;
1818
readonly List<string> loginExceptions = [];
1919
readonly Action<string> log;
@@ -22,26 +22,15 @@ public class AzureClient
2222
AuthenticatedClientSet currentClients;
2323

2424
public string FullyQualifiedNamespace { get; }
25-
public string SubscriptionId { get; }
26-
public string ResourceGroup { get; }
27-
28-
public AzureClient(string resourceId, string serviceBusDomain, Action<string> log = null)
25+
public AzureClient(string resourceId, string serviceBusDomain, string region, string metricsDomain, Action<string> log = null)
2926
{
30-
this.resourceId = resourceId;
27+
this.resourceId = ResourceIdentifier.Parse(resourceId);
3128

3229
this.log = log ?? new(msg => { });
3330

34-
var resourceIdentifier = ResourceIdentifier.Parse(resourceId);
35-
36-
ResourceGroup = resourceIdentifier.ResourceGroupName;
37-
38-
SubscriptionId = resourceIdentifier.SubscriptionId;
39-
40-
FullyQualifiedNamespace = $"{resourceIdentifier.Name}.{serviceBusDomain}";
31+
FullyQualifiedNamespace = $"{this.resourceId.Name}.{serviceBusDomain}";
4132

42-
connections = CreateCredentials()
43-
.Select(c => new AuthenticatedClientSet(c, FullyQualifiedNamespace))
44-
.ToArray();
33+
connections = [.. CreateCredentials().Select(c => new AuthenticatedClientSet(c, FullyQualifiedNamespace, region, metricsDomain))];
4534

4635
ResetConnectionQueue();
4736
}
@@ -51,7 +40,6 @@ IEnumerable<TokenCredential> CreateCredentials()
5140
yield return new AzureCliCredential();
5241
yield return new AzurePowerShellCredential();
5342
yield return new EnvironmentCredential();
54-
yield return new SharedTokenCacheCredential();
5543
yield return new VisualStudioCredential();
5644

5745
// Don't really need this one to take 100s * 4 tries to finally time out
@@ -64,10 +52,7 @@ IEnumerable<TokenCredential> CreateCredentials()
6452
/// <summary>
6553
/// Doesn't change the last successful `current` method but restores all options as possibilities if it doesn't work
6654
/// </summary>
67-
public void ResetConnectionQueue()
68-
{
69-
connectionQueue = new Queue<AuthenticatedClientSet>(connections);
70-
}
55+
public void ResetConnectionQueue() => connectionQueue = new Queue<AuthenticatedClientSet>(connections);
7156

7257
async Task<T> GetDataWithCurrentCredentials<T>(GetDataDelegate<T> getData, CancellationToken cancellationToken)
7358
{
@@ -116,33 +101,33 @@ bool NextCredentials()
116101
}
117102
}
118103

119-
public Task<IReadOnlyList<MetricValue>> GetMetrics(string queueName, DateOnly startTime, DateOnly endTime, CancellationToken cancellationToken = default)
120-
{
121-
return GetDataWithCurrentCredentials(async token =>
104+
public Task<IList<MetricValue>> GetMetrics(string queueName, DateOnly startTime, DateOnly endTime, CancellationToken cancellationToken = default) =>
105+
GetDataWithCurrentCredentials(async token =>
122106
{
123107
try
124108
{
125-
var response = await currentClients.Metrics.QueryResourceAsync(resourceId,
109+
var response = await currentClients.Metrics.QueryResourcesAsync(
110+
[resourceId],
126111
["CompleteMessage"],
127-
new MetricsQueryOptions
112+
"Microsoft.ServiceBus/Namespaces",
113+
new MetricsQueryResourcesOptions
128114
{
129115
Filter = $"EntityName eq '{queueName}'",
130-
TimeRange = new QueryTimeRange(startTime.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc), endTime.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc)),
116+
StartTime = startTime.ToDateTime(TimeOnly.MinValue, DateTimeKind.Utc),
117+
EndTime = endTime.ToDateTime(TimeOnly.MaxValue, DateTimeKind.Utc),
131118
Granularity = TimeSpan.FromDays(1)
132119
},
133120
token).ConfigureAwait(false);
134121

135122
// Yeah, it's buried deep
136-
var metricValues = response.Value.Metrics.FirstOrDefault()?.TimeSeries.FirstOrDefault()?.Values;
137-
return metricValues;
123+
return response.Value.Values.FirstOrDefault()?.Metrics.FirstOrDefault()?.TimeSeries.FirstOrDefault()?.Values ?? [];
138124
}
139125
catch (Azure.RequestFailedException reqFailed) when (reqFailed.Message.Contains("ResourceGroupNotFound"))
140126
{
141127
// Azure exception message has a lot of information including exact resource group name
142128
throw new QueryException(QueryFailureReason.InvalidEnvironment, reqFailed.Message);
143129
}
144130
}, cancellationToken);
145-
}
146131

147132
public Task<string[]> GetQueueNames(CancellationToken cancellationToken = default)
148133
{
@@ -162,31 +147,24 @@ public Task<string[]> GetQueueNames(CancellationToken cancellationToken = defaul
162147
}, cancellationToken);
163148
}
164149

165-
static bool IsAuthenticationException(Exception x)
166-
{
167-
return x is CredentialUnavailableException or AuthenticationFailedException or UnauthorizedAccessException;
168-
}
150+
static bool IsAuthenticationException(Exception x) =>
151+
x is CredentialUnavailableException or AuthenticationFailedException or UnauthorizedAccessException;
169152

170153
delegate Task<T> GetDataDelegate<T>(CancellationToken cancellationToken);
171154

172155
class AuthenticatedClientSet
173156
{
174157
public string Name { get; }
175-
public MetricsQueryClient Metrics { get; }
158+
public MetricsClient Metrics { get; }
176159
public ServiceBusAdministrationClient ServiceBus { get; }
177160

178-
public AuthenticatedClientSet(TokenCredential credentials, string fullyQualifiedNamespace)
161+
public AuthenticatedClientSet(TokenCredential credentials, string fullyQualifiedNamespace, string region, string metricsDomain)
179162
{
180-
var managementUrl = "https://management.azure.com";
181-
182-
if (!fullyQualifiedNamespace.EndsWith("servicebus.windows.net", StringComparison.OrdinalIgnoreCase))
183-
{
184-
var reversedParts = fullyQualifiedNamespace.Split('.', StringSplitOptions.RemoveEmptyEntries).Reverse().ToArray();
185-
managementUrl = $"https://management.{reversedParts[1]}.{reversedParts[0]}";
186-
}
163+
var metricsUrl = $"https://{region}.{metricsDomain}";
164+
var audience = $"https://{metricsDomain}";
187165

188166
Name = credentials.GetType().Name;
189-
Metrics = new MetricsQueryClient(new Uri(managementUrl), credentials, new MetricsQueryClientOptions { Audience = new MetricsQueryAudience(managementUrl) });
167+
Metrics = new MetricsClient(new Uri(metricsUrl), credentials, new MetricsClientOptions { Audience = new MetricsClientAudience(audience) });
190168
ServiceBus = new ServiceBusAdministrationClient(fullyQualifiedNamespace, credentials);
191169
}
192170
}

src/Query/Particular.ThroughputQuery.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<PackageReference Include="AWSSDK.SQS" />
1111
<PackageReference Include="Azure.Identity" />
1212
<PackageReference Include="Azure.Messaging.ServiceBus" />
13-
<PackageReference Include="Azure.Monitor.Query" />
13+
<PackageReference Include="Azure.Monitor.Query.Metrics" />
1414
<PackageReference Include="Microsoft.Data.SqlClient" />
1515
<PackageReference Include="Npgsql" />
1616
<PackageReference Include="System.Threading.RateLimiting" />

0 commit comments

Comments
 (0)