diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0ca9240a480..88a7a5ced07 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,14 +41,14 @@ jobs: restore-keys: ${{ runner.os }}-nuget- - name: Initialize CodeQL - uses: github/codeql-action/init@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/init@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/autobuild@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/analyze@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 with: category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml index 819f61d9553..eb6bcdb092c 100644 --- a/.github/workflows/ossf-scorecard.yml +++ b/.github/workflows/ossf-scorecard.yml @@ -39,6 +39,6 @@ jobs: retention-days: 5 - name: Upload to code-scanning - uses: github/codeql-action/upload-sarif@f3feb00acb00f31a6f60280e6ace9ca31d91c76a # v2.3.2 + uses: github/codeql-action/upload-sarif@29b1f65c5e92e24fe6b6647da1eaabe529cec70f # v2.3.3 with: sarif_file: results.sarif diff --git a/.github/workflows/update-dotnet-sdk.yml b/.github/workflows/update-dotnet-sdk.yml index 06853e9a084..32ca01b727f 100644 --- a/.github/workflows/update-dotnet-sdk.yml +++ b/.github/workflows/update-dotnet-sdk.yml @@ -25,7 +25,7 @@ jobs: uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2 - name: Update .NET SDK - uses: martincostello/update-dotnet-sdk@bba9c5d796cf9e84046ae0cb42f7dd33bde568f3 # v2.1.4 + uses: martincostello/update-dotnet-sdk@6cfd047b0c2ce72ea0e22708bc1918a3d912c050 # v2.2.0 with: labels: "dependencies,.NET" repo-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index f618126c537..cad0c8cc8ed 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -3,7 +3,7 @@ - + @@ -13,7 +13,7 @@ - + diff --git a/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs b/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs index aeec877c49c..61673025b97 100644 --- a/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs +++ b/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryOptionsTests.cs @@ -8,8 +8,12 @@ public void Ctor_EnsureDefaults() { ResilienceStrategyRegistryOptions options = new(); - options.KeyFormatter.Should().NotBeNull(); - options.KeyFormatter(null!).Should().Be(""); - options.KeyFormatter("ABC").Should().Be("ABC"); + options.StrategyKeyFormatter.Should().NotBeNull(); + options.StrategyKeyFormatter(null!).Should().Be(""); + options.StrategyKeyFormatter("ABC").Should().Be("ABC"); + + options.BuilderNameFormatter.Should().NotBeNull(); + options.BuilderNameFormatter(null!).Should().Be(""); + options.BuilderNameFormatter("ABC").Should().Be("ABC"); } } diff --git a/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs b/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs index e8f463ff2b5..1ade2d37721 100644 --- a/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs +++ b/src/Polly.Core.Tests/Registry/ResilienceStrategyRegistryTests.cs @@ -7,8 +7,22 @@ namespace Polly.Core.Tests.Registry; public class ResilienceStrategyRegistryTests { + private readonly ResilienceStrategyRegistryOptions _options; + private Action _callback = _ => { }; + public ResilienceStrategyRegistryTests() => _options = new() + { + BuilderFactory = () => + { + var builder = new ResilienceStrategyBuilder(); + _callback(builder); + return builder; + }, + StrategyComparer = StrategyId.Comparer, + BuilderComparer = StrategyId.BuilderComparer + }; + [Fact] public void Ctor_Default_Ok() { @@ -121,18 +135,21 @@ public void AddBuilder_GetStrategy_EnsureCalled() [Fact] public void AddBuilder_EnsureStrategyKey() { + _options.BuilderNameFormatter = k => k.BuilderName; + _options.StrategyKeyFormatter = k => k.InstanceName; + var called = false; var registry = CreateRegistry(); - registry.TryAddBuilder(StrategyId.Create("A"), (key, builder) => + registry.TryAddBuilder(StrategyId.Create("A"), (_, builder) => { builder.AddStrategy(new TestResilienceStrategy()); + builder.BuilderName.Should().Be("A"); builder.Properties.TryGetValue(TelemetryUtil.StrategyKey, out var val).Should().BeTrue(); - val.Should().Be(key.ToString()); + val.Should().Be("Instance1"); called = true; }); registry.Get(StrategyId.Create("A", "Instance1")); - called.Should().BeTrue(); } @@ -175,16 +192,6 @@ public void TryAdd_Twice_SecondNotAdded() private ResilienceStrategyRegistry CreateRegistry() { - return new ResilienceStrategyRegistry(new ResilienceStrategyRegistryOptions - { - BuilderFactory = () => - { - var builder = new ResilienceStrategyBuilder(); - _callback(builder); - return builder; - }, - StrategyComparer = StrategyId.Comparer, - BuilderComparer = StrategyId.BuilderComparer - }); + return new ResilienceStrategyRegistry(_options); } } diff --git a/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs b/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs index 75a52594a5d..c16fc61bbaa 100644 --- a/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs +++ b/src/Polly.Core/Registry/ResilienceStrategyRegistry.cs @@ -21,7 +21,8 @@ public sealed class ResilienceStrategyRegistry : ResilienceStrategyProvide private readonly Func _activator; private readonly ConcurrentDictionary> _builders; private readonly ConcurrentDictionary _strategies; - private readonly Func _keyFormatter; + private readonly Func _strategyKeyFormatter; + private readonly Func _builderNameFormatter; /// /// Initializes a new instance of the class with the default comparer. @@ -44,7 +45,8 @@ public ResilienceStrategyRegistry(ResilienceStrategyRegistryOptions option _activator = options.BuilderFactory; _builders = new ConcurrentDictionary>(options.BuilderComparer); _strategies = new ConcurrentDictionary(options.StrategyComparer); - _keyFormatter = options.KeyFormatter; + _strategyKeyFormatter = options.StrategyKeyFormatter; + _builderNameFormatter = options.BuilderNameFormatter; } /// @@ -89,7 +91,8 @@ public override bool TryGet(TKey key, [NotNullWhen(true)] out ResilienceStrategy strategy = _strategies.GetOrAdd(key, key => { var builder = _activator(); - builder.Properties.Set(TelemetryUtil.StrategyKey, _keyFormatter(key)); + builder.BuilderName = _builderNameFormatter(key); + builder.Properties.Set(TelemetryUtil.StrategyKey, _strategyKeyFormatter(key)); configure(key, builder); return builder.Build(); }); diff --git a/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs b/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs index f4622488df4..05cd3ac68b9 100644 --- a/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs +++ b/src/Polly.Core/Registry/ResilienceStrategyRegistryOptions.cs @@ -36,8 +36,30 @@ public class ResilienceStrategyRegistryOptions public IEqualityComparer BuilderComparer { get; set; } = EqualityComparer.Default; /// - /// Gets or sets the formatter that is used by the registry to format the keys as a string. + /// Gets or sets the formatter that is used by the registry to format the to a string that + /// represents the strategy key. /// + /// + /// By default, the formatter uses the method. + /// + /// 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. + /// + /// + [Required] + public Func StrategyKeyFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty; + + /// + /// Gets or sets the formatter that is used by the registry to format the to a string that + /// represents the builder name. + /// + /// + /// By default, the formatter uses the method. + /// + /// 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. + /// + /// [Required] - public Func KeyFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty; + public Func BuilderNameFormatter { get; set; } = (key) => key?.ToString() ?? string.Empty; }