Skip to content

Commit

Permalink
Update README.md for Polly.Extensions wtih telemetry info (#1401)
Browse files Browse the repository at this point in the history
  • Loading branch information
martintmk committed Jul 13, 2023
1 parent 58b1ffe commit b3ffbaf
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 13 deletions.
7 changes: 7 additions & 0 deletions src/Polly.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,10 @@ new ResilienceStrategyBuilder()
## Registering Custom Callbacks

When setting the delegates, ensure to respect the `ResilienceContext.IsSynchronous` property's value and execute your delegates synchronously for synchronous executions. In addition, use the `ResilienceContext.ContinueOnCapturedContext` property when your user code uses execution with synchronization context (for example, asynchronous calls in UI applications, such as in Windows Forms or WPF applications).

## Telemetry

Each individual resilience strategy can emit telemetry by using the [`ResilienceStrategyTelemetry`](Telemetry/ResilienceStrategyTelemetry.cs) API. Polly wraps the arguments as [`TelemetryEventArguments`](Telemetry/TelemetryEventArguments.cs) and emits them using `DiagnosticSource`.
To consume the telemetry, Polly adopters needs to assign an instance of `DiagnosticSource` to `ResilienceStrategyBuilder.DiagnosticSource` and consume `TelemetryEventArguments`.

For common use-cases, it is anticipated that Polly users would leverage `Polly.Extensions`. This allows all of the aforementioned functionalities by invoking the `ResilienceStrategyBuilder.ConfigureTelemetry(...)` extension method. `ConfigureTelemetry` processes `TelemetryEventArguments` and generates logs and metrics from it.
145 changes: 134 additions & 11 deletions src/Polly.Extensions/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
# About Polly.Hosting
# Polly.Extensions Overview

The `Polly.Hosting` enables the following features:
`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. Note that telemetry is enabled by default when utilizing the `AddResilienceStrategy` extension method.


- Integrates Polly with the standard `IServiceCollection` Dependency Injection (DI) container.
- Implements `ResilienceTelemetryFactory` that adds [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 using the DI extension points.

Example:
Below is an example illustrating these capabilities:

``` csharp
var services = new ServiceCollection();

// Define your strategy
// Define a strategy
services.AddResilienceStrategy(
"my-key",
context => context.Builder.AddTimeout(TimeSpan.FromSeconds(10)));
context => context.Builder.AddTimeout(TimeSpan.FromSeconds(10)));

// Define your strategy using custom options
// Define a strategy with custom options
services.AddResilienceStrategy(
"my-timeout",
context =>
Expand All @@ -25,9 +21,136 @@ services.AddResilienceStrategy(
context.Builder.AddTimeout(myOptions.Timeout);
});

// Use your strategy
// Utilize the strategy
var serviceProvider = services.BuildServiceProvider();
var strategyProvider = serviceProvider.GetRequiredService<ResilienceStrategyProvider<string>>();
var resilienceStrategy = strategyProvider.Get("my-key");
```

## Telemetry Features

Upon invoking the `ConfigureTelemetry` extension method, Polly begins to emit logs and metrics. Here's an example:

``` csharp
var telemetryOptions = new TelemetryOptions();

// Configure logging
telemetryOptions.LoggerFactory = LoggerFactory.Create(builder => builder.AddConsole());

// Configure enrichers
telemetryOptions.Enrichers.Add(context =>
{
context.Tags.Add(new("my-custom-tag", "custom-value"));
});

// Manually handle the event
telemetryOptions.OnTelemetryEvent = args =>
{
Console.WriteLine($"Telemetry event occurred: {args.Event.EventName}");
});

var builder = new ResilienceStrategyBuilder()
.AddTimeout(TimeSpan.FromSeconds(1))
.ConfigureTelemetry(telemetryOptions) // This method enables telemetry in the builder
.Build();
```

Alternatively, you can use the `AddResilienceStrategy` extension which automatically adds telemetry:

``` csharp
var serviceCollection = new ServiceCollection()
.AddLogging(builder => builder.AddConsole())
.AddResilienceStrategy("my-strategy", builder => builder.AddTimeout(TimeSpan.FromSeconds(1)))
// Configure the default settings for TelemetryOptions
.Configure<TelemetryOptions>(options =>
{
// Configure enrichers
options.Enrichers.Add(context => context.Tags.Add(new("my-custom-tag", "custom-value")));

// Manually handle the event
options.OnTelemetryEvent = args =>
{
Console.WriteLine($"Telemetry event occurred: {args.Event.EventName}");
};
});
```

### Emitted Metrics

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.

#### resilience-events

- Type: *Counter*
- Description: Emitted upon the occurrence of a resilience event.

Dimensions:

|Name|Description|
|---| ---|
|`event-name`| The name of the emitted event.|
|`event-severity`| The severity of the event (`Debug`, `Information`, `Warning`, `Error`, `Critical`).|
|`builder-name`| The name of the builder corresponding to the resilience strategy.|
|`builder-instance`| The instance name of the builder corresponding to the resilience strategy.|
|`strategy-name`| The name of the strategy generating this event.|
|`strategy-type`| The type of the strategy generating this event.|
|`operation-key`| The operation key associated with the call site. |
|`result-type`| The result type (`string`, `HttpResponseMessage`). |
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |

#### execution-attempt-duration

- Type: *Histogram*
- Unit: *milliseconds*
- Description: Tracks the duration of execution attempts, produced by `Retry` and `Hedging` resilience strategies.

Dimensions:

|Name|Description|
|---| ---|
|`event-name`| The name of the emitted event.|
|`event-severity`| The severity of the event (`Debug`, `Information`, `Warning`, `Error`, `Critical`).|
|`builder-name`| The name of the builder corresponding to the resilience strategy.|
|`builder-instance`| The instance name of the builder corresponding to the resilience strategy.|
|`strategy-name`| The name of the strategy generating this event.|
|`strategy-type`| The type of the strategy generating this event.|
|`operation-key`| The operation key associated with the call site. |
|`result-type`| The result type (`string`, `HttpResponseMessage`). |
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
|`attempt-number`| The execution attempt number, starting at 0 (0, 1, 2). |
|`attempt-handled`| Indicates if the execution outcome was handled. A handled outcome indicates execution failure and the need for retry (`true`, `false`). |

#### strategy-execution-duration

- Type: *Histogram*
- Unit: *milliseconds*
- Description: Measures the duration and results of resilience strategy executions.

Dimensions:

|Name|Description|
|---| ---|
|`builder-name`| The name of the builder corresponding to the resilience strategy.|
|`builder-instance`| The instance name of the builder corresponding to the resilience strategy.|
|`operation-key`| The operation key associated with the call site. |
|`result-type`| The result type (`string`, `HttpResponseMessage`). |
|`exception-name`| The full name of the exception assigned to the execution result (`System.InvalidOperationException`). |
|`execution-health`| Indicates whether the execution was healthy or not (`Healthy`, `Unhealthy`). |

### Logs

Logs are registered under the `Polly` logger name. Here are some examples of the logs:

``` text
// This log is recorded whenever a resilience event occurs. EventId = 0
Resilience event occurred. EventName: '{EventName}', Source: '{BuilderName}[{BuilderInstance}]/{StrategyType}[{StrategyName}]', Operation Key: '{OperationKey}', Result: '{Result}'
// This log is recorded when a resilience strategy begins executing. EventId = 1
Resilience strategy executing. Source: '{BuilderName}[{BuilderInstance}]', Operation Key: '{OperationKey}', Result Type: '{ResultType}'
// This log is recorded when a resilience strategy finishes execution. EventId = 2
Resilience strategy executed. Source: '{BuilderName}[{BuilderInstance}]', Operation Key: '{OperationKey}', Result Type: '{ResultType}', Result: '{Result}', Execution Health: '{ExecutionHealth}', Execution Time: {ExecutionTime}ms
// This log is recorded upon the completion of every execution attempt. EventId = 3
Execution attempt. Source: '{BuilderName}[{BuilderInstance}]/{StrategyType}[{StrategyName}]', Operation Key: '{OperationKey}', Result: '{Result}', Handled: '{Handled}', Attempt: '{Attempt}', Execution Time: '{ExecutionTimeMs}'
```
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal sealed class TelemetryResilienceStrategy : ResilienceStrategy
ExecutionDuration = ResilienceTelemetryDiagnosticSource.Meter.CreateHistogram<double>(
"strategy-execution-duration",
unit: "ms",
description: "The execution duration and execution result of resilience strategies.");
description: "The execution duration and execution results of resilience strategies.");
}

public Histogram<double> ExecutionDuration { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public void Ctor_Ok()
var duration = CreateStrategy().ExecutionDuration;

duration.Unit.Should().Be("ms");
duration.Description.Should().Be("The execution duration and execution result of resilience strategies.");
duration.Description.Should().Be("The execution duration and execution results of resilience strategies.");
}

[InlineData(true)]
Expand Down

0 comments on commit b3ffbaf

Please sign in to comment.