Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 32 additions & 3 deletions sdk/monitor/Azure.Monitor.OpenTelemetry.AspNetCore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ public class AzureMonitorOptions : ClientOptions
/// <summary>
/// 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.
/// </summary>
public float SamplingRatio { get; set; } = 1.0F;

Expand All @@ -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.
/// </summary>
public double? TracesPerSecond { get; set; }
public double? TracesPerSecond { get; set; } = 5.0;

/// <summary>
/// Override the default directory for offline storage.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<KeyValuePair<string, string?>>
Expand All @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ public async Task SqlClientErrorsAreCollectedSuccessfully(
var activities = new List<Activity>();
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));
Expand Down Expand Up @@ -172,7 +177,12 @@ public async Task SqlClientCallsAreCollectedSuccessfully(
var activities = new List<Activity>();
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));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
21 changes: 21 additions & 0 deletions sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
32 changes: 32 additions & 0 deletions sdk/monitor/Azure.Monitor.OpenTelemetry.Exporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ public class AzureMonitorExporterOptions : ClientOptions
/// <summary>
/// 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.
/// </summary>
public float SamplingRatio { get; set; } = 1.0F;

Expand All @@ -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.
/// </summary>
public double? TracesPerSecond { get; set; }
public double? TracesPerSecond { get; set; } = 5.0;

/// <summary>
/// The <see cref="ServiceVersion"/> of the Azure Monitor ingestion API.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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
{
Expand Down
Loading
Loading