From 59477cf7763eed17db5a7a9c452cdc6af8fe04f6 Mon Sep 17 00:00:00 2001 From: Matthew Sainsbury Date: Tue, 24 Feb 2026 10:40:40 -0800 Subject: [PATCH 1/3] plumb EnableStandardMetrics and EnablePerfCounters --- .../src/AzureMonitorOptions.cs | 14 + .../AzureMonitorOptionsTests.cs | 256 ++++++++++++++++++ 2 files changed, 270 insertions(+) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs index e152e65924b2..cc436c9f7e16 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs @@ -48,6 +48,18 @@ public class AzureMonitorOptions : ClientOptions /// public bool EnableLiveMetrics { get; set; } = true; + /// + /// Gets or sets a value indicating whether standard metrics should be collected. + /// Default is true. + /// + public bool EnableStandardMetrics { get; set; } = true; + + /// + /// Gets or sets a value indicating whether performance counters should be collected. + /// Default is true. + /// + public bool EnablePerfCounters { get; set; } = true; + /// /// Enables or disables filtering logs based on trace sampling decisions. /// @@ -95,6 +107,8 @@ internal void SetValueToExporterOptions(AzureMonitorExporterOptions exporterOpti exporterOptions.TracesPerSecond = TracesPerSecond; exporterOptions.StorageDirectory = StorageDirectory; exporterOptions.EnableLiveMetrics = EnableLiveMetrics; + exporterOptions.EnableStandardMetrics = EnableStandardMetrics; + exporterOptions.EnablePerfCounters = EnablePerfCounters; exporterOptions.EnableTraceBasedLogsSampler = EnableTraceBasedLogsSampler; if (Transport != null) { diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/AzureMonitorOptionsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/AzureMonitorOptionsTests.cs index c0d9a6c13cef..185d76fab398 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/AzureMonitorOptionsTests.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/AzureMonitorOptionsTests.cs @@ -141,6 +141,262 @@ public void UseAzureMonitor_EnableTraceBasedLogsSampler_PropagatesCorrectly() Assert.True(exporterOptions.EnableTraceBasedLogsSampler); } + [Fact] + public void AzureMonitorOptions_EnableStandardMetrics_DefaultValue_IsTrue() + { + // Arrange & Act + var options = new AzureMonitorOptions(); + + // Assert + Assert.True(options.EnableStandardMetrics); + } + + [Fact] + public void AzureMonitorOptions_EnableStandardMetrics_CanBeDisabled() + { + // Arrange & Act + var options = new AzureMonitorOptions + { + EnableStandardMetrics = false + }; + + // Assert + Assert.False(options.EnableStandardMetrics); + } + + [Fact] + public void AzureMonitorOptions_SetValueToExporterOptions_CopiesEnableStandardMetrics() + { + // Arrange + var azureMonitorOptions = new AzureMonitorOptions + { + ConnectionString = TestConnectionString, + EnableStandardMetrics = false + }; + + var exporterOptions = new AzureMonitorExporterOptions(); + + // Act + azureMonitorOptions.SetValueToExporterOptions(exporterOptions); + + // Assert + Assert.False(exporterOptions.EnableStandardMetrics); + Assert.Equal(TestConnectionString, exporterOptions.ConnectionString); + } + + [Fact] + public void UseAzureMonitor_DefaultEnableStandardMetrics() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = TestConnectionString; + options.DisableOfflineStorage = true; + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Assert + var azureMonitorOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.True(azureMonitorOptions.EnableStandardMetrics); + + var exporterOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.True(exporterOptions.EnableStandardMetrics); + } + + [Fact] + public void UseAzureMonitor_CanDisableStandardMetrics() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = TestConnectionString; + options.EnableStandardMetrics = false; + options.DisableOfflineStorage = true; + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Assert + var azureMonitorOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.False(azureMonitorOptions.EnableStandardMetrics); + + var exporterOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.False(exporterOptions.EnableStandardMetrics); + } + + [Fact] + public void UseAzureMonitor_EnableStandardMetrics_PropagatesCorrectly() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act - Test with true + serviceCollection.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = TestConnectionString; + options.EnableStandardMetrics = true; + options.DisableOfflineStorage = true; + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Assert + var azureMonitorOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + var exporterOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.Equal(azureMonitorOptions.EnableStandardMetrics, exporterOptions.EnableStandardMetrics); + Assert.True(exporterOptions.EnableStandardMetrics); + } + + [Fact] + public void AzureMonitorOptions_EnablePerfCounters_DefaultValue_IsTrue() + { + // Arrange & Act + var options = new AzureMonitorOptions(); + + // Assert + Assert.True(options.EnablePerfCounters); + } + + [Fact] + public void AzureMonitorOptions_EnablePerfCounters_CanBeDisabled() + { + // Arrange & Act + var options = new AzureMonitorOptions + { + EnablePerfCounters = false + }; + + // Assert + Assert.False(options.EnablePerfCounters); + } + + [Fact] + public void AzureMonitorOptions_SetValueToExporterOptions_CopiesEnablePerfCounters() + { + // Arrange + var azureMonitorOptions = new AzureMonitorOptions + { + ConnectionString = TestConnectionString, + EnablePerfCounters = false + }; + + var exporterOptions = new AzureMonitorExporterOptions(); + + // Act + azureMonitorOptions.SetValueToExporterOptions(exporterOptions); + + // Assert + Assert.False(exporterOptions.EnablePerfCounters); + Assert.Equal(TestConnectionString, exporterOptions.ConnectionString); + } + + [Fact] + public void UseAzureMonitor_DefaultEnablePerfCounters() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = TestConnectionString; + options.DisableOfflineStorage = true; + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Assert + var azureMonitorOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.True(azureMonitorOptions.EnablePerfCounters); + + var exporterOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.True(exporterOptions.EnablePerfCounters); + } + + [Fact] + public void UseAzureMonitor_CanDisablePerfCounters() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act + serviceCollection.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = TestConnectionString; + options.EnablePerfCounters = false; + options.DisableOfflineStorage = true; + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Assert + var azureMonitorOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.False(azureMonitorOptions.EnablePerfCounters); + + var exporterOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.False(exporterOptions.EnablePerfCounters); + } + + [Fact] + public void UseAzureMonitor_EnablePerfCounters_PropagatesCorrectly() + { + // Arrange + var serviceCollection = new ServiceCollection(); + + // Act - Test with true + serviceCollection.AddOpenTelemetry() + .UseAzureMonitor(options => + { + options.ConnectionString = TestConnectionString; + options.EnablePerfCounters = true; + options.DisableOfflineStorage = true; + }); + + var serviceProvider = serviceCollection.BuildServiceProvider(); + + // Assert + var azureMonitorOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + var exporterOptions = serviceProvider.GetRequiredService>() + .Get(Options.DefaultName); + + Assert.Equal(azureMonitorOptions.EnablePerfCounters, exporterOptions.EnablePerfCounters); + Assert.True(exporterOptions.EnablePerfCounters); + } + [Fact] public void UseAzureMonitor_WithoutConfiguration_UsesDefaultValue() { From 8c1f191556a3f48797459bc3c8f6b479c6f300bc Mon Sep 17 00:00:00 2001 From: Matthew Sainsbury Date: Tue, 24 Feb 2026 11:08:22 -0800 Subject: [PATCH 2/3] api --- .../api/Azure.Monitor.OpenTelemetry.AspNetCore.net10.0.cs | 2 ++ .../api/Azure.Monitor.OpenTelemetry.AspNetCore.net8.0.cs | 2 ++ .../Azure.Monitor.OpenTelemetry.AspNetCore.netstandard2.0.cs | 2 ++ 3 files changed, 6 insertions(+) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net10.0.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net10.0.cs index 3a59d85b44d5..68411b159f7c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net10.0.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net10.0.cs @@ -7,6 +7,8 @@ public AzureMonitorOptions() { } public Azure.Core.TokenCredential Credential { get { throw null; } set { } } public bool DisableOfflineStorage { get { throw null; } set { } } public bool EnableLiveMetrics { get { throw null; } set { } } + public bool EnablePerfCounters { get { throw null; } set { } } + public bool EnableStandardMetrics { get { throw null; } set { } } public bool EnableTraceBasedLogsSampler { get { throw null; } set { } } public float SamplingRatio { get { throw null; } set { } } public string StorageDirectory { get { throw null; } set { } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net8.0.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net8.0.cs index 3a59d85b44d5..68411b159f7c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net8.0.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.net8.0.cs @@ -7,6 +7,8 @@ public AzureMonitorOptions() { } public Azure.Core.TokenCredential Credential { get { throw null; } set { } } public bool DisableOfflineStorage { get { throw null; } set { } } public bool EnableLiveMetrics { get { throw null; } set { } } + public bool EnablePerfCounters { get { throw null; } set { } } + public bool EnableStandardMetrics { get { throw null; } set { } } public bool EnableTraceBasedLogsSampler { get { throw null; } set { } } public float SamplingRatio { get { throw null; } set { } } public string StorageDirectory { get { throw null; } set { } } diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.netstandard2.0.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.netstandard2.0.cs index 3a59d85b44d5..68411b159f7c 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.netstandard2.0.cs +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/api/Azure.Monitor.OpenTelemetry.AspNetCore.netstandard2.0.cs @@ -7,6 +7,8 @@ public AzureMonitorOptions() { } public Azure.Core.TokenCredential Credential { get { throw null; } set { } } public bool DisableOfflineStorage { get { throw null; } set { } } public bool EnableLiveMetrics { get { throw null; } set { } } + public bool EnablePerfCounters { get { throw null; } set { } } + public bool EnableStandardMetrics { get { throw null; } set { } } public bool EnableTraceBasedLogsSampler { get { throw null; } set { } } public float SamplingRatio { get { throw null; } set { } } public string StorageDirectory { get { throw null; } set { } } From de0cf41fd90a2dd8ed27e4d058c29fadba7884b8 Mon Sep 17 00:00:00 2001 From: Matthew Sainsbury Date: Tue, 24 Feb 2026 11:36:12 -0800 Subject: [PATCH 3/3] changelog --- .../Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md index 376b2a95bfb2..997e5e57e85a 100644 --- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md +++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md @@ -4,6 +4,9 @@ ### Features Added +* Add ability to specify EnableStandardMetrics and EnablePerfCounters + ([#56438](https://github.com/Azure/azure-sdk-for-net/pull/56438)) + ### Breaking Changes * **Default Sampler Changed**: The default sampling behavior has been changed from @@ -15,7 +18,7 @@ traces exported by default. **Migration**: To maintain the previous behavior (100% sampling), explicitly configure the sampler: - + ```csharp // Option 1: Set SamplingRatio and clear TracesPerSecond builder.Services.AddOpenTelemetry() @@ -78,7 +81,7 @@ - `preview.item.dropped.count` - `preview.item.retry.count` ([#53010](https://github.com/Azure/azure-sdk-for-net/pull/53010)) -* Add `enduser.pseudo.id` as ai.user.id +* Add `enduser.pseudo.id` as ai.user.id ([#52722](https://github.com/Azure/azure-sdk-for-net/pull/52722)) * Add `ai.location.ip` mapping for all telemetry types ([#52211](https://github.com/Azure/azure-sdk-for-net/pull/52211))