mirror of
https://github.com/DuendeSoftware/products
synced 2026-05-24 09:28:24 +00:00
Move to individual incrementer variables over concurrent dictionary
This commit is contained in:
parent
99a456365f
commit
2443eff841
3 changed files with 108 additions and 62 deletions
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright (c) Duende Software. All rights reserved.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
namespace Duende.IdentityServer.Licensing.V2;
|
||||
|
||||
internal class AtomicCounter(int initialCount = 0)
|
||||
{
|
||||
private long _count = initialCount;
|
||||
|
||||
public void Increment() => Interlocked.Increment(ref _count);
|
||||
|
||||
public long Count => _count;
|
||||
}
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
// See LICENSE in the project root for license information.
|
||||
|
||||
#nullable enable
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics.Metrics;
|
||||
using System.Text.Json;
|
||||
using Duende.IdentityServer.Models;
|
||||
|
|
@ -11,21 +10,27 @@ namespace Duende.IdentityServer.Licensing.V2.Diagnostics.DiagnosticEntries;
|
|||
|
||||
internal class TokenIssueCountDiagnosticEntry : IDiagnosticEntry
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, AtomicCounter> _tokenCounts;
|
||||
private long _jwtTokenIssued;
|
||||
private long _referenceTokenIssued;
|
||||
private long _refreshTokenIssued;
|
||||
private long _jwtPoPDPoPTokenIssued;
|
||||
private long _referencePoPDPoPTokenIssued;
|
||||
private long _jwtPoPmTLSTokenIssued;
|
||||
private long _referencePoPmTLSTokenIssued;
|
||||
private long _idTokenIssued;
|
||||
|
||||
private long _implicitGrantTypeFlows;
|
||||
private long _hybridGrantTypeFlows;
|
||||
private long _authorizationCodeGrantTypeFlows;
|
||||
private long _clientCredentialsGrantTypeFlows;
|
||||
private long _resourceOwnerPasswordGrantTypeFlows;
|
||||
private long _deviceFlowGrantTypeFlows;
|
||||
private long _otherGrantTypeFlows;
|
||||
|
||||
private readonly MeterListener _meterListener;
|
||||
|
||||
public TokenIssueCountDiagnosticEntry()
|
||||
{
|
||||
_tokenCounts = new ConcurrentDictionary<string, AtomicCounter>([
|
||||
new("Jwt", new AtomicCounter()),
|
||||
new ("Reference", new AtomicCounter()),
|
||||
new ("Refresh", new AtomicCounter()),
|
||||
new("JwtPoPDPoP", new AtomicCounter()),
|
||||
new("ReferencePoPDPoP", new AtomicCounter()),
|
||||
new("JwtPoPmTLS", new AtomicCounter()),
|
||||
new("ReferencePoPmTLS", new AtomicCounter()),
|
||||
new("Id", new AtomicCounter())
|
||||
]);
|
||||
_meterListener = new MeterListener();
|
||||
|
||||
_meterListener.InstrumentPublished += (instrument, listener) =>
|
||||
|
|
@ -46,10 +51,21 @@ internal class TokenIssueCountDiagnosticEntry : IDiagnosticEntry
|
|||
writer.WritePropertyName("TokenIssueCounts");
|
||||
writer.WriteStartObject();
|
||||
|
||||
foreach (var (tokenType, counter) in _tokenCounts)
|
||||
{
|
||||
writer.WriteNumber(tokenType, counter.Count);
|
||||
}
|
||||
writer.WriteNumber("Jwt", _jwtTokenIssued);
|
||||
writer.WriteNumber("Reference", _referenceTokenIssued);
|
||||
writer.WriteNumber("JwtPoPDPoP", _jwtPoPDPoPTokenIssued);
|
||||
writer.WriteNumber("ReferencePoPDPoP", _referencePoPDPoPTokenIssued);
|
||||
writer.WriteNumber("JwtPoPmTLS", _jwtPoPmTLSTokenIssued);
|
||||
writer.WriteNumber("ReferencePoPmTLS", _referencePoPmTLSTokenIssued);
|
||||
writer.WriteNumber("Refresh", _refreshTokenIssued);
|
||||
writer.WriteNumber("Id", _idTokenIssued);
|
||||
writer.WriteNumber(GrantType.Implicit, _implicitGrantTypeFlows);
|
||||
writer.WriteNumber(GrantType.Hybrid, _hybridGrantTypeFlows);
|
||||
writer.WriteNumber(GrantType.AuthorizationCode, _authorizationCodeGrantTypeFlows);
|
||||
writer.WriteNumber(GrantType.ClientCredentials, _clientCredentialsGrantTypeFlows);
|
||||
writer.WriteNumber(GrantType.ResourceOwnerPassword, _resourceOwnerPasswordGrantTypeFlows);
|
||||
writer.WriteNumber(GrantType.DeviceFlow, _deviceFlowGrantTypeFlows);
|
||||
writer.WriteNumber("Other", _otherGrantTypeFlows);
|
||||
|
||||
writer.WriteEndObject();
|
||||
|
||||
|
|
@ -106,44 +122,65 @@ internal class TokenIssueCountDiagnosticEntry : IDiagnosticEntry
|
|||
switch (proofType)
|
||||
{
|
||||
case ProofType.None when accessTokenType == AccessTokenType.Jwt:
|
||||
_tokenCounts["Jwt"].Increment();
|
||||
Interlocked.Increment(ref _jwtTokenIssued);
|
||||
break;
|
||||
case ProofType.None when accessTokenType == AccessTokenType.Reference:
|
||||
_tokenCounts["Reference"].Increment();
|
||||
Interlocked.Increment(ref _referenceTokenIssued);
|
||||
break;
|
||||
case ProofType.DPoP when accessTokenType == AccessTokenType.Jwt:
|
||||
_tokenCounts["JwtPoPDPoP"].Increment();
|
||||
Interlocked.Increment(ref _jwtPoPDPoPTokenIssued);
|
||||
break;
|
||||
case ProofType.DPoP when accessTokenType == AccessTokenType.Reference:
|
||||
_tokenCounts["ReferencePoPDPoP"].Increment();
|
||||
Interlocked.Increment(ref _referencePoPDPoPTokenIssued);
|
||||
break;
|
||||
case ProofType.ClientCertificate when accessTokenType == AccessTokenType.Jwt:
|
||||
_tokenCounts["JwtPoPmTLS"].Increment();
|
||||
Interlocked.Increment(ref _jwtPoPmTLSTokenIssued);
|
||||
break;
|
||||
case ProofType.ClientCertificate when accessTokenType == AccessTokenType.Reference:
|
||||
_tokenCounts["ReferencePoPmTLS"].Increment();
|
||||
Interlocked.Increment(ref _referencePoPmTLSTokenIssued);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshTokenIssued)
|
||||
{
|
||||
_tokenCounts["Refresh"].Increment();
|
||||
Interlocked.Increment(ref _refreshTokenIssued);
|
||||
}
|
||||
|
||||
if (identityTokenIssued)
|
||||
{
|
||||
_tokenCounts["Id"].Increment();
|
||||
Interlocked.Increment(ref _idTokenIssued);
|
||||
}
|
||||
|
||||
var tokenWasIssued = accessTokenIssued || refreshTokenIssued || identityTokenIssued;
|
||||
if (tokenWasIssued && !string.IsNullOrEmpty(grantType))
|
||||
if (!tokenWasIssued || string.IsNullOrEmpty(grantType))
|
||||
{
|
||||
_tokenCounts.AddOrUpdate(grantType, new AtomicCounter(1), (_, counter) =>
|
||||
{
|
||||
counter.Increment();
|
||||
return counter;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
switch (grantType)
|
||||
{
|
||||
case GrantType.Implicit:
|
||||
Interlocked.Increment(ref _implicitGrantTypeFlows);
|
||||
break;
|
||||
case GrantType.Hybrid:
|
||||
Interlocked.Increment(ref _hybridGrantTypeFlows);
|
||||
break;
|
||||
case GrantType.AuthorizationCode:
|
||||
Interlocked.Increment(ref _authorizationCodeGrantTypeFlows);
|
||||
break;
|
||||
case GrantType.ClientCredentials:
|
||||
Interlocked.Increment(ref _clientCredentialsGrantTypeFlows);
|
||||
break;
|
||||
case GrantType.ResourceOwnerPassword:
|
||||
Interlocked.Increment(ref _resourceOwnerPasswordGrantTypeFlows);
|
||||
break;
|
||||
case GrantType.DeviceFlow:
|
||||
Interlocked.Increment(ref _deviceFlowGrantTypeFlows);
|
||||
break;
|
||||
default:
|
||||
Interlocked.Increment(ref _otherGrantTypeFlows);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) Duende Software. All rights reserved.
|
||||
// See LICENSE in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using Duende.IdentityServer.Licensing.V2.Diagnostics.DiagnosticEntries;
|
||||
using Duende.IdentityServer.Models;
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_JwtAccessToken()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_JwtReferenceToken()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Reference, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Reference, false, ProofType.None, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_JwtDPoPToken()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.DPoP, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.DPoP, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -43,7 +44,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_ReferenceDPoPToken()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Reference, false, ProofType.DPoP, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Reference, false, ProofType.DPoP, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_JwtMTlsToken()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.ClientCertificate, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.ClientCertificate, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -63,7 +64,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_ReferenceMTlsToken()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Reference, false, ProofType.ClientCertificate, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Reference, false, ProofType.ClientCertificate, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -83,7 +84,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Count_IdToken()
|
||||
{
|
||||
IssueToken("authorization_code", false, AccessTokenType.Jwt, false, ProofType.None, true);
|
||||
IssueToken(GrantType.AuthorizationCode, false, AccessTokenType.Jwt, false, ProofType.None, true);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -93,8 +94,8 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Handle_Multiple_Token_Types()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, true, ProofType.None, false);
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.DPoP, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, true, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.DPoP, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -107,7 +108,7 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Handle_No_Token_Issued()
|
||||
{
|
||||
IssueToken("authorization_code", false, null, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, false, null, false, ProofType.None, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
|
|
@ -125,37 +126,58 @@ public class TokenIssueCountDiagnosticEntryTests
|
|||
[Fact]
|
||||
public async Task Should_Handle_Initial_Grant_Type_Count()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
var tokenIssueCounts = result.RootElement.GetProperty("TokenIssueCounts");
|
||||
tokenIssueCounts.GetProperty("authorization_code").GetInt64().ShouldBe(1);
|
||||
tokenIssueCounts.GetProperty(GrantType.AuthorizationCode).GetInt64().ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Handle_Multiple_Grant_Type_Counts()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken("client_credentials", true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken(GrantType.ClientCredentials, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
var tokenIssueCounts = result.RootElement.GetProperty("TokenIssueCounts");
|
||||
tokenIssueCounts.GetProperty("authorization_code").GetInt64().ShouldBe(1);
|
||||
tokenIssueCounts.GetProperty("client_credentials").GetInt64().ShouldBe(1);
|
||||
tokenIssueCounts.GetProperty(GrantType.AuthorizationCode).GetInt64().ShouldBe(1);
|
||||
tokenIssueCounts.GetProperty(GrantType.ClientCredentials).GetInt64().ShouldBe(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Handle_Multiple_Grant_Type_Counts_With_Grant_Type()
|
||||
{
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken("authorization_code", true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
IssueToken(GrantType.AuthorizationCode, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
var tokenIssueCounts = result.RootElement.GetProperty("TokenIssueCounts");
|
||||
tokenIssueCounts.GetProperty("authorization_code").GetInt64().ShouldBe(2);
|
||||
tokenIssueCounts.GetProperty(GrantType.AuthorizationCode).GetInt64().ShouldBe(2);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Should_Handle_Grant_Type_Counts_For_All_Grant_Types()
|
||||
{
|
||||
var grantTypes = typeof(GrantType).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
|
||||
.Where(field => field.IsLiteral && !field.IsInitOnly)
|
||||
.Select(field => field.GetValue(null)?.ToString())
|
||||
.Where(value => value != null);
|
||||
foreach (var grantType in grantTypes)
|
||||
{
|
||||
IssueToken(grantType, true, AccessTokenType.Jwt, false, ProofType.None, false);
|
||||
}
|
||||
|
||||
var result = await DiagnosticEntryTestHelper.WriteEntryToJson(_subject);
|
||||
|
||||
var tokenIssueCounts = result.RootElement.GetProperty("TokenIssueCounts");
|
||||
foreach (var grantType in grantTypes)
|
||||
{
|
||||
tokenIssueCounts.GetProperty(grantType).GetInt64().ShouldBe(1);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
Loading…
Reference in a new issue