diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md
index 5a95a693feb9..376b2a95bfb2 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md
@@ -6,6 +6,28 @@
### Breaking Changes
+* **Default Sampler Changed**: The default sampling behavior has been changed from
+ `ApplicationInsightsSampler` with 100% sampling (all traces sampled) to
+ `RateLimitedSampler` with 5.0 traces per second. This change significantly
+ reduces telemetry volume for high-traffic applications and provides better
+ cost optimization out of the box.
+ **Impact**: Applications with more than 5 requests per second will see fewer
+ 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()
+ .UseAzureMonitor(options =>
+ {
+ options.SamplingRatio = 1.0f;
+ options.TracesPerSecond = null;
+ });
+ // Option 2: Use environment variables
+ // OTEL_TRACES_SAMPLER=microsoft.fixed_percentage
+ // OTEL_TRACES_SAMPLER_ARG=1.0
+ ```
### Bugs Fixed
* Fixed an issue where Azure Container Apps instances were showing VM instance GUIDs
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md
index 07f046fbac09..135226c0ee25 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md
@@ -130,17 +130,46 @@ Note that the `Credential` property is optional. If it is not set, Azure Monitor
### Advanced configuration
-#### Customizing Sampling Percentage
+#### Customizing Sampling Behavior
-When using the Azure Monitor Distro, the sampling percentage for telemetry data is set to 100% (1.0F) by default. For example, let's say you want to set the sampling percentage to 50%. You can achieve this by modifying the code as follows:
+The Azure Monitor Distro uses **rate-limited sampling** by default, collecting up to **5.0 traces per second**. This provides cost-effective telemetry collection for most applications while maintaining observability.
+To customize the sampling behavior:
+
+**Option 1: Set the rate limited sampler to use a configured traces per second**
+``` C#
+builder.Services.AddOpenTelemetry().UseAzureMonitor(options =>
+{
+ options.TracesPerSecond = 10.0; // Collect up to 10 traces per second
+});
+```
+
+**Option 2: Switch to percentage-based sampling**
``` C#
builder.Services.AddOpenTelemetry().UseAzureMonitor(options =>
{
- options.SamplingRatio = 0.5F;
+ options.SamplingRatio = 0.5F; // Sample 50% of traces
+ options.TracesPerSecond = null; // Disable rate-limited sampling
});
```
+**Option 3: Use environment variables**
+For rate-limited sampling:
+
+```
+OTEL_TRACES_SAMPLER=microsoft.rate_limited
+OTEL_TRACES_SAMPLER_ARG=10
+```
+
+For percentage-based sampling:
+
+```
+OTEL_TRACES_SAMPLER=microsoft.fixed_percentage
+OTEL_TRACES_SAMPLER_ARG=0.5
+```
+
+**Note**: When both `TracesPerSecond` and `SamplingRatio` are configured, `TracesPerSecond` takes precedence.
+
#### Adding Custom ActivitySource to Traces
```C#
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs
index 8c12e41e59ae..e152e65924b2 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/AzureMonitorOptions.cs
@@ -61,7 +61,6 @@ public class AzureMonitorOptions : ClientOptions
///
/// Gets or sets the ratio of telemetry items to be sampled. The value must be between 0.0F and 1.0F, inclusive.
/// For example, specifying 0.4 means that 40% of traces are sampled and 60% are dropped.
- /// The default value is 1.0F, indicating that all telemetry items are sampled.
///
public float SamplingRatio { get; set; } = 1.0F;
@@ -70,7 +69,7 @@ public class AzureMonitorOptions : ClientOptions
/// For example, specifying 0.5 means one request every two seconds.
/// When both TracesPerSecond and SamplingRatio are specified, TracesPerSecond takes precedence.
///
- public double? TracesPerSecond { get; set; }
+ public double? TracesPerSecond { get; set; } = 5.0;
///
/// Override the default directory for offline storage.
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/DefaultAzureMonitorOptions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/DefaultAzureMonitorOptions.cs
index 9a54cf8ae102..0e32c9243a20 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/DefaultAzureMonitorOptions.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/src/DefaultAzureMonitorOptions.cs
@@ -28,7 +28,13 @@ public void Configure(AzureMonitorOptions options)
{
if (_configuration != null)
{
- _configuration.GetSection(AzureMonitorSectionFromConfig).Bind(options);
+ var azureMonitorSection = _configuration.GetSection(AzureMonitorSectionFromConfig);
+ azureMonitorSection.Bind(options);
+ if (azureMonitorSection["TracesPerSecond"] == null && azureMonitorSection["SamplingRatio"] != null)
+ {
+ // This is so user does not have to explicitly set TracesPerSecond to null in config to use fixed-percentage sampling.
+ options.TracesPerSecond = null;
+ }
// IConfiguration can read from EnvironmentVariables or InMemoryCollection if configured to do so.
var connectionStringFromIConfig = _configuration[EnvironmentVariableConstants.APPLICATIONINSIGHTS_CONNECTION_STRING];
@@ -97,6 +103,7 @@ private static void ConfigureSamplingOptions(string? samplerType, string? sample
if (ratio >= 0.0 && ratio <= 1.0)
{
options.SamplingRatio = (float)ratio;
+ options.TracesPerSecond = null; // Explicitly set to null to use fixed-percentage sampling
}
else
{
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsSamplerTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsSamplerTests.cs
index 77e862ca7806..1b81402cf263 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsSamplerTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsSamplerTests.cs
@@ -60,8 +60,8 @@ public void Configure_Sampler_InvalidArgs_Ignored()
var configurator = new DefaultAzureMonitorOptions(configuration);
var options = new AzureMonitorOptions();
configurator.Configure(options);
- Assert.Equal(1.0f, options.SamplingRatio); // default
- Assert.Null(options.TracesPerSecond);
+ Assert.Equal(1.0f, options.SamplingRatio);
+ Assert.Equal(5.0, options.TracesPerSecond); // default value retained
// invalid negative rate
configValues = new List>
@@ -73,7 +73,7 @@ public void Configure_Sampler_InvalidArgs_Ignored()
configurator = new DefaultAzureMonitorOptions(configuration);
options = new AzureMonitorOptions();
configurator.Configure(options);
- Assert.Null(options.TracesPerSecond);
+ Assert.Equal(5.0, options.TracesPerSecond); // default value retained
Assert.Equal(1.0f, options.SamplingRatio);
}
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsTests.cs
index 5240d5b9d5e2..a71ec3547a61 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/DefaultAzureMonitorOptionsTests.cs
@@ -28,6 +28,7 @@ public void VerifyConfigure_Default()
Assert.Null(azureMonitorOptions.ConnectionString);
Assert.False(azureMonitorOptions.DisableOfflineStorage);
Assert.Equal(1.0F, azureMonitorOptions.SamplingRatio);
+ Assert.Equal(5.0, azureMonitorOptions.TracesPerSecond);
Assert.Null(azureMonitorOptions.StorageDirectory);
Assert.True(azureMonitorOptions.EnableTraceBasedLogsSampler);
}
@@ -57,6 +58,35 @@ public void VerifyConfigure_ViaJson()
Assert.Equal("testJsonValue", azureMonitorOptions.ConnectionString);
Assert.True(azureMonitorOptions.DisableOfflineStorage);
Assert.Equal(0.5F, azureMonitorOptions.SamplingRatio);
+ Assert.Null(azureMonitorOptions.TracesPerSecond);
+ Assert.Equal("testJsonValue", azureMonitorOptions.StorageDirectory);
+ }
+
+ [Fact]
+ public void VerifyConfigure_TracesPerSecond_ViaJson()
+ {
+ var appSettings = @"{""AzureMonitor"":{
+ ""ConnectionString"" : ""testJsonValue"",
+ ""DisableOfflineStorage"" : ""true"",
+ ""TracesPerSecond"" : 6.0,
+ ""StorageDirectory"" : ""testJsonValue"",
+ ""EnableTraceBasedLogsSampler"" : ""true""
+ }}";
+
+ var configuration = new ConfigurationBuilder()
+ .AddJsonStream(new MemoryStream(Encoding.UTF8.GetBytes(appSettings)))
+ .Build();
+
+ var defaultAzureMonitorOptions = new DefaultAzureMonitorOptions(configuration);
+
+ var azureMonitorOptions = new AzureMonitorOptions();
+
+ defaultAzureMonitorOptions.Configure(azureMonitorOptions);
+
+ Assert.Equal("testJsonValue", azureMonitorOptions.ConnectionString);
+ Assert.True(azureMonitorOptions.DisableOfflineStorage);
+ Assert.Equal(1.0F, azureMonitorOptions.SamplingRatio);
+ Assert.Equal(6.0, azureMonitorOptions.TracesPerSecond);
Assert.Equal("testJsonValue", azureMonitorOptions.StorageDirectory);
}
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/AspNetCoreInstrumentationTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/AspNetCoreInstrumentationTests.cs
index b5301b7ab0bc..ce125ac1f085 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/AspNetCoreInstrumentationTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/AspNetCoreInstrumentationTests.cs
@@ -71,6 +71,8 @@ public void AspNetCoreRequestsAreCapturedCorrectly(string path, string? queryStr
{
x.EnableLiveMetrics = false;
x.ConnectionString = testConnectionString;
+ x.SamplingRatio = 1.0f; // Ensure 100% sampling for tests
+ x.TracesPerSecond = null; // Disable rate limited sampler
})
.WithTracing(x => x.AddInMemoryExporter(activities))
// Custom resources must be added AFTER AzureMonitor to override the included ResourceDetectors.
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/HttpClientInstrumentationTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/HttpClientInstrumentationTests.cs
index bc3d74547fbc..077a18d9c9dd 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/HttpClientInstrumentationTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/HttpClientInstrumentationTests.cs
@@ -58,7 +58,12 @@ public async Task HttpRequestsAreCapturedCorrectly(string? queryString, int expe
var serviceCollection = new ServiceCollection();
serviceCollection.AddOpenTelemetry()
- .UseAzureMonitor(x => x.ConnectionString = testConnectionString)
+ .UseAzureMonitor(x =>
+ {
+ x.ConnectionString = testConnectionString;
+ x.SamplingRatio = 1.0f; // Ensure 100% sampling for tests
+ x.TracesPerSecond = null; // Disable rate limited sampler
+ })
.WithTracing(x => x.AddInMemoryExporter(activities))
// Custom resources must be added AFTER AzureMonitor to override the included ResourceDetectors.
.ConfigureResource(x => x.AddAttributes(SharedTestVars.TestResourceAttributes));
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/SqlClientInstrumentationTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/SqlClientInstrumentationTests.cs
index 21cb43fff8aa..8cc2dc0d346d 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/SqlClientInstrumentationTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/E2ETests/SqlClientInstrumentationTests.cs
@@ -72,7 +72,12 @@ public async Task SqlClientErrorsAreCollectedSuccessfully(
var activities = new List();
var serviceCollection = new ServiceCollection();
serviceCollection.AddOpenTelemetry()
- .UseAzureMonitor(x => x.ConnectionString = testConnectionString)
+ .UseAzureMonitor(x =>
+ {
+ x.ConnectionString = testConnectionString;
+ x.SamplingRatio = 1.0f; // Ensure 100% sampling for tests
+ x.TracesPerSecond = null; // Disable rate limiting sampler
+ })
.WithTracing(x => x.AddInMemoryExporter(activities))
// Custom resources must be added AFTER AzureMonitor to override the included ResourceDetectors.
.ConfigureResource(x => x.AddAttributes(SharedTestVars.TestResourceAttributes));
@@ -172,7 +177,12 @@ public async Task SqlClientCallsAreCollectedSuccessfully(
var activities = new List();
var serviceCollection = new ServiceCollection();
serviceCollection.AddOpenTelemetry()
- .UseAzureMonitor(x => x.ConnectionString = testConnectionString)
+ .UseAzureMonitor(x =>
+ {
+ x.ConnectionString = testConnectionString;
+ x.SamplingRatio = 1.0f; // Ensure 100% sampling for tests
+ x.TracesPerSecond = null; // Disable rate limited sampler
+ })
.WithTracing(x => x.AddInMemoryExporter(activities))
// Custom resources must be added AFTER AzureMonitor to override the included ResourceDetectors.
.ConfigureResource(x => x.AddAttributes(SharedTestVars.TestResourceAttributes));
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/InitializationTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/InitializationTests.cs
index f8e969532cbd..fce82c6ee220 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/InitializationTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/tests/Azure.Monitor.OpenTelemetry.AspNetCore.Tests/InitializationTests.cs
@@ -300,7 +300,8 @@ public static void EvaluateTracerProvider(IServiceProvider serviceProvider, bool
Assert.Equal(expectedProfilingSessionTraceProcessor, variables.foundProfilingSessionTraceProcessor);
// Validate Sampler
- EvaluationHelper.EvaluateTracerProviderSampler(serviceProvider, false);
+ // The default TracesPerSecond is 5.0, so we expect RateLimitedSampler by default
+ EvaluationHelper.EvaluateTracerProviderSampler(serviceProvider, true);
// Validate Instrumentations
var instrumentationsProperty = tracerProvider.GetType().GetProperty("Instrumentations", BindingFlags.NonPublic | BindingFlags.Instance);
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/CHANGELOG.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/CHANGELOG.md
index 119befa383e6..0e9c365b9ef3 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/CHANGELOG.md
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/CHANGELOG.md
@@ -5,6 +5,27 @@
### Features Added
### Breaking Changes
+* **Default Sampler Changed**: The default sampling behavior has been changed from
+ `ApplicationInsightsSampler` with 100% sampling (all traces sampled) to
+ `RateLimitedSampler` with 5.0 traces per second. This change significantly
+ reduces telemetry volume for high-traffic applications and provides better
+ cost optimization out of the box.
+ **Impact**: Applications with more than 5 requests per second will see fewer
+ 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()
+ .UseAzureMonitorExporter(options =>
+ {
+ options.SamplingRatio = 1.0f;
+ options.TracesPerSecond = null;
+ });
+ // Option 2: Use environment variables
+ // OTEL_TRACES_SAMPLER=microsoft.fixed_percentage
+ // OTEL_TRACES_SAMPLER_ARG=1.0
+ ```
### Bugs Fixed
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md
index eabf983c16ed..6464b15bfc34 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md
@@ -150,6 +150,38 @@ Some key concepts for OpenTelemetry include:
- [Sampling](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/sdk.md#sampling):
Sampling is a mechanism to control the noise and overhead introduced by OpenTelemetry by reducing the number of samples of traces collected and sent to the backend.
+ **Default Sampling**: By default, the Azure Monitor Exporter uses `RateLimitedSampler` with a rate of 5.0 traces per second. This provides cost-effective telemetry collection for most applications. To change the sampling behavior:
+
+ - **For rate-limited sampling**: Set `TracesPerSecond` in `AzureMonitorExporterOptions`:
+
+ ```csharp
+ .AddAzureMonitorTraceExporter(options => {
+ options.TracesPerSecond = 10.0; // Sample 10 traces per second
+ })
+ ```
+
+ - **For percentage-based sampling**: Set `SamplingRatio` and clear `TracesPerSecond`:
+
+ ```csharp
+ .AddAzureMonitorTraceExporter(options => {
+ options.SamplingRatio = 0.5f; // Sample 50% of traces
+ options.TracesPerSecond = null;
+ })
+ ```
+
+ - **Via environment variables**:
+
+ ```
+ OTEL_TRACES_SAMPLER=microsoft.rate_limited
+ OTEL_TRACES_SAMPLER_ARG=10
+ ```
+
+ or
+
+ ```
+ OTEL_TRACES_SAMPLER=microsoft.fixed_percentage
+ OTEL_TRACES_SAMPLER_ARG=0.5
+ ```
- [Metric Signal](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#metric-signal):
OpenTelemetry allows to record raw measurements or metrics with predefined aggregation and a set of attributes (dimensions).
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/AzureMonitorExporterOptions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/AzureMonitorExporterOptions.cs
index 5e8907575b19..935539a6ab61 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/AzureMonitorExporterOptions.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/AzureMonitorExporterOptions.cs
@@ -36,7 +36,6 @@ public class AzureMonitorExporterOptions : ClientOptions
///
/// Gets or sets the ratio of telemetry items to be sampled. The value must be between 0.0F and 1.0F, inclusive.
/// For example, specifying 0.4 means that 40% of traces are sampled and 60% are dropped.
- /// The default value is 1.0F, indicating that all telemetry items are sampled.
///
public float SamplingRatio { get; set; } = 1.0F;
@@ -45,7 +44,7 @@ public class AzureMonitorExporterOptions : ClientOptions
/// For example, specifying 0.5 means one request every two seconds.
/// When both TracesPerSecond and SamplingRatio are specified, TracesPerSecond takes precedence.
///
- public double? TracesPerSecond { get; set; }
+ public double? TracesPerSecond { get; set; } = 5.0;
///
/// The of the Azure Monitor ingestion API.
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/DefaultAzureMonitorExporterOptions.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/DefaultAzureMonitorExporterOptions.cs
index 8d2090868430..8165102f34a3 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/DefaultAzureMonitorExporterOptions.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/src/DefaultAzureMonitorExporterOptions.cs
@@ -31,7 +31,13 @@ public void Configure(AzureMonitorExporterOptions options)
{
if (_configuration != null)
{
- BindIConfigurationOptions(_configuration, options);
+ var azureMonitorSection = _configuration.GetSection(AzureMonitorExporterSectionFromConfig);
+ azureMonitorSection.Bind(options);
+ if (azureMonitorSection["TracesPerSecond"] == null && azureMonitorSection["SamplingRatio"] != null)
+ {
+ // This is so user does not have to explicitly set TracesPerSecond to null in config to use fixed-percentage sampling.
+ options.TracesPerSecond = null;
+ }
// IConfiguration can read from EnvironmentVariables or InMemoryCollection if configured to do so.
var connectionStringFromIConfig = _configuration[EnvironmentVariableConstants.APPLICATIONINSIGHTS_CONNECTION_STRING];
@@ -100,6 +106,7 @@ private static void ConfigureSamplingOptions(string? samplerType, string? sample
if (ratio >= 0.0 && ratio <= 1.0)
{
options.SamplingRatio = (float)ratio;
+ options.TracesPerSecond = null; // Explicitly set to null to use fixed-percentage sampling
}
else
{
diff --git a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/DefaultAzureMonitorExporterOptionsTests.cs b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/DefaultAzureMonitorExporterOptionsTests.cs
index 4ccc2bd238db..dfcb30acf94d 100644
--- a/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/DefaultAzureMonitorExporterOptionsTests.cs
+++ b/sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/tests/Azure.Monitor.OpenTelemetry.Exporter.Tests/DefaultAzureMonitorExporterOptionsTests.cs
@@ -110,7 +110,7 @@ public void Configure_Sampler_InvalidArgs_Ignored()
// Assert - defaults unchanged
Assert.Equal(1.0f, options.SamplingRatio);
- Assert.Null(options.TracesPerSecond);
+ Assert.Equal(5.0, options.TracesPerSecond); // Default value retained
// Now test invalid negative rate_limited
configValues = new List>
@@ -126,7 +126,7 @@ public void Configure_Sampler_InvalidArgs_Ignored()
defaultConfigurator.Configure(options);
// Assert
- Assert.Null(options.TracesPerSecond);
+ Assert.Equal(5.0, options.TracesPerSecond); // Default value retained
Assert.Equal(1.0f, options.SamplingRatio);
}
finally
@@ -203,5 +203,55 @@ public void Configure_Sampler_EnvironmentVariable_Overrides_IConfiguration()
Environment.SetEnvironmentVariable("OTEL_TRACES_SAMPLER_ARG", prevSamplerArg);
}
}
+
+ [Fact]
+ public void Configure_SamplingRatio_ViaJson_WithoutTracesPerSecond_SetsTracesPerSecondToNull_And_SetsSamplingRatio()
+ {
+ // Arrange - simulate appsettings.json with only SamplingRatio set (using InMemoryCollection with section key format)
+ var configValues = new List>
+ {
+ new("AzureMonitorExporter:ConnectionString", "testConnectionString"),
+ new("AzureMonitorExporter:SamplingRatio", "0.5"),
+ };
+
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(configValues)
+ .Build();
+
+ var defaultConfigurator = new DefaultAzureMonitorExporterOptions(configuration);
+ var options = new AzureMonitorExporterOptions();
+
+ // Act
+ defaultConfigurator.Configure(options);
+
+ // Assert
+ Assert.Equal(0.5f, options.SamplingRatio);
+ Assert.Null(options.TracesPerSecond);
+ }
+
+ [Fact]
+ public void Configure_TracesPerSecond_ViaJson_WithoutSamplingRatio_SetsTracesPerSecond()
+ {
+ // Arrange - simulate appsettings.json with only TracesPerSecond set (using InMemoryCollection with section key format)
+ var configValues = new List>
+ {
+ new("AzureMonitorExporter:ConnectionString", "testConnectionString"),
+ new("AzureMonitorExporter:TracesPerSecond", "10"),
+ };
+
+ var configuration = new ConfigurationBuilder()
+ .AddInMemoryCollection(configValues)
+ .Build();
+
+ var defaultConfigurator = new DefaultAzureMonitorExporterOptions(configuration);
+ var options = new AzureMonitorExporterOptions();
+
+ // Act
+ defaultConfigurator.Configure(options);
+
+ // Assert
+ Assert.Equal(1.0f, options.SamplingRatio); // default unchanged
+ Assert.Equal(10d, options.TracesPerSecond);
+ }
}
}