Skip to content

Commit 7f04671

Browse files
committed
[Docs] Telemetry page
1 parent 3f1b435 commit 7f04671

3 files changed

Lines changed: 158 additions & 145 deletions

File tree

docs/telemetry.md

Lines changed: 154 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,156 @@
11
# Telemetry
22

3-
🚧 This documentation is being written as part of the Polly v8 release.
3+
Starting with version 8, Polly provides telemetry for all built-in resilience strategies.
4+
5+
## Usage
6+
7+
To enable telemetry in Polly, add the `Polly.Extensions` package to your project:
8+
9+
```sh
10+
dotnet add package Polly.Extensions
11+
```
12+
13+
Afterwards, you can use the `ConfigureTelemetry(...)` extension method on the `ResiliencePipelineBuilder`:
14+
15+
<!-- snippet: configure-telemetry -->
16+
```cs
17+
var telemetryOptions = new TelemetryOptions
18+
{
19+
// Configure logging
20+
LoggerFactory = LoggerFactory.Create(builder => builder.AddConsole())
21+
};
22+
23+
// Configure enrichers
24+
telemetryOptions.MeteringEnrichers.Add(new MyMeteringEnricher());
25+
26+
// Configure telemetry listeners
27+
telemetryOptions.TelemetryListeners.Add(new MyTelemetryListener());
28+
29+
var builder = new ResiliencePipelineBuilder()
30+
.AddTimeout(TimeSpan.FromSeconds(1))
31+
.ConfigureTelemetry(telemetryOptions) // This method enables telemetry in the builder
32+
.Build();
33+
```
34+
<!-- endSnippet -->
35+
36+
The `MyTelemetryListener` and `MyMeteringEnricher` is implemented as:
37+
38+
<!-- snippet: telemetry-listeners -->
39+
```cs
40+
internal class MyTelemetryListener : TelemetryListener
41+
{
42+
public override void Write<TResult, TArgs>(in TelemetryEventArguments<TResult, TArgs> args)
43+
{
44+
Console.WriteLine($"Telemetry event occurred: {args.Event.EventName}");
45+
}
46+
}
47+
48+
internal class MyMeteringEnricher : MeteringEnricher
49+
{
50+
public override void Enrich<TResult, TArgs>(in EnrichmentContext<TResult, TArgs> context)
51+
{
52+
context.Tags.Add(new("my-custom-tag", "custom-value"));
53+
}
54+
}
55+
```
56+
<!-- endSnippet -->
57+
58+
Alternatively, you can use the `AddResiliencePipeline(...)` extension method which automatically enables telemetry for defined pipeline:
59+
60+
<!-- snippet: add-resilience-pipeline-with-telemetry -->
61+
```cs
62+
var serviceCollection = new ServiceCollection()
63+
.AddLogging(builder => builder.AddConsole())
64+
.AddResiliencePipeline("my-strategy", builder => builder.AddTimeout(TimeSpan.FromSeconds(1)))
65+
.Configure<TelemetryOptions>(options =>
66+
{
67+
// Configure enrichers
68+
options.MeteringEnrichers.Add(new MyMeteringEnricher());
69+
70+
// Configure telemetry listeners
71+
options.TelemetryListeners.Add(new MyTelemetryListener());
72+
});
73+
```
74+
<!-- endSnippet -->
75+
76+
## Metrics
77+
78+
The emitted metrics are emitted under the `Polly` meter name. The subsequent sections provide insights into the metrics produced by Polly. Please note that any custom enriched dimensions are not depicted in the following tables.
79+
80+
### resilience-events
81+
82+
- Type: *Counter*
83+
- Description: Emitted upon the occurrence of a resilience event.
84+
85+
Dimensions:
86+
87+
|Name|Description|
88+
|---| ---|
89+
|`event-name`| The name of the emitted event.|
90+
|`event-severity`| The severity of the event (`Debug`, `Information`, `Warning`, `Error`, `Critical`).|
91+
|`pipeline-name`| The name of the pipeline corresponding to the resilience pipeline.|
92+
|`pipeline-instance`| The instance name of the pipeline corresponding to the resilience pipeline.|
93+
|`strategy-name`| The name of the strategy generating this event.|
94+
|`operation-key`| The operation key associated with the call site. |
95+
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
96+
97+
### execution-attempt-duration
98+
99+
- Type: *Histogram*
100+
- Unit: *milliseconds*
101+
- Description: Tracks the duration of execution attempts, produced by `Retry` and `Hedging` resilience strategies.
102+
103+
Dimensions:
104+
105+
|Name|Description|
106+
|---| ---|
107+
|`event-name`| The name of the emitted event.|
108+
|`event-severity`| The severity of the event (`Debug`, `Information`, `Warning`, `Error`, `Critical`).|
109+
|`pipeline-name`| The name of the pipeline corresponding to the resilience pipeline.|
110+
|`pipeline-instance`| The instance name of the pipeline corresponding to the resilience pipeline.|
111+
|`strategy-name`| The name of the strategy generating this event.|
112+
|`operation-key`| The operation key associated with the call site. |
113+
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
114+
|`attempt-number`| The execution attempt number, starting at 0 (0, 1, 2). |
115+
|`attempt-handled`| Indicates if the execution outcome was handled. A handled outcome indicates execution failure and the need for retry (`true`, `false`). |
116+
117+
### pipeline-execution-duration
118+
119+
- Type: *Histogram*
120+
- Unit: *milliseconds*
121+
- Description: Measures the duration and results of resilience pipelines.
122+
123+
Dimensions:
124+
125+
|Name|Description|
126+
|---| ---|
127+
|`pipeline-name`| The name of the pipeline corresponding to the resilience pipeline.|
128+
|`pipeline-instance`| The instance name of the pipeline corresponding to the resilience pipeline.|
129+
|`operation-key`| The operation key associated with the call site. |
130+
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
131+
132+
## Logs
133+
134+
Logs are registered under the `Polly` logger name. Here are some examples of the logs:
135+
136+
``` text
137+
// This log is recorded whenever a resilience event occurs. EventId = 0
138+
Resilience event occurred. EventName: '{EventName}', Source: '{PipelineName}/{PipelineInstance}/{StrategyName}', Operation Key: '{OperationKey}', Result: '{Result}'
139+
140+
// This log is recorded when a resilience pipeline begins executing. EventId = 1
141+
Resilience pipeline executing. Source: '{PipelineName}/{PipelineInstance}', Operation Key: '{OperationKey}'
142+
143+
// This log is recorded when a resilience pipeline finishes execution. EventId = 2
144+
Resilience pipeline executed. Source: '{PipelineName}/{PipelineInstance}', Operation Key: '{OperationKey}', Result: '{Result}', Execution Health: '{ExecutionHealth}', Execution Time: {ExecutionTime}ms
145+
146+
// This log is recorded upon the completion of every execution attempt. EventId = 3
147+
Execution attempt. Source: '{PipelineName}/{PipelineInstance}/{StrategyName}', Operation Key: '{OperationKey}', Result: '{Result}', Handled: '{Handled}', Attempt: '{Attempt}', Execution Time: '{ExecutionTimeMs}'
148+
```
149+
150+
## Emitting telemetry events
151+
152+
Each resilience strategy can generate telemetry data through the [`ResilienceStrategyTelemetry`](../src/Polly.Core/Telemetry/ResilienceStrategyTelemetry.cs) API. Polly encapsulates event details as [`TelemetryEventArguments`](../src/Polly.Core/Telemetry/TelemetryEventArguments.cs) and emits them via `TelemetryListener`.
153+
154+
To leverage this telemetry data, users should assign a `TelemetryListener` instance to `ResiliencePipelineBuilder.TelemetryListener` and then consume the `TelemetryEventArguments`.
155+
156+
For common scenarios, it is expected that users would make use of `Polly.Extensions`. This extension enables telemetry configuration through the `ResiliencePipelineBuilder.ConfigureTelemetry(...)` method, which processes `TelemetryEventArguments` to generate logs and metrics.

src/Polly.Core/README.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ Recommended signatures for these delegates are:
189189
- `Func<Args<TResult>, ValueTask<TValue>>` (Reactive)
190190
- `Func<Args, ValueTask<TValue>>` (Proactive)
191191

192-
193192
These delegates accept either `Args` or `Args<TResult>` arguments, which encapsulate event information. Note that all these delegates are asynchronous and return a `ValueTask`.
194193

195194
> [!NOTE]
@@ -248,11 +247,3 @@ new ResiliencePipelineBuilder<string>()
248247
.Build();
249248
```
250249
<!-- endSnippet -->
251-
252-
## Telemetry
253-
254-
Each resilience strategy can generate telemetry data through the [`ResiliencePipelineTelemetry`](Telemetry/ResiliencePipelineTelemetry.cs) API. Polly encapsulates event details as [`TelemetryEventArguments`](Telemetry/TelemetryEventArguments.cs) and emits them via `TelemetryListener`.
255-
256-
To leverage this telemetry data, users should assign a `TelemetryListener` instance to `ResiliencePipelineBuilder.TelemetryListener` and then consume the `TelemetryEventArguments`.
257-
258-
For common scenarios, it is expected that users would make use of `Polly.Extensions`. This extension enables telemetry configuration through the `ResiliencePipelineBuilder.ConfigureTelemetry(...)` method, which processes `TelemetryEventArguments` to generate logs and metrics.

src/Polly.Extensions/README.md

Lines changed: 4 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Polly.Extensions Overview
22

3-
`Polly.Extensions` provides a set of features that streamline the integration of Polly with the standard `IServiceCollection` Dependency Injection (DI) container. It further enhances telemetry by exposing a `ConfigureTelemetry` extension method that enables [logging](https://learn.microsoft.com/dotnet/core/extensions/logging?tabs=command-line) and [metering](https://learn.microsoft.com/dotnet/core/diagnostics/metrics) for all strategies created via DI extension points.
3+
`Polly.Extensions` provides a set of features that streamline the integration of Polly with the standard `IServiceCollection` Dependency Injection (DI) container. It further enhances telemetry by exposing a `ConfigureTelemetry` extension method that enables [logging](https://learn.microsoft.com/dotnet/core/extensions/logging?tabs=command-line) and [metering](https://learn.microsoft.com/dotnet/core/diagnostics/metrics) for all strategies created via DI extension points.
44

55
Below is an example illustrating the usage of `AddResiliencePipeline` extension method:
66

@@ -36,141 +36,10 @@ await pipeline.ExecuteAsync(async cancellation => await Task.Delay(100, cancella
3636
<!-- endSnippet -->
3737

3838
> [!NOTE]
39-
> Telemetry is enabled by default when utilizing the `AddResiliencePipeline` extension method.
39+
> Telemetry is enabled by default when utilizing the `AddResiliencePipeline(...)` extension method.
4040
4141
## Telemetry Features
4242

43-
Upon invoking the `ConfigureTelemetry` extension method, Polly begins to emit logs and metrics. Here's an example:
43+
This project implements the `TelemetryListener` and uses it to bridge the Polly-native events into logs and metrics.
4444

45-
<!-- snippet: configure-telemetry -->
46-
```cs
47-
var telemetryOptions = new TelemetryOptions
48-
{
49-
// Configure logging
50-
LoggerFactory = LoggerFactory.Create(builder => builder.AddConsole())
51-
};
52-
53-
// Configure enrichers
54-
telemetryOptions.MeteringEnrichers.Add(new MyMeteringEnricher());
55-
56-
// Configure telemetry listeners
57-
telemetryOptions.TelemetryListeners.Add(new MyTelemetryListener());
58-
59-
var builder = new ResiliencePipelineBuilder()
60-
.AddTimeout(TimeSpan.FromSeconds(1))
61-
.ConfigureTelemetry(telemetryOptions) // This method enables telemetry in the builder
62-
.Build();
63-
```
64-
<!-- endSnippet -->
65-
66-
<!-- snippet: telemetry-listeners -->
67-
```cs
68-
internal class MyTelemetryListener : TelemetryListener
69-
{
70-
public override void Write<TResult, TArgs>(in TelemetryEventArguments<TResult, TArgs> args)
71-
{
72-
Console.WriteLine($"Telemetry event occurred: {args.Event.EventName}");
73-
}
74-
}
75-
76-
internal class MyMeteringEnricher : MeteringEnricher
77-
{
78-
public override void Enrich<TResult, TArgs>(in EnrichmentContext<TResult, TArgs> context)
79-
{
80-
context.Tags.Add(new("my-custom-tag", "custom-value"));
81-
}
82-
}
83-
```
84-
<!-- endSnippet -->
85-
86-
Alternatively, you can use the `AddResiliencePipeline` extension which automatically adds telemetry:
87-
88-
<!-- snippet: add-resilience-pipeline-with-telemetry -->
89-
```cs
90-
var serviceCollection = new ServiceCollection()
91-
.AddLogging(builder => builder.AddConsole())
92-
.AddResiliencePipeline("my-strategy", builder => builder.AddTimeout(TimeSpan.FromSeconds(1)))
93-
.Configure<TelemetryOptions>(options =>
94-
{
95-
// Configure enrichers
96-
options.MeteringEnrichers.Add(new MyMeteringEnricher());
97-
98-
// Configure telemetry listeners
99-
options.TelemetryListeners.Add(new MyTelemetryListener());
100-
});
101-
```
102-
<!-- endSnippet -->
103-
104-
### Emitted Metrics
105-
106-
The emitted metrics are emitted under the `Polly` meter name. The subsequent sections provide insights into the metrics produced by Polly. Please note that any custom enriched dimensions are not depicted in the following tables.
107-
108-
#### resilience-events
109-
110-
- Type: *Counter*
111-
- Description: Emitted upon the occurrence of a resilience event.
112-
113-
Dimensions:
114-
115-
|Name|Description|
116-
|---| ---|
117-
|`event-name`| The name of the emitted event.|
118-
|`event-severity`| The severity of the event (`Debug`, `Information`, `Warning`, `Error`, `Critical`).|
119-
|`pipeline-name`| The name of the pipeline corresponding to the resilience pipeline.|
120-
|`pipeline-instance`| The instance name of the pipeline corresponding to the resilience pipeline.|
121-
|`strategy-name`| The name of the strategy generating this event.|
122-
|`operation-key`| The operation key associated with the call site. |
123-
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
124-
125-
#### execution-attempt-duration
126-
127-
- Type: *Histogram*
128-
- Unit: *milliseconds*
129-
- Description: Tracks the duration of execution attempts, produced by `Retry` and `Hedging` resilience strategies.
130-
131-
Dimensions:
132-
133-
|Name|Description|
134-
|---| ---|
135-
|`event-name`| The name of the emitted event.|
136-
|`event-severity`| The severity of the event (`Debug`, `Information`, `Warning`, `Error`, `Critical`).|
137-
|`pipeline-name`| The name of the pipeline corresponding to the resilience pipeline.|
138-
|`pipeline-instance`| The instance name of the pipeline corresponding to the resilience pipeline.|
139-
|`strategy-name`| The name of the strategy generating this event.|
140-
|`operation-key`| The operation key associated with the call site. |
141-
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
142-
|`attempt-number`| The execution attempt number, starting at 0 (0, 1, 2). |
143-
|`attempt-handled`| Indicates if the execution outcome was handled. A handled outcome indicates execution failure and the need for retry (`true`, `false`). |
144-
145-
#### pipeline-execution-duration
146-
147-
- Type: *Histogram*
148-
- Unit: *milliseconds*
149-
- Description: Measures the duration and results of resilience pipelines.
150-
151-
Dimensions:
152-
153-
|Name|Description|
154-
|---| ---|
155-
|`pipeline-name`| The name of the pipeline corresponding to the resilience pipeline.|
156-
|`pipeline-instance`| The instance name of the pipeline corresponding to the resilience pipeline.|
157-
|`operation-key`| The operation key associated with the call site. |
158-
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
159-
160-
### Logs
161-
162-
Logs are registered under the `Polly` logger name. Here are some examples of the logs:
163-
164-
``` text
165-
// This log is recorded whenever a resilience event occurs. EventId = 0
166-
Resilience event occurred. EventName: '{EventName}', Source: '{PipelineName}/{PipelineInstance}/{StrategyName}', Operation Key: '{OperationKey}', Result: '{Result}'
167-
168-
// This log is recorded when a resilience pipeline begins executing. EventId = 1
169-
Resilience pipeline executing. Source: '{PipelineName}/{PipelineInstance}', Operation Key: '{OperationKey}'
170-
171-
// This log is recorded when a resilience pipeline finishes execution. EventId = 2
172-
Resilience pipeline executed. Source: '{PipelineName}/{PipelineInstance}', Operation Key: '{OperationKey}', Result: '{Result}', Execution Health: '{ExecutionHealth}', Execution Time: {ExecutionTime}ms
173-
174-
// This log is recorded upon the completion of every execution attempt. EventId = 3
175-
Execution attempt. Source: '{PipelineName}/{PipelineInstance}/{StrategyName}', Operation Key: '{OperationKey}', Result: '{Result}', Handled: '{Handled}', Attempt: '{Attempt}', Execution Time: '{ExecutionTimeMs}'
176-
```
45+
Explore [telemetry documentation](../../docs/telemetry.md) for more details.

0 commit comments

Comments
 (0)