OpenTelemetry instrumentation for Polly v8 resilience pipelines.
Emits distributed trace spans (Activity) and metrics for retry, circuit breaker, and timeout strategies — giving you full observability into your resilience layer.
Polly ships built-in logging and basic metrics via
ConfigureTelemetry(ILoggerFactory).
This package adds the missing piece: OpenTelemetry-native traces and enriched metrics.
dotnet add package PollyOpenTelemetry
services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddPollyInstrumentation() // register the "Polly" ActivitySource
.AddOtlpExporter())
.WithMetrics(metrics => metrics
.AddPollyInstrumentation() // register the "Polly" Meter
.AddOtlpExporter());var pipeline = new ResiliencePipelineBuilder()
.AddPollyOpenTelemetry() // ← one call enables both traces + metrics
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 3,
BackoffType = DelayBackoffType.Exponential,
})
.AddCircuitBreaker(new CircuitBreakerStrategyOptions
{
FailureRatio = 0.5,
MinimumThroughput = 10,
})
.AddTimeout(TimeSpan.FromSeconds(30))
.Build();services.AddResiliencePipeline("my-http-client", builder =>
{
builder
.AddPollyOpenTelemetry()
.AddRetry(new RetryStrategyOptions { MaxRetryAttempts = 3 })
.AddTimeout(TimeSpan.FromSeconds(30));
});| Activity name | When emitted |
|---|---|
polly.attempt |
Each individual execution attempt |
polly.retry |
Each retry decision |
polly.circuit_breaker.opened |
Circuit breaker transitions to open |
polly.circuit_breaker.closed |
Circuit breaker transitions to closed |
polly.circuit_breaker.half_opened |
Circuit breaker transitions to half-open |
polly.timeout |
Operation cancelled due to timeout |
| Tag | Value |
|---|---|
polly.pipeline.name |
ResiliencePipelineBuilder.Name |
polly.pipeline.instance_name |
ResiliencePipelineBuilder.InstanceName |
polly.strategy.name |
Name of the individual strategy |
polly.outcome |
success, failure, or unknown |
error.type |
Exception type (on failure) |
polly.attempt: polly.attempt.number, polly.attempt.handled
polly.retry: polly.attempt.number, polly.retry.delay_ms
polly.circuit_breaker.opened: polly.circuit_breaker.break_duration_ms, polly.circuit_breaker.is_manual
polly.timeout: polly.timeout_ms
| Metric name | Type | Unit | Description |
|---|---|---|---|
polly.attempt.duration |
Histogram | ms | Duration of each individual execution attempt |
polly.retry.count |
Counter | {attempt} |
Number of retry decisions made |
polly.circuit_breaker.open |
Counter | {open} |
Number of times circuit breaker opened |
polly.timeout.count |
Counter | {timeout} |
Number of operations cancelled due to timeout |
builder.AddPollyOpenTelemetry(options =>
{
options.EnableTracing = true; // default: true
options.EnableMetrics = true; // default: true
// Enrich activities with custom tags
options.EnrichActivity = (activity, resilienceEvent, source) =>
{
activity.SetTag("my.custom.tag", "value");
};
});AddPollyOpenTelemetry() is safe to combine with Polly's built-in ConfigureTelemetry(ILoggerFactory) — both listeners are composed automatically:
var pipeline = new ResiliencePipelineBuilder()
.ConfigureTelemetry(loggerFactory) // Polly structured logging + basic metrics
.AddPollyOpenTelemetry() // OpenTelemetry traces + enriched metrics
.AddRetry(...)
.Build();▶ polly.attempt [polly.pipeline.name=payment-api] [polly.attempt.number=0] [polly.outcome=failure]
✗ error.type=System.Net.Http.HttpRequestException
▶ polly.retry [polly.retry.delay_ms=200] [polly.attempt.number=0]
▶ polly.attempt [polly.pipeline.name=payment-api] [polly.attempt.number=1] [polly.outcome=success]
- .NET 8.0+
- Polly 8.x
- OpenTelemetry 1.x
This package is published to NuGet.org via GitHub Actions using NuGet trusted publishing — no API key secret is stored in the repository.
- On nuget.org, go to your package → Manage → Trusted Publishers → Add a publisher
- Choose GitHub Actions and enter:
- Owner:
Sweevo - Repository:
Polly-Contrib-OpenTelemetry - Workflow:
build.yml
- Owner:
- Push a
v*tag to trigger the publish workflow:git tag v1.0.0 git push --tags
The workflow requests a short-lived OIDC token from GitHub (audience api.nuget.org) and uses it as the push credential — no NUGET_API_KEY secret required.
If PollyOpenTelemetry improves your observability, consider supporting the project:
💼 Need .NET observability or resilience help? Visit solidqualitysolutions.com for consulting and architecture services.
| Package | Description |
|---|---|
| PollyChaos | Chaos engineering — inject faults & latency (Simmy for v8) |
| PollyMediatR | Polly v8 pipelines for MediatR request handlers |
| PollyEFCore | Polly v8 resilience for EF Core queries and SaveChanges |
| PollyBackoff | Backoff delay strategies |
| PollyHealthChecks | |
| PollyOpenAI | |
| PollyRedis | |
| PollySignalR | |
| PollyGrpc | Polly v8 resilience (retry, CB, timeout) for gRPC .NET clients via Interceptor |
| PollyKafka | Polly v8 resilience (retry, CB, timeout) for Confluent.Kafka producers and consumers |
| PollyAzureServiceBus | Polly v8 resilience (retry, CB, timeout) for Azure Service Bus senders and receivers |
| PollyCaching | Caching resilience strategy |
| PollyBulkhead | Bulkhead isolation |
| PollyRateLimiter | Rate limiting strategies |
| PollyRabbitMQ | Polly v8 resilience for RabbitMQ.Client channels |
MIT — Copyright © 2025 Justin Bannister