diff --git a/src/Polly.Core/Registry/ConfigureBuilderContext.cs b/src/Polly.Core/Registry/ConfigureBuilderContext.cs index 4c4ab402264..284e4edef14 100644 --- a/src/Polly.Core/Registry/ConfigureBuilderContext.cs +++ b/src/Polly.Core/Registry/ConfigureBuilderContext.cs @@ -9,11 +9,11 @@ namespace Polly.Registry; public class ConfigureBuilderContext 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; } /// @@ -27,9 +27,9 @@ internal ConfigureBuilderContext(TKey strategyKey, string builderName, string st public string BuilderName { get; } /// - /// 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. /// - public string StrategyKeyString { get; } + public string? BuilderInstanceName { get; } internal Func>? ReloadTokenProducer { get; private set; } diff --git a/src/Polly.Core/Registry/ResilienceStrategyRegistry.TResult.cs b/src/Polly.Core/Registry/ResilienceStrategyRegistry.TResult.cs index 7ff833b2c41..ca16feb5f7c 100644 --- a/src/Polly.Core/Registry/ResilienceStrategyRegistry.TResult.cs +++ b/src/Polly.Core/Registry/ResilienceStrategyRegistry.TResult.cs @@ -11,21 +11,21 @@ private sealed class GenericRegistry private readonly ConcurrentDictionary, ConfigureBuilderContext>> _builders; private readonly ConcurrentDictionary> _strategies; - private readonly Func _strategyKeyFormatter; private readonly Func _builderNameFormatter; + private readonly Func? _instanceNameFormatter; public GenericRegistry( Func> activator, IEqualityComparer builderComparer, IEqualityComparer strategyComparer, - Func strategyKeyFormatter, - Func builderNameFormatter) + Func builderNameFormatter, + Func? instanceNameFormatter) { _activator = activator; _builders = new ConcurrentDictionary, ConfigureBuilderContext>>(builderComparer); _strategies = new ConcurrentDictionary>(strategyComparer); - _strategyKeyFormatter = strategyKeyFormatter; _builderNameFormatter = builderNameFormatter; + _instanceNameFormatter = instanceNameFormatter; } public bool TryAdd(TKey key, ResilienceStrategy strategy) => _strategies.TryAdd(key, strategy); @@ -51,7 +51,7 @@ public bool TryGet(TKey key, [NotNullWhen(true)] out ResilienceStrategy public ResilienceStrategy GetOrAdd(TKey key, Action, ConfigureBuilderContext> configure) { - var context = new ConfigureBuilderContext(key, _builderNameFormatter(key), _strategyKeyFormatter(key)); + var context = new ConfigureBuilderContext(key, _builderNameFormatter(key), _instanceNameFormatter?.Invoke(key)); #if NETCOREAPP3_0_OR_GREATER return _strategies.GetOrAdd(key, static (_, factory) => diff --git a/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs b/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs index 221a5c018d3..298f9d89438 100644 --- a/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs +++ b/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs @@ -24,7 +24,7 @@ public sealed partial class ResilienceStrategyRegistry : ResilienceStrateg private readonly ConcurrentDictionary _strategies; private readonly ConcurrentDictionary _genericRegistry = new(); - private readonly Func _strategyKeyFormatter; + private readonly Func? _instanceNameFormatter; private readonly Func _builderNameFormatter; private readonly IEqualityComparer _builderComparer; private readonly IEqualityComparer _strategyComparer; @@ -52,7 +52,7 @@ public ResilienceStrategyRegistry(ResilienceStrategyRegistryOptions option _activator = options.BuilderFactory; _builders = new ConcurrentDictionary>>(options.BuilderComparer); _strategies = new ConcurrentDictionary(options.StrategyComparer); - _strategyKeyFormatter = options.StrategyKeyFormatter; + _instanceNameFormatter = options.InstanceNameFormatter; _builderNameFormatter = options.BuilderNameFormatter; _builderComparer = options.BuilderComparer; _strategyComparer = options.StrategyComparer; @@ -154,7 +154,7 @@ public ResilienceStrategy GetOrAddStrategy(TKey key, Action(key, _builderNameFormatter(key), _strategyKeyFormatter(key)); + var context = new ConfigureBuilderContext(key, _builderNameFormatter(key), _instanceNameFormatter?.Invoke(key)); #if NETCOREAPP3_0_OR_GREATER return _strategies.GetOrAdd(key, static (_, factory) => @@ -272,7 +272,7 @@ private static ResilienceStrategy CreateStrategy( { var builder = activator(); builder.BuilderName = context.BuilderName; - builder.Properties.Set(TelemetryUtil.StrategyKey, context.StrategyKeyString); + builder.InstanceName = context.BuilderInstanceName; configure(builder, context); return builder; @@ -294,6 +294,7 @@ private static ResilienceStrategy CreateStrategy( TelemetryUtil.CreateTelemetry( diagnosticSource, context.BuilderName, + context.BuilderInstanceName, builder.Properties, ReloadableResilienceStrategy.StrategyName, ReloadableResilienceStrategy.StrategyType)); @@ -312,8 +313,8 @@ private GenericRegistry GetGenericRegistry() () => new ResilienceStrategyBuilder(_activator()), _builderComparer, _strategyComparer, - _strategyKeyFormatter, - _builderNameFormatter); + _builderNameFormatter, + _instanceNameFormatter); }); } } diff --git a/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs b/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs index 05cd3ac68b9..de3d0877cc2 100644 --- a/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs +++ b/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs @@ -37,17 +37,16 @@ public class ResilienceStrategyRegistryOptions /// /// Gets or sets the formatter that is used by the registry to format the to a string that - /// represents the strategy key. + /// represents the instance name of the builder. /// /// - /// By default, the formatter uses the method. + /// Defaults to . /// - /// 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. /// /// - [Required] - public Func StrategyKeyFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty; + public Func? InstanceNameFormatter { get; set; } /// /// Gets or sets the formatter that is used by the registry to format the to a string that diff --git a/src/Polly.Core/ResilienceStrategyBuilderBase.cs b/src/Polly.Core/ResilienceStrategyBuilderBase.cs index 58592fb204e..c7083f16034 100644 --- a/src/Polly.Core/ResilienceStrategyBuilderBase.cs +++ b/src/Polly.Core/ResilienceStrategyBuilderBase.cs @@ -40,6 +40,16 @@ private protected ResilienceStrategyBuilderBase(ResilienceStrategyBuilderBase ot /// public string? BuilderName { get; set; } + /// + /// Gets or sets the instance name of the builder. + /// + /// + /// 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 . + /// Defaults to . + /// + public string? InstanceName { get; set; } + /// /// Gets the custom properties attached to builder options. /// @@ -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, diff --git a/src/Polly.Core/ResilienceStrategyBuilderContext.cs b/src/Polly.Core/ResilienceStrategyBuilderContext.cs index 7af4af62e9f..27e97bbbc5b 100644 --- a/src/Polly.Core/ResilienceStrategyBuilderContext.cs +++ b/src/Polly.Core/ResilienceStrategyBuilderContext.cs @@ -11,6 +11,7 @@ public sealed class ResilienceStrategyBuilderContext { internal ResilienceStrategyBuilderContext( string? builderName, + string? builderInstanceName, ResilienceProperties builderProperties, string? strategyName, string strategyType, @@ -20,12 +21,13 @@ internal ResilienceStrategyBuilderContext( Func 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; } @@ -34,6 +36,11 @@ internal ResilienceStrategyBuilderContext( /// public string? BuilderName { get; } + /// + /// Gets the instance name of the builder. + /// + public string? BuilderInstanceName { get; } + /// /// Gets the custom properties attached to the builder. /// diff --git a/src/Polly.Core/Telemetry/ResilienceTelemetrySource.cs b/src/Polly.Core/Telemetry/ResilienceTelemetrySource.cs index 0a2fbda10eb..18e680c8b7b 100644 --- a/src/Polly.Core/Telemetry/ResilienceTelemetrySource.cs +++ b/src/Polly.Core/Telemetry/ResilienceTelemetrySource.cs @@ -4,6 +4,7 @@ namespace Polly.Telemetry; /// The source of resilience telemetry events. /// /// The builder name. +/// The builder instance name. /// The builder properties. /// The strategy name. /// The strategy type. @@ -12,6 +13,7 @@ namespace Polly.Telemetry; /// public sealed record class ResilienceTelemetrySource( string? BuilderName, + string? BuilderInstanceName, ResilienceProperties BuilderProperties, string? StrategyName, string StrategyType); diff --git a/src/Polly.Core/Telemetry/TelemetryUtil.cs b/src/Polly.Core/Telemetry/TelemetryUtil.cs index f2afd372dec..92b75d2bf9e 100644 --- a/src/Polly.Core/Telemetry/TelemetryUtil.cs +++ b/src/Polly.Core/Telemetry/TelemetryUtil.cs @@ -6,16 +6,15 @@ internal static class TelemetryUtil internal const string ExecutionAttempt = "ExecutionAttempt"; - internal static readonly ResiliencePropertyKey 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); } diff --git a/src/Polly.Extensions/Telemetry/Log.cs b/src/Polly.Extensions/Telemetry/Log.cs index 06ec3b794e1..0fa597f9850 100644 --- a/src/Polly.Extensions/Telemetry/Log.cs +++ b/src/Polly.Extensions/Telemetry/Log.cs @@ -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")] @@ -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); @@ -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}', " + @@ -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, @@ -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}', " + @@ -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, diff --git a/src/Polly.Extensions/Telemetry/ResilienceTelemetryDiagnosticSource.cs b/src/Polly.Extensions/Telemetry/ResilienceTelemetryDiagnosticSource.cs index fa7de3d0910..a7a54fb6ce6 100644 --- a/src/Polly.Extensions/Telemetry/ResilienceTelemetryDiagnosticSource.cs +++ b/src/Polly.Extensions/Telemetry/ResilienceTelemetryDiagnosticSource.cs @@ -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)); @@ -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) { @@ -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, @@ -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); diff --git a/src/Polly.Extensions/Telemetry/ResilienceTelemetryTags.cs b/src/Polly.Extensions/Telemetry/ResilienceTelemetryTags.cs index cc1f26c49f4..63d955e888b 100644 --- a/src/Polly.Extensions/Telemetry/ResilienceTelemetryTags.cs +++ b/src/Polly.Extensions/Telemetry/ResilienceTelemetryTags.cs @@ -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"; diff --git a/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategy.cs b/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategy.cs index d06ee65327a..733def18ffc 100644 --- a/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategy.cs +++ b/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategy.cs @@ -7,7 +7,7 @@ internal sealed class TelemetryResilienceStrategy : ResilienceStrategy { private readonly TimeProvider _timeProvider; private readonly string? _builderName; - private readonly string? _strategyKey; + private readonly string? _builderInstance; private readonly List> _enrichers; private readonly ILogger _logger; private readonly Func _resultFormatter; @@ -15,25 +15,25 @@ internal sealed class TelemetryResilienceStrategy : ResilienceStrategy // Temporary only, until the TimeProvider is exposed public TelemetryResilienceStrategy( string builderName, - string? strategyKey, + string? builderInstance, ILoggerFactory loggerFactory, Func resultFormatter, List> enrichers) - : this(TimeProvider.System, builderName, strategyKey, loggerFactory, resultFormatter, enrichers) + : this(TimeProvider.System, builderName, builderInstance, loggerFactory, resultFormatter, enrichers) { } public TelemetryResilienceStrategy( TimeProvider timeProvider, string? builderName, - string? strategyKey, + string? builderInstance, ILoggerFactory loggerFactory, Func resultFormatter, List> enrichers) { _timeProvider = timeProvider; _builderName = builderName; - _strategyKey = strategyKey; + _builderInstance = builderInstance; _resultFormatter = resultFormatter; _enrichers = enrichers; _logger = loggerFactory.CreateLogger(TelemetryUtil.PollyDiagnosticSource); @@ -51,7 +51,7 @@ protected override async ValueTask> ExecuteCoreAsync> ExecuteCoreAsync(ResilienceContext context, Outcome var enrichmentContext = EnrichmentContext.Get(context, null, CreateOutcome(outcome)); enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.BuilderName, _builderName)); - enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.StrategyKey, _strategyKey)); + enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.BuilderInstance, _builderInstance)); enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.OperationKey, context.OperationKey)); enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.ResultType, context.GetResultType())); enrichmentContext.Tags.Add(new(ResilienceTelemetryTags.ExceptionName, outcome.Exception?.GetType().FullName)); diff --git a/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategyBuilderExtensions.cs b/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategyBuilderExtensions.cs index ad822a48292..66f6b64614d 100644 --- a/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategyBuilderExtensions.cs +++ b/src/Polly.Extensions/Telemetry/TelemetryResilienceStrategyBuilderExtensions.cs @@ -57,7 +57,7 @@ public static TBuilder ConfigureTelemetry(this TBuilder builder, Telem var telemetryStrategy = new TelemetryResilienceStrategy( TimeProvider.System, builder.BuilderName, - builder.Properties.GetValue(TelemetryUtil.StrategyKey, null!), + builder.InstanceName, options.LoggerFactory, options.ResultFormatter, options.Enrichers.ToList()); diff --git a/src/Polly.Extensions/Telemetry/TelemetryUtil.cs b/src/Polly.Extensions/Telemetry/TelemetryUtil.cs index c04a37efee7..167a628a0a3 100644 --- a/src/Polly.Extensions/Telemetry/TelemetryUtil.cs +++ b/src/Polly.Extensions/Telemetry/TelemetryUtil.cs @@ -15,8 +15,6 @@ internal static class TelemetryUtil internal const string PollyDiagnosticSource = "Polly"; - internal static readonly ResiliencePropertyKey StrategyKey = new("Polly.StrategyKey"); - public static object AsBoxedBool(this bool value) => value switch { true => True, diff --git a/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs b/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs index 61673025b97..4315fe10498 100644 --- a/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs +++ b/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs @@ -8,9 +8,7 @@ public void Ctor_EnsureDefaults() { ResilienceStrategyRegistryOptions options = new(); - options.StrategyKeyFormatter.Should().NotBeNull(); - options.StrategyKeyFormatter(null!).Should().Be(""); - options.StrategyKeyFormatter("ABC").Should().Be("ABC"); + options.InstanceNameFormatter.Should().BeNull(); options.BuilderNameFormatter.Should().NotBeNull(); options.BuilderNameFormatter(null!).Should().Be(""); diff --git a/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs b/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs index 80c0c24ae43..05aa6eaa0b3 100644 --- a/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs +++ b/test/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs @@ -2,7 +2,6 @@ using System.Globalization; using Polly.Registry; using Polly.Retry; -using Polly.Telemetry; using Polly.Timeout; namespace Polly.Core.Tests.Registry; @@ -233,18 +232,16 @@ public void AddBuilder_GenericGetStrategy_EnsureCalled() public void AddBuilder_EnsureStrategyKey() { _options.BuilderNameFormatter = k => k.BuilderName; - _options.StrategyKeyFormatter = k => k.InstanceName; + _options.InstanceNameFormatter = k => k.InstanceName; var called = false; var registry = CreateRegistry(); registry.TryAddBuilder(StrategyId.Create("A"), (builder, context) => { context.BuilderName.Should().Be("A"); - context.StrategyKeyString.Should().Be("Instance1"); + context.BuilderInstanceName.Should().Be("Instance1"); builder.AddStrategy(new TestResilienceStrategy()); builder.BuilderName.Should().Be("A"); - builder.Properties.TryGetValue(TelemetryUtil.StrategyKey, out var val).Should().BeTrue(); - val.Should().Be("Instance1"); called = true; }); @@ -267,7 +264,7 @@ public void AddBuilder_MultipleGeneric_EnsureDistinctInstances() public void AddBuilder_Generic_EnsureStrategyKey() { _options.BuilderNameFormatter = k => k.BuilderName; - _options.StrategyKeyFormatter = k => k.InstanceName; + _options.InstanceNameFormatter = k => k.InstanceName; var called = false; var registry = CreateRegistry(); @@ -275,8 +272,7 @@ public void AddBuilder_Generic_EnsureStrategyKey() { builder.AddStrategy(new TestResilienceStrategy()); builder.BuilderName.Should().Be("A"); - builder.Properties.TryGetValue(TelemetryUtil.StrategyKey, out var val).Should().BeTrue(); - val.Should().Be("Instance1"); + builder.InstanceName.Should().Be("Instance1"); called = true; }); diff --git a/test/Polly.Core.Tests/ResilienceStrategyBuilderContextTests.cs b/test/Polly.Core.Tests/ResilienceStrategyBuilderContextTests.cs index 9320693bbfc..71522769891 100644 --- a/test/Polly.Core.Tests/ResilienceStrategyBuilderContextTests.cs +++ b/test/Polly.Core.Tests/ResilienceStrategyBuilderContextTests.cs @@ -10,10 +10,11 @@ public void Ctor_EnsureDefaults() { var properties = new ResilienceProperties(); var timeProvider = new FakeTimeProvider(); - var context = new ResilienceStrategyBuilderContext("builder-name", properties, "strategy-name", "strategy-type", timeProvider, true, Mock.Of(), () => 1.0); + var context = new ResilienceStrategyBuilderContext("builder-name", "instance", properties, "strategy-name", "strategy-type", timeProvider, true, Mock.Of(), () => 1.0); context.IsGenericBuilder.Should().BeTrue(); context.BuilderName.Should().Be("builder-name"); + context.BuilderInstanceName.Should().Be("instance"); context.BuilderProperties.Should().BeSameAs(properties); context.StrategyName.Should().Be("strategy-name"); context.StrategyType.Should().Be("strategy-type"); diff --git a/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs b/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs index 743a6d3a1cd..5891546c113 100644 --- a/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs +++ b/test/Polly.Core.Tests/Telemetry/ResilienceStrategyTelemetryTests.cs @@ -7,7 +7,12 @@ public class ResilienceStrategyTelemetryTests { private readonly Mock _diagnosticSource = new(MockBehavior.Strict); - public ResilienceStrategyTelemetryTests() => _sut = new(new ResilienceTelemetrySource("builder", new ResilienceProperties(), "strategy-name", "strategy-type"), _diagnosticSource.Object); + public ResilienceStrategyTelemetryTests() => _sut = new(new ResilienceTelemetrySource( + "builder", + "instance", + new ResilienceProperties(), + "strategy-name", + "strategy-type"), _diagnosticSource.Object); private readonly ResilienceStrategyTelemetry _sut; @@ -52,7 +57,7 @@ public void Report_NoOutcomeWhenNotSubscribed_None() [Fact] public void ResilienceStrategyTelemetry_NoDiagnosticSource_Ok() { - var source = new ResilienceTelemetrySource("builder", new ResilienceProperties(), "strategy-name", "strategy-type"); + var source = new ResilienceTelemetrySource("builder", "instance", new ResilienceProperties(), "strategy-name", "strategy-type"); var sut = new ResilienceStrategyTelemetry(source, null); var context = ResilienceContext.Get(); diff --git a/test/Polly.Core.Tests/Telemetry/TelemetryEventArgumentsTests.cs b/test/Polly.Core.Tests/Telemetry/TelemetryEventArgumentsTests.cs index 710546db6ef..229e7820b1f 100644 --- a/test/Polly.Core.Tests/Telemetry/TelemetryEventArgumentsTests.cs +++ b/test/Polly.Core.Tests/Telemetry/TelemetryEventArgumentsTests.cs @@ -4,7 +4,7 @@ namespace Polly.Extensions.Tests.Telemetry; public class TelemetryEventArgumentsTests { - private readonly ResilienceTelemetrySource _source = new("builder", new ResilienceProperties(), "strategy", "type"); + private readonly ResilienceTelemetrySource _source = new("builder", "instance", new ResilienceProperties(), "strategy", "type"); [Fact] public void Get_Ok() diff --git a/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs b/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs index 41f243fa92c..ba27b61e46c 100644 --- a/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs +++ b/test/Polly.Core.Tests/Telemetry/TelemetryUtilTests.cs @@ -5,18 +5,13 @@ namespace Polly.Core.Tests.Telemetry; public class TelemetryUtilTests { - [Fact] - public void Ctor_Ok() - { - TelemetryUtil.StrategyKey.Key.Should().Be("Polly.StrategyKey"); - } - [Fact] public void CreateResilienceTelemetry_Ok() { - var telemetry = TelemetryUtil.CreateTelemetry(null, "builder", new ResilienceProperties(), "strategy-name", "strategy-type"); + var telemetry = TelemetryUtil.CreateTelemetry(null, "builder", "instance", new ResilienceProperties(), "strategy-name", "strategy-type"); telemetry.TelemetrySource.BuilderName.Should().Be("builder"); + telemetry.TelemetrySource.BuilderInstanceName.Should().Be("instance"); telemetry.TelemetrySource.StrategyName.Should().Be("strategy-name"); telemetry.TelemetrySource.StrategyType.Should().Be("strategy-type"); telemetry.DiagnosticSource.Should().BeNull(); @@ -28,7 +23,7 @@ public void CreateResilienceTelemetry_DiagnosticSourceFromProperties_Ok() var props = new ResilienceProperties(); var source = Mock.Of(); - var telemetry = TelemetryUtil.CreateTelemetry(source, "builder", props, "strategy-name", "strategy-type"); + var telemetry = TelemetryUtil.CreateTelemetry(source, "builder", "instance", props, "strategy-name", "strategy-type"); telemetry.DiagnosticSource.Should().Be(source); } diff --git a/test/Polly.Extensions.Tests/Telemetry/ResilienceTelemetryDiagnosticSourceTests.cs b/test/Polly.Extensions.Tests/Telemetry/ResilienceTelemetryDiagnosticSourceTests.cs index 555d12d47e3..53f2e7ebfa8 100644 --- a/test/Polly.Extensions.Tests/Telemetry/ResilienceTelemetryDiagnosticSourceTests.cs +++ b/test/Polly.Extensions.Tests/Telemetry/ResilienceTelemetryDiagnosticSourceTests.cs @@ -72,11 +72,11 @@ public void WriteEvent_LoggingWithOutcome_Ok(bool noOutcome) if (noOutcome) { - messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: ''"); + messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: ''"); } else { - messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: '200'"); + messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: '200'"); } } @@ -99,23 +99,23 @@ public void WriteEvent_LoggingWithException_Ok(bool noOutcome) if (noOutcome) { - messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: ''"); + messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: ''"); } else { - messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: 'Dummy message.'"); + messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: 'Dummy message.'"); } } [Fact] - public void WriteEvent_LoggingWithoutStrategyKey_Ok() + public void WriteEvent_LoggingWithoutInstanceName_Ok() { var telemetry = Create(); - ReportEvent(telemetry, null, strategyKey: null); + ReportEvent(telemetry, null, instanceName: null); var messages = _logger.GetRecords(new EventId(0, "ResilienceEvent")).ToList(); - messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: '', Operation Key: 'op-key', Result: ''"); + messages[0].Message.Should().Be("Resilience event occurred. EventName: 'my-event', Source: 'my-builder[]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: ''"); } [InlineData(ResilienceEventSeverity.Error, LogLevel.Error)] @@ -150,7 +150,7 @@ public void WriteExecutionAttempt_LoggingWithException_Ok() var messages = _logger.GetRecords(new EventId(3, "ExecutionAttempt")).ToList(); messages.Should().HaveCount(1); - messages[0].Message.Should().Be("Execution attempt. Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: 'Dummy message.', Handled: 'True', Attempt: '4', Execution Time: '123'"); + messages[0].Message.Should().Be("Execution attempt. Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: 'Dummy message.', Handled: 'True', Attempt: '4', Execution Time: '123'"); } [InlineData(true, true)] @@ -170,11 +170,11 @@ public void WriteExecutionAttempt_LoggingWithOutcome_Ok(bool noOutcome, bool han if (noOutcome) { string resultString = string.Empty; - messages[0].Message.Should().Be($"Execution attempt. Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: '{resultString}', Handled: '{handled}', Attempt: '4', Execution Time: '123'"); + messages[0].Message.Should().Be($"Execution attempt. Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: '{resultString}', Handled: '{handled}', Attempt: '4', Execution Time: '123'"); } else { - messages[0].Message.Should().Be($"Execution attempt. Builder Name: 'my-builder', Strategy Name: 'my-strategy', Strategy Type: 'my-strategy-type', Strategy Key: 'my-strategy-key', Operation Key: 'op-key', Result: '200', Handled: '{handled}', Attempt: '4', Execution Time: '123'"); + messages[0].Message.Should().Be($"Execution attempt. Source: 'my-builder[builder-instance]/my-strategy-type[my-strategy]', Operation Key: 'op-key', Result: '200', Handled: '{handled}', Attempt: '4', Execution Time: '123'"); } messages[0].LogLevel.Should().Be(LogLevel.Warning); @@ -217,7 +217,7 @@ public void WriteEvent_MeteringWithoutEnrichers_Ok(bool noOutcome, bool exceptio ev["event-severity"].Should().Be("Warning"); ev["strategy-type"].Should().Be("my-strategy-type"); ev["strategy-name"].Should().Be("my-strategy"); - ev["strategy-key"].Should().Be("my-strategy-key"); + ev["builder-instance"].Should().Be("builder-instance"); ev["operation-key"].Should().Be("op-key"); ev["builder-name"].Should().Be("my-builder"); ev["result-type"].Should().Be("Boolean"); @@ -258,7 +258,7 @@ public void WriteExecutionAttemptEvent_Metering_Ok(bool noOutcome, bool exceptio ev["event-severity"].Should().Be("Warning"); ev["strategy-type"].Should().Be("my-strategy-type"); ev["strategy-name"].Should().Be("my-strategy"); - ev["strategy-key"].Should().Be("my-strategy-key"); + ev["builder-instance"].Should().Be("builder-instance"); ev["operation-key"].Should().Be("op-key"); ev["builder-name"].Should().Be("my-builder"); ev["result-type"].Should().Be("Boolean"); @@ -313,11 +313,11 @@ public void WriteEvent_MeteringWithEnrichers_Ok(int count) } [Fact] - public void WriteEvent_MeteringWithoutStrategyKey_Ok() + public void WriteEvent_MeteringWithoutBuilderInstance_Ok() { var telemetry = Create(); - ReportEvent(telemetry, null, strategyKey: null); - var events = GetEvents("resilience-events")[0]["strategy-key"].Should().BeNull(); + ReportEvent(telemetry, null, instanceName: null); + var events = GetEvents("resilience-events")[0]["builder-instance"].Should().BeNull(); } [InlineData(true)] @@ -333,7 +333,7 @@ public void OnTelemetryEvent_Ok(bool hasCallback) } var telemetry = Create(); - ReportEvent(telemetry, null, strategyKey: null); + ReportEvent(telemetry, null, instanceName: null); called.Should().Be(hasCallback); } @@ -356,21 +356,22 @@ private ResilienceTelemetryDiagnosticSource Create(Action? outcome, - string? strategyKey = "my-strategy-key", + string? instanceName = "builder-instance", ResilienceContext? context = null, object? arg = null, ResilienceEventSeverity severity = ResilienceEventSeverity.Warning) { context ??= ResilienceContext.Get("op-key"); var props = new ResilienceProperties(); - if (!string.IsNullOrEmpty(strategyKey)) + if (!string.IsNullOrEmpty(instanceName)) { - props.Set(new ResiliencePropertyKey("Polly.StrategyKey"), strategyKey); + props.Set(new ResiliencePropertyKey("Polly.StrategyKey"), instanceName); } telemetry.ReportEvent( new ResilienceEvent(severity, "my-event"), "my-builder", + instanceName, props, "my-strategy", "my-strategy-type", diff --git a/test/Polly.Extensions.Tests/Telemetry/TelemetryResilienceStrategyTests.cs b/test/Polly.Extensions.Tests/Telemetry/TelemetryResilienceStrategyTests.cs index b5f708bf1e1..953e412591d 100644 --- a/test/Polly.Extensions.Tests/Telemetry/TelemetryResilienceStrategyTests.cs +++ b/test/Polly.Extensions.Tests/Telemetry/TelemetryResilienceStrategyTests.cs @@ -50,10 +50,10 @@ public void Execute_EnsureLogged(bool healthy) var messages = _logger.GetRecords(new EventId(1, "StrategyExecuting")).ToList(); messages.Should().HaveCount(1); - messages[0].Message.Should().Be("Resilience strategy executing. Builder Name: 'my-builder', Strategy Key: 'my-key', Operation Key: 'op-key', Result Type: 'void'"); + messages[0].Message.Should().Be("Resilience strategy executing. Source: 'my-builder[my-instance]', Operation Key: 'op-key', Result Type: 'void'"); messages = _logger.GetRecords(new EventId(2, "StrategyExecuted")).ToList(); messages.Should().HaveCount(1); - messages[0].Message.Should().Match($"Resilience strategy executed. Builder Name: 'my-builder', Strategy Key: 'my-key', Operation Key: 'op-key', Result Type: 'void', Result: 'void', Execution Health: '{healthString}', Execution Time: *ms"); + messages[0].Message.Should().Match($"Resilience strategy executed. Source: 'my-builder[my-instance]', Operation Key: 'op-key', Result Type: 'void', Result: 'void', Execution Health: '{healthString}', Execution Time: *ms"); messages[0].LogLevel.Should().Be(healthy ? LogLevel.Debug : LogLevel.Warning); // verify reported state @@ -78,11 +78,11 @@ public void Execute_WithException_EnsureLogged() var messages = _logger.GetRecords(new EventId(1, "StrategyExecuting")).ToList(); messages.Should().HaveCount(1); - messages[0].Message.Should().Be("Resilience strategy executing. Builder Name: 'my-builder', Strategy Key: 'my-key', Operation Key: 'op-key', Result Type: 'void'"); + messages[0].Message.Should().Be("Resilience strategy executing. Source: 'my-builder[my-instance]', Operation Key: 'op-key', Result Type: 'void'"); messages = _logger.GetRecords(new EventId(2, "StrategyExecuted")).ToList(); messages.Should().HaveCount(1); - messages[0].Message.Should().Match($"Resilience strategy executed. Builder Name: 'my-builder', Strategy Key: 'my-key', Operation Key: 'op-key', Result Type: 'void', Result: 'Dummy message.', Execution Health: 'Healthy', Execution Time: *ms"); + messages[0].Message.Should().Match($"Resilience strategy executed. Source: 'my-builder[my-instance]', Operation Key: 'op-key', Result Type: 'void', Result: 'Dummy message.', Execution Health: 'Healthy', Execution Time: *ms"); messages[0].Exception.Should().BeOfType(); } @@ -120,7 +120,7 @@ public void Execute_WithException_EnsureMetered() var ev = _events.Single(v => v.Name == "strategy-execution-duration").Tags; ev.Count.Should().Be(6); - ev["strategy-key"].Should().Be("my-key"); + ev["builder-instance"].Should().Be("my-instance"); ev["operation-key"].Should().Be("op-key"); ev["builder-name"].Should().Be("my-builder"); ev["result-type"].Should().Be("void"); @@ -165,7 +165,7 @@ public void Execute_WithResult_EnsureMetered(bool healthy) var ev = _events.Single(v => v.Name == "strategy-execution-duration").Tags; ev.Count.Should().Be(6); - ev["strategy-key"].Should().Be("my-key"); + ev["builder-instance"].Should().Be("my-instance"); ev["operation-key"].Should().Be("op-key"); ev["builder-name"].Should().Be("my-builder"); ev["result-type"].Should().Be("Boolean"); @@ -217,7 +217,7 @@ public void Execute_ExecutionHealth(bool healthy) } } - private TelemetryResilienceStrategy CreateStrategy() => new("my-builder", "my-key", _loggerFactory, (_, r) => r, new List> { c => _enricher?.Invoke(c) }); + private TelemetryResilienceStrategy CreateStrategy() => new("my-builder", "my-instance", _loggerFactory, (_, r) => r, new List> { c => _enricher?.Invoke(c) }); public void Dispose() { diff --git a/test/Polly.TestUtils/TestUtilities.cs b/test/Polly.TestUtils/TestUtilities.cs index b4e5aa7fbd0..37aa9566245 100644 --- a/test/Polly.TestUtils/TestUtilities.cs +++ b/test/Polly.TestUtils/TestUtilities.cs @@ -38,10 +38,10 @@ public static async Task AssertWithTimeoutAsync(Func assertion, TimeSpan t } public static ResilienceStrategyTelemetry CreateResilienceTelemetry(DiagnosticSource source) - => new(new ResilienceTelemetrySource("dummy-builder", new ResilienceProperties(), "strategy-name", "strategy-type"), source); + => new(new ResilienceTelemetrySource("dummy-builder", "dummy-instance", new ResilienceProperties(), "strategy-name", "strategy-type"), source); public static ResilienceStrategyTelemetry CreateResilienceTelemetry(Action callback) - => new(new ResilienceTelemetrySource("dummy-builder", new ResilienceProperties(), "strategy-name", "strategy-type"), new CallbackDiagnosticSource(callback)); + => new(new ResilienceTelemetrySource("dummy-builder", "dummy-instance", new ResilienceProperties(), "strategy-name", "strategy-type"), new CallbackDiagnosticSource(callback)); public static ILoggerFactory CreateLoggerFactory(out FakeLogger logger) { @@ -80,6 +80,7 @@ public static void ReportEvent( this DiagnosticSource source, ResilienceEvent resilienceEvent, string builderName, + string? instanceName, ResilienceProperties builderProperties, string strategyName, string strategyType, @@ -89,7 +90,7 @@ public static void ReportEvent( #pragma warning restore S107 // Methods should not have too many parameters { source.Write(resilienceEvent.EventName, TelemetryEventArguments.Get( - new ResilienceTelemetrySource(builderName, builderProperties, strategyName, strategyType), + new ResilienceTelemetrySource(builderName, instanceName, builderProperties, strategyName, strategyType), resilienceEvent, context, outcome,