Skip to main content
net10.0.NETFramework4.6.2net8.0.NETStandard2.0

OpenTelemetry .NET SDK preview features and extensions.

Published
Oct 15, 2026
15d ago
Total Downloads
5.5M
5,528,334

Install

dotnet add package OpenTelemetry.Extensions --version 1.20.0-beta.1
ProductVersions
.NET
net10.0net8.0
.NET Standard
netstandard2.0
Other
.NETFramework4.6.2

README

OpenTelemetry .NET SDK preview features and extensions

Status
Stability Beta
Code Owners @mikegoldsmith

NuGet version badge NuGet download count badge codecov.io

Contains useful features and extensions to the OpenTelemetry .NET SDK that are not part of the official OpenTelemetry specification but might be added in the future.

Logging

AttachLogsToActivityEvent

Adds a log processor which will convert log messages into events and attach them to the currently running Activity.

AddBaggageProcessor

Adds a log processor which will copy baggage entries to log records. The method takes an optional predicate to filter the copied baggage entries based on the entry key. If no predicate is provided, all entries are copied.

Example of AddBaggageProcessor usage with a predicate:

var regex = new Regex("^allow", RegexOptions.Compiled);
using var loggerFactory = LoggerFactory.Create(builder => builder
.AddOpenTelemetry(options =>
{
    options.AddBaggageProcessor(regex.IsMatch);
    // other set up (exporters, processors)
})

Warning: The baggage key predicate is executed for every baggage entry for each log record. Do not use slow or intensive operations.

Traces

AutoFlushActivityProcessor

Processor that flushes its containing TracerProvider if an ended Activity matches a predicate. Note that this processor must be added after exporter related Activity processors.

Example of AutoFlushActivityProcessor usage:

public static TracerProviderBuilder AddMyExporter(this TracerProviderBuilder builder, MyExporterOptions options)
{
    return builder
        .AddProcessor(new BatchActivityExportProcessor(
                    new MyExporter(options),
                    options.BatchExportProcessorOptions.MaxQueueSize,
                    options.BatchExportProcessorOptions.ScheduledDelayMilliseconds,
                    options.BatchExportProcessorOptions.ExporterTimeoutMilliseconds,
                    options.BatchExportProcessorOptions.MaxExportBatchSize))
        .AddAutoFlushActivityProcessor(a => a.Parent == null && (a.Kind == ActivityKind.Server || a.Kind == ActivityKind.Consumer), 5000);
}

BaggageActivityProcessor

The BaggageActivityProcessor reads entries stored in Baggage from the current Baggage and adds the baggage keys and values to the Activity as tags (attributes) on start.

Add this activity processor to a tracer provider.

For example, to add all baggage entries to new activities:

var tracerProvider = Sdk.CreateTracerProviderBuilder()
    .AddBaggageActivityProcessor(BaggageActivityProcessor.AllowAllBaggageKeys)
    .Build();

Alternatively, you can select which baggage keys you want to copy using a custom predicate function.

For example, to only copy baggage entries where the key start with my-key using a custom function:

var tracerProvider = Sdk.CreateTracerProviderBuilder()
  .AddBaggageActivityProcessor((baggageKey) => baggageKey.StartWith("my-key", System.StringComparison.Ordinal))
  .Build();

For example, to only copy baggage entries where the key matches the regular expression ^my-key:

var baggageKeyRegex = new Regex("^mykey", RegexOptions.Compiled);
var tracerProvider = Sdk.CreateTracerProviderBuilder()
  .AddBaggageActivityProcessor((baggageKey) => baggageKeyRegex.IsMatch(baggageKey))
  .Build();

Warning: The baggage key predicate is executed for every baggage entry for each started activity. Do not use slow or intensive operations.

RateLimitingSampler

The rate limiting sampler is a sampler that will limit the number of samples to the specified rate per second. It is typically used in conjunction with the ParentBasedSampler to ensure that the rate limiting sampler is only applied to the root spans. When using the ParentBasedSampler, when an Activity creation request comes in without a sampling decision, it will delegate to the rate limiting sampler which will make a decision based on the rate limit, that way all spans in the trace will use the same sampling decision, and the rate will effectively become the number of traces per second, irrespective of the number of spans within each trace.

Example of RateLimitingSampler usage:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing.AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            // Add the rate limiting sampler with a limit of 3 traces per second
            .SetSampler(new ParentBasedSampler(new RateLimitingSampler(3)))
    });

ConsistentProbabilitySampler

The ConsistentProbabilitySampler samples a configured proportion of spans and records the sampling probability in the tracestate, following the OpenTelemetry probability sampling specification. Because all participants in a trace share the same source of randomness, their sampling decisions are consistent with one another.

Like the built-in TraceIdRatioBased sampler, it makes an independent decision, so combine it with a ParentBasedSampler to follow the parent's decision for non-root spans.

The shared randomness comes from the explicit randomness value (the rv sub-key of the ot tracestate entry) when one is present, and otherwise from the least-significant 56 bits of the TraceId. The sampler never creates or modifies an explicit randomness value, so every participant that observes the same context resolves the same randomness.

An example of ConsistentProbabilitySampler usage is shown below:

builder.Services.AddOpenTelemetry()
    .WithTracing(tracing =>
    {
        tracing.AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            // Sample approximately 10% of traces consistently
            .SetSampler(new ParentBasedSampler(new ConsistentProbabilitySampler(0.1)));
    });

W3CTraceState

W3CTraceState is an immutable, parsed view of a W3C tracestate header. It exposes the get, add, update and delete operations the OpenTelemetry tracing API specification defines for TraceState, which .NET otherwise surfaces only as the raw ActivityContext.TraceState string. Custom samplers and propagators that edit that string by hand have to re-implement the W3C mutation rules, and the obvious hand-rolled version gets several of them wrong.

Parsing always succeeds, a mutating operation that changes something returns a new instance, and neither throws: an operation that changes nothing, such as one naming an invalid key or value, hands back the receiver itself. A member that is malformed, or is a repeated key, is dropped as the header is parsed, so the state is always a valid tracestate. Valid members this instance did not generate are kept in place.

Use TryParse where a caller wants to know whether the header was valid; the out parameter holds the valid members either way.

Example of W3CTraceState usage in a custom sampler:

public override SamplingResult ShouldSample(in SamplingParameters samplingParameters)
{
    var traceState = W3CTraceState.Parse(samplingParameters.ParentContext.TraceState)
                                  .Set("mykey", "myvalue")
                                  .ToString();

    return new SamplingResult(SamplingDecision.RecordAndSample, traceState);
}

Changes from Previous Version

No structural changes between v1.19.1-beta.1 and v1.20.0-beta.1.

Adoption Assessment

A verified publisher signal is available. Assess fit from the package's supported frameworks, license and dependency graph rather than popularity alone.

This version is marked prerelease. Validate its API and upgrade path before production use.Compatibility metadata lists 4 target frameworks; confirm the exact target used by your application.

Related Guides & Workflows

Learn how to evaluate, integrate, or audit this package in your .NET project.