Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ResilienceStrategyBuilder.InstanceName and use it in telemetry #1392

Merged
merged 1 commit into from
Jul 10, 2023
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
8 changes: 4 additions & 4 deletions src/Polly.Core/Registry/ConfigureBuilderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ namespace Polly.Registry;
public class ConfigureBuilderContext<TKey>
where TKey : notnull
{
internal ConfigureBuilderContext(TKey strategyKey, string builderName, string strategyKeyString)
internal ConfigureBuilderContext(TKey strategyKey, string builderName, string? builderInstanceName)
{
StrategyKey = strategyKey;
BuilderName = builderName;
StrategyKeyString = strategyKeyString;
BuilderInstanceName = builderInstanceName;
}

/// <summary>
Expand All @@ -27,9 +27,9 @@ internal ConfigureBuilderContext(TKey strategyKey, string builderName, string st
public string BuilderName { get; }

/// <summary>
/// Gets the string representation of strategy key for the strategy being created.
/// Gets the instance name for the builder being used to create the strategy.
/// </summary>
public string StrategyKeyString { get; }
public string? BuilderInstanceName { get; }

internal Func<Func<CancellationToken>>? ReloadTokenProducer { get; private set; }

Expand Down
10 changes: 5 additions & 5 deletions src/Polly.Core/Registry/ResilienceStrategyRegistry.TResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ private sealed class GenericRegistry<TResult>
private readonly ConcurrentDictionary<TKey, Action<ResilienceStrategyBuilder<TResult>, ConfigureBuilderContext<TKey>>> _builders;
private readonly ConcurrentDictionary<TKey, ResilienceStrategy<TResult>> _strategies;

private readonly Func<TKey, string> _strategyKeyFormatter;
private readonly Func<TKey, string> _builderNameFormatter;
private readonly Func<TKey, string>? _instanceNameFormatter;

public GenericRegistry(
Func<ResilienceStrategyBuilder<TResult>> activator,
IEqualityComparer<TKey> builderComparer,
IEqualityComparer<TKey> strategyComparer,
Func<TKey, string> strategyKeyFormatter,
Func<TKey, string> builderNameFormatter)
Func<TKey, string> builderNameFormatter,
Func<TKey, string>? instanceNameFormatter)
{
_activator = activator;
_builders = new ConcurrentDictionary<TKey, Action<ResilienceStrategyBuilder<TResult>, ConfigureBuilderContext<TKey>>>(builderComparer);
_strategies = new ConcurrentDictionary<TKey, ResilienceStrategy<TResult>>(strategyComparer);
_strategyKeyFormatter = strategyKeyFormatter;
_builderNameFormatter = builderNameFormatter;
_instanceNameFormatter = instanceNameFormatter;
}

public bool TryAdd(TKey key, ResilienceStrategy<TResult> strategy) => _strategies.TryAdd(key, strategy);
Expand All @@ -51,7 +51,7 @@ public bool TryGet(TKey key, [NotNullWhen(true)] out ResilienceStrategy<TResult>

public ResilienceStrategy<TResult> GetOrAdd(TKey key, Action<ResilienceStrategyBuilder<TResult>, ConfigureBuilderContext<TKey>> configure)
{
var context = new ConfigureBuilderContext<TKey>(key, _builderNameFormatter(key), _strategyKeyFormatter(key));
var context = new ConfigureBuilderContext<TKey>(key, _builderNameFormatter(key), _instanceNameFormatter?.Invoke(key));

#if NETCOREAPP3_0_OR_GREATER
return _strategies.GetOrAdd(key, static (_, factory) =>
Expand Down
13 changes: 7 additions & 6 deletions src/Polly.Core/Registry/ResilienceStrategyRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public sealed partial class ResilienceStrategyRegistry<TKey> : ResilienceStrateg
private readonly ConcurrentDictionary<TKey, ResilienceStrategy> _strategies;
private readonly ConcurrentDictionary<Type, object> _genericRegistry = new();

private readonly Func<TKey, string> _strategyKeyFormatter;
private readonly Func<TKey, string>? _instanceNameFormatter;
private readonly Func<TKey, string> _builderNameFormatter;
private readonly IEqualityComparer<TKey> _builderComparer;
private readonly IEqualityComparer<TKey> _strategyComparer;
Expand Down Expand Up @@ -52,7 +52,7 @@ public ResilienceStrategyRegistry(ResilienceStrategyRegistryOptions<TKey> option
_activator = options.BuilderFactory;
_builders = new ConcurrentDictionary<TKey, Action<ResilienceStrategyBuilder, ConfigureBuilderContext<TKey>>>(options.BuilderComparer);
_strategies = new ConcurrentDictionary<TKey, ResilienceStrategy>(options.StrategyComparer);
_strategyKeyFormatter = options.StrategyKeyFormatter;
_instanceNameFormatter = options.InstanceNameFormatter;
_builderNameFormatter = options.BuilderNameFormatter;
_builderComparer = options.BuilderComparer;
_strategyComparer = options.StrategyComparer;
Expand Down Expand Up @@ -154,7 +154,7 @@ public ResilienceStrategy GetOrAddStrategy(TKey key, Action<ResilienceStrategyBu
return strategy;
}

var context = new ConfigureBuilderContext<TKey>(key, _builderNameFormatter(key), _strategyKeyFormatter(key));
var context = new ConfigureBuilderContext<TKey>(key, _builderNameFormatter(key), _instanceNameFormatter?.Invoke(key));

#if NETCOREAPP3_0_OR_GREATER
return _strategies.GetOrAdd(key, static (_, factory) =>
Expand Down Expand Up @@ -272,7 +272,7 @@ private static ResilienceStrategy CreateStrategy<TBuilder>(
{
var builder = activator();
builder.BuilderName = context.BuilderName;
builder.Properties.Set(TelemetryUtil.StrategyKey, context.StrategyKeyString);
builder.InstanceName = context.BuilderInstanceName;
configure(builder, context);

return builder;
Expand All @@ -294,6 +294,7 @@ private static ResilienceStrategy CreateStrategy<TBuilder>(
TelemetryUtil.CreateTelemetry(
diagnosticSource,
context.BuilderName,
context.BuilderInstanceName,
builder.Properties,
ReloadableResilienceStrategy.StrategyName,
ReloadableResilienceStrategy.StrategyType));
Expand All @@ -312,8 +313,8 @@ private GenericRegistry<TResult> GetGenericRegistry<TResult>()
() => new ResilienceStrategyBuilder<TResult>(_activator()),
_builderComparer,
_strategyComparer,
_strategyKeyFormatter,
_builderNameFormatter);
_builderNameFormatter,
_instanceNameFormatter);
});
}
}
11 changes: 5 additions & 6 deletions src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,16 @@ public class ResilienceStrategyRegistryOptions<TKey>

/// <summary>
/// Gets or sets the formatter that is used by the registry to format the <typeparamref name="TKey"/> to a string that
/// represents the strategy key.
/// represents the instance name of the builder.
/// </summary>
/// <remarks>
/// By default, the formatter uses the <see cref="object.ToString"/> method.
/// Defaults to <see langword="null"/>.
/// <para>
/// Use custom formatter for composite keys in case you want to have different metric values for a builder and strategy key.
/// In general, strategies can have the same builder name and different strategy keys.
/// Use custom formatter for composite keys in case you want to have different metric values for a builder and instance key.
/// In general, strategies can have the same builder name and different instance names.
/// </para>
/// </remarks>
[Required]
public Func<TKey, string> StrategyKeyFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty;
public Func<TKey, string>? InstanceNameFormatter { get; set; }

/// <summary>
/// Gets or sets the formatter that is used by the registry to format the <typeparamref name="TKey"/> to a string that
Expand Down
11 changes: 11 additions & 0 deletions src/Polly.Core/ResilienceStrategyBuilderBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ private protected ResilienceStrategyBuilderBase(ResilienceStrategyBuilderBase ot
/// </remarks>
public string? BuilderName { get; set; }

/// <summary>
/// Gets or sets the instance name of the builder.
/// </summary>
/// <remarks>
/// This property is also included in the telemetry that is produced by the individual resilience strategies.
/// The instance name can be used to differentiate between multiple builder instances with the same <see cref="BuilderName"/>.
/// Defaults to <see langword="null"/>.
/// </remarks>
public string? InstanceName { get; set; }

/// <summary>
/// Gets the custom properties attached to builder options.
/// </summary>
Expand Down Expand Up @@ -125,6 +135,7 @@ private ResilienceStrategy CreateResilienceStrategy(Entry entry)
{
var context = new ResilienceStrategyBuilderContext(
builderName: BuilderName,
builderInstanceName: InstanceName,
builderProperties: Properties,
strategyName: entry.Properties.StrategyName,
strategyType: entry.Properties.StrategyType,
Expand Down
9 changes: 8 additions & 1 deletion src/Polly.Core/ResilienceStrategyBuilderContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public sealed class ResilienceStrategyBuilderContext
{
internal ResilienceStrategyBuilderContext(
string? builderName,
string? builderInstanceName,
ResilienceProperties builderProperties,
string? strategyName,
string strategyType,
Expand All @@ -20,12 +21,13 @@ internal ResilienceStrategyBuilderContext(
Func<double> randomizer)
{
BuilderName = builderName;
BuilderInstanceName = builderInstanceName;
BuilderProperties = builderProperties;
StrategyName = strategyName;
StrategyType = strategyType;
TimeProvider = timeProvider;
IsGenericBuilder = isGenericBuilder;
Telemetry = TelemetryUtil.CreateTelemetry(diagnosticSource, builderName, builderProperties, strategyName, strategyType);
Telemetry = TelemetryUtil.CreateTelemetry(diagnosticSource, builderName, builderInstanceName, builderProperties, strategyName, strategyType);
Randomizer = randomizer;
}

Expand All @@ -34,6 +36,11 @@ internal ResilienceStrategyBuilderContext(
/// </summary>
public string? BuilderName { get; }

/// <summary>
/// Gets the instance name of the builder.
/// </summary>
public string? BuilderInstanceName { get; }

/// <summary>
/// Gets the custom properties attached to the builder.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Polly.Core/Telemetry/ResilienceTelemetrySource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Polly.Telemetry;
/// The source of resilience telemetry events.
/// </summary>
/// <param name="BuilderName">The builder name.</param>
/// <param name="BuilderInstanceName">The builder instance name.</param>
/// <param name="BuilderProperties">The builder properties.</param>
/// <param name="StrategyName">The strategy name. </param>
/// <param name="StrategyType">The strategy type.</param>
Expand All @@ -12,6 +13,7 @@ namespace Polly.Telemetry;
/// </remarks>
public sealed record class ResilienceTelemetrySource(
string? BuilderName,
string? BuilderInstanceName,
ResilienceProperties BuilderProperties,
string? StrategyName,
string StrategyType);
Expand Down
5 changes: 2 additions & 3 deletions src/Polly.Core/Telemetry/TelemetryUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@ internal static class TelemetryUtil

internal const string ExecutionAttempt = "ExecutionAttempt";

internal static readonly ResiliencePropertyKey<string> StrategyKey = new("Polly.StrategyKey");

public static ResilienceStrategyTelemetry CreateTelemetry(
DiagnosticSource? diagnosticSource,
string? builderName,
string? builderInstanceName,
ResilienceProperties builderProperties,
string? strategyName,
string strategyType)
{
var telemetrySource = new ResilienceTelemetrySource(builderName, builderProperties, strategyName, strategyType);
var telemetrySource = new ResilienceTelemetrySource(builderName, builderInstanceName, builderProperties, strategyName, strategyType);

return new ResilienceStrategyTelemetry(telemetrySource, diagnosticSource);
}
Expand Down
24 changes: 8 additions & 16 deletions src/Polly.Extensions/Telemetry/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ internal static partial class Log
EventId = 0,
Message = "Resilience event occurred. " +
"EventName: '{EventName}', " +
"Builder Name: '{BuilderName}', " +
"Strategy Name: '{StrategyName}', " +
"Strategy Type: '{StrategyType}', " +
"Strategy Key: '{StrategyKey}', " +
"Source: '{BuilderName}[{BuilderInstance}]/{StrategyType}[{StrategyName}]', " +
"Operation Key: '{OperationKey}', " +
"Result: '{Result}'",
EventName = "ResilienceEvent")]
Expand All @@ -24,9 +21,9 @@ public static partial void ResilienceEvent(
LogLevel logLevel,
string eventName,
string? builderName,
string? builderInstance,
string? strategyName,
string strategyType,
string? strategyKey,
string? operationKey,
object? result,
Exception? exception);
Expand All @@ -35,23 +32,21 @@ public static partial void ResilienceEvent(
1,
LogLevel.Debug,
"Resilience strategy executing. " +
"Builder Name: '{BuilderName}', " +
"Strategy Key: '{StrategyKey}', " +
"Source: '{BuilderName}[{BuilderInstance}]', " +
"Operation Key: '{OperationKey}', " +
"Result Type: '{ResultType}'",
EventName = "StrategyExecuting")]
public static partial void ExecutingStrategy(
this ILogger logger,
string? builderName,
string? strategyKey,
string? builderInstance,
string? operationKey,
string resultType);

[LoggerMessage(
EventId = 2,
Message = "Resilience strategy executed. " +
"Builder Name: '{BuilderName}', " +
"Strategy Key: '{StrategyKey}', " +
"Source: '{BuilderName}[{BuilderInstance}]', " +
"Operation Key: '{OperationKey}', " +
"Result Type: '{ResultType}', " +
"Result: '{Result}', " +
Expand All @@ -62,7 +57,7 @@ public static partial void StrategyExecuted(
this ILogger logger,
LogLevel logLevel,
string? builderName,
string? strategyKey,
string? builderInstance,
string? operationKey,
string resultType,
object? result,
Expand All @@ -73,10 +68,7 @@ public static partial void StrategyExecuted(
[LoggerMessage(
EventId = 3,
Message = "Execution attempt. " +
"Builder Name: '{BuilderName}', " +
"Strategy Name: '{StrategyName}', " +
"Strategy Type: '{StrategyType}', " +
"Strategy Key: '{StrategyKey}', " +
"Source: '{BuilderName}[{BuilderInstance}]/{StrategyType}[{StrategyName}]', " +
"Operation Key: '{OperationKey}', " +
"Result: '{Result}', " +
"Handled: '{Handled}', " +
Expand All @@ -88,9 +80,9 @@ public static partial void ExecutionAttempt(
this ILogger logger,
LogLevel level,
string? builderName,
string? builderInstance,
string? strategyName,
string strategyType,
string? strategyKey,
string? operationKey,
object? result,
bool handled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,9 @@ private static void AddCommonTags(TelemetryEventArguments args, ResilienceTeleme
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.EventName, args.Event.EventName));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.EventSeverity, args.Event.Severity.AsString()));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.BuilderName, source.BuilderName));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.BuilderInstance, source.BuilderInstanceName));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.StrategyName, source.StrategyName));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.StrategyType, source.StrategyType));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.StrategyKey, source.BuilderProperties.GetValue(TelemetryUtil.StrategyKey, null!)));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.OperationKey, enrichmentContext.Context.OperationKey));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.ResultType, args.Context.GetResultType()));
enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.ExceptionName, args.Outcome?.Exception?.GetType().FullName));
Expand Down Expand Up @@ -93,7 +93,6 @@ private void MeterEvent(TelemetryEventArguments args)

private void LogEvent(TelemetryEventArguments args)
{
var strategyKey = args.Source.BuilderProperties.GetValue(TelemetryUtil.StrategyKey, null!);
var result = args.Outcome?.Result;
if (result is not null)
{
Expand All @@ -114,9 +113,9 @@ private void LogEvent(TelemetryEventArguments args)
_logger,
level,
args.Source.BuilderName,
args.Source.BuilderInstanceName,
args.Source.StrategyName,
args.Source.StrategyType,
strategyKey,
args.Context.OperationKey,
result,
executionAttempt.Handled,
Expand All @@ -132,9 +131,9 @@ private void LogEvent(TelemetryEventArguments args)
level,
args.Event.EventName,
args.Source.BuilderName,
args.Source.BuilderInstanceName,
args.Source.StrategyName,
args.Source.StrategyType,
strategyKey,
args.Context.OperationKey,
result,
args.Outcome?.Exception);
Expand Down
4 changes: 2 additions & 2 deletions src/Polly.Extensions/Telemetry/ResilienceTelemetryTags.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ internal class ResilienceTelemetryTags

public const string BuilderName = "builder-name";

public const string BuilderInstance = "builder-instance";

public const string StrategyName = "strategy-name";

public const string StrategyType = "strategy-type";

public const string StrategyKey = "strategy-key";

public const string ResultType = "result-type";

public const string OperationKey = "operation-key";
Expand Down
Loading