diff --git a/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj b/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj
index 22bf430928da..5f13920b61f5 100644
--- a/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj
+++ b/src/Identity/Core/src/Microsoft.AspNetCore.Identity.csproj
@@ -15,6 +15,7 @@
+
diff --git a/src/Identity/Core/src/SignInManager.cs b/src/Identity/Core/src/SignInManager.cs
index 011ba2096b87..2391e36c0e72 100644
--- a/src/Identity/Core/src/SignInManager.cs
+++ b/src/Identity/Core/src/SignInManager.cs
@@ -1,6 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Security.Claims;
@@ -169,15 +170,16 @@ public virtual async Task CanSignInAsync(TUser user)
/// The task object representing the asynchronous operation.
public virtual async Task RefreshSignInAsync(TUser user)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var (success, isPersistent) = await RefreshSignInCoreAsync(user);
var signInResult = success ? SignInResult.Success : SignInResult.Failed;
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, signInResult, SignInType.Refresh, isPersistent);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, signInResult, SignInType.Refresh, isPersistent, startTimestamp);
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.Refresh, isPersistent: null, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.Refresh, isPersistent: null, startTimestamp, ex);
throw;
}
}
@@ -391,6 +393,7 @@ public virtual async Task ValidateSecurityStampAsync(TUser? user, string?
public virtual async Task PasswordSignInAsync(TUser user, string password,
bool isPersistent, bool lockoutOnFailure)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ArgumentNullException.ThrowIfNull(user);
@@ -399,13 +402,13 @@ public virtual async Task PasswordSignInAsync(TUser user, string p
var result = attempt.Succeeded
? await SignInOrTwoFactorAsync(user, isPersistent)
: attempt;
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.Password, isPersistent);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.Password, isPersistent, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.Password, isPersistent, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.Password, isPersistent, startTimestamp, ex);
throw;
}
}
@@ -423,10 +426,11 @@ public virtual async Task PasswordSignInAsync(TUser user, string p
public virtual async Task PasswordSignInAsync(string userName, string password,
bool isPersistent, bool lockoutOnFailure)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
var user = await UserManager.FindByNameAsync(userName);
if (user == null)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, SignInResult.Failed, SignInType.Password, isPersistent);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, SignInResult.Failed, SignInType.Password, isPersistent, startTimestamp);
return SignInResult.Failed;
}
@@ -635,16 +639,17 @@ public virtual async Task> PerformPasskeyAssertion
///
public virtual async Task PasskeySignInAsync(string credentialJson)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await PasskeySignInCoreAsync(credentialJson);
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.Passkey, isPersistent: false);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.Passkey, isPersistent: false, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.Passkey, isPersistent: false, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.Passkey, isPersistent: false, startTimestamp, ex);
throw;
}
}
@@ -787,16 +792,17 @@ public virtual async Task ForgetTwoFactorClientAsync()
///
public virtual async Task TwoFactorRecoveryCodeSignInAsync(string recoveryCode)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await TwoFactorRecoveryCodeSignInCoreAsync(recoveryCode);
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.TwoFactorRecoveryCode, isPersistent: false);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.TwoFactorRecoveryCode, isPersistent: false, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.TwoFactorRecoveryCode, isPersistent: false, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.TwoFactorRecoveryCode, isPersistent: false, startTimestamp, ex);
throw;
}
}
@@ -868,16 +874,17 @@ private async Task DoTwoFactorSignInAsync(TUser user, TwoFactorAut
/// for the sign-in attempt.
public virtual async Task TwoFactorAuthenticatorSignInAsync(string code, bool isPersistent, bool rememberClient)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await TwoFactorAuthenticatorSignInCoreAsync(code, isPersistent, rememberClient);
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.TwoFactorAuthenticator, isPersistent);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.TwoFactorAuthenticator, isPersistent, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.TwoFactorAuthenticator, isPersistent, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.TwoFactorAuthenticator, isPersistent, startTimestamp, ex);
throw;
}
}
@@ -932,16 +939,17 @@ private async Task TwoFactorAuthenticatorSignInCoreAsync(string co
/// for the sign-in attempt.
public virtual async Task TwoFactorSignInAsync(string provider, string code, bool isPersistent, bool rememberClient)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await TwoFactorSignInCoreAsync(provider, code, isPersistent, rememberClient);
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.TwoFactor, isPersistent);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.TwoFactor, isPersistent, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.TwoFactor, isPersistent, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.TwoFactor, isPersistent, startTimestamp, ex);
throw;
}
}
@@ -1021,16 +1029,17 @@ public virtual Task ExternalLoginSignInAsync(string loginProvider,
/// for the sign-in attempt.
public virtual async Task ExternalLoginSignInAsync(string loginProvider, string providerKey, bool isPersistent, bool bypassTwoFactor)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await ExternalLoginSignInCoreAsync(loginProvider, providerKey, isPersistent, bypassTwoFactor);
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.External, isPersistent);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result, SignInType.External, isPersistent, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.External, isPersistent, ex);
+ _metrics?.AuthenticateSignIn(typeof(TUser).FullName!, AuthenticationScheme, result: null, SignInType.External, isPersistent, startTimestamp, ex);
throw;
}
}
diff --git a/src/Identity/Core/src/SignInManagerMetrics.cs b/src/Identity/Core/src/SignInManagerMetrics.cs
index f14c37edf042..f55a37af2895 100644
--- a/src/Identity/Core/src/SignInManagerMetrics.cs
+++ b/src/Identity/Core/src/SignInManagerMetrics.cs
@@ -3,6 +3,8 @@
using System.Diagnostics;
using System.Diagnostics.Metrics;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Identity;
@@ -10,31 +12,55 @@ internal sealed class SignInManagerMetrics : IDisposable
{
public const string MeterName = "Microsoft.AspNetCore.Identity";
- public const string AuthenticateCounterName = "aspnetcore.identity.sign_in.authenticate";
- public const string RememberTwoFactorCounterName = "aspnetcore.identity.sign_in.remember_two_factor";
- public const string ForgetTwoFactorCounterName = "aspnetcore.identity.sign_in.forget_two_factor";
- public const string CheckPasswordCounterName = "aspnetcore.identity.sign_in.check_password";
- public const string SignInUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_in";
- public const string SignOutUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_out";
+ public const string AuthenticateDurationName = "aspnetcore.identity.sign_in.authenticate.duration";
+ public const string RememberedTwoFactorCounterName = "aspnetcore.identity.sign_in.two_factor_clients_remembered";
+ public const string ForgottenTwoFactorCounterName = "aspnetcore.identity.sign_in.two_factor_clients_forgotten";
+ public const string CheckPasswordAttemptsCounterName = "aspnetcore.identity.sign_in.check_password_attempts";
+ public const string SignInsCounterName = "aspnetcore.identity.sign_in.sign_ins";
+ public const string SignOutsCounterName = "aspnetcore.identity.sign_in.sign_outs";
private readonly Meter _meter;
- private readonly Counter _authenticateCounter;
+ private readonly Histogram _authenticateDuration;
private readonly Counter _rememberTwoFactorClientCounter;
private readonly Counter _forgetTwoFactorCounter;
private readonly Counter _checkPasswordCounter;
- private readonly Counter _signInUserPrincipalCounter;
- private readonly Counter _signOutUserPrincipalCounter;
+ private readonly Counter _signInsCounter;
+ private readonly Counter _signOutsCounter;
public SignInManagerMetrics(IMeterFactory meterFactory)
{
_meter = meterFactory.Create(MeterName);
- _authenticateCounter = _meter.CreateCounter(AuthenticateCounterName, "{count}", "The number of authenticate attempts. The authenticate counter is incremented by sign in methods such as PasswordSignInAsync and TwoFactorSignInAsync.");
- _rememberTwoFactorClientCounter = _meter.CreateCounter(RememberTwoFactorCounterName, "{count}", "The number of two factor clients remembered.");
- _forgetTwoFactorCounter = _meter.CreateCounter(ForgetTwoFactorCounterName, "{count}", "The number of two factor clients forgotten.");
- _checkPasswordCounter = _meter.CreateCounter(CheckPasswordCounterName, "{check}", "The number of check password attempts. Checks that the account is in a state that can log in and that the password is valid using the UserManager.CheckPasswordAsync method.");
- _signInUserPrincipalCounter = _meter.CreateCounter(SignInUserPrincipalCounterName, "{sign_in}", "The number of calls to sign in user principals.");
- _signOutUserPrincipalCounter = _meter.CreateCounter(SignOutUserPrincipalCounterName, "{sign_out}", "The number of calls to sign out user principals.");
+ _authenticateDuration = _meter.CreateHistogram(
+ AuthenticateDurationName,
+ unit: "s",
+ description: "The duration of authenticate attempts. The authenticate metrics is recorded by sign in methods such as PasswordSignInAsync and TwoFactorSignInAsync.",
+ advice: new() { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
+
+ _rememberTwoFactorClientCounter = _meter.CreateCounter(
+ RememberedTwoFactorCounterName,
+ unit: "{client}",
+ description: "The total number of two factor clients remembered.");
+
+ _forgetTwoFactorCounter = _meter.CreateCounter(
+ ForgottenTwoFactorCounterName,
+ unit: "{client}",
+ description: "The total number of two factor clients forgotten.");
+
+ _checkPasswordCounter = _meter.CreateCounter(
+ CheckPasswordAttemptsCounterName,
+ unit: "{attempt}",
+ description: "The total number of check password attempts. Checks that the account is in a state that can log in and that the password is valid using the UserManager.CheckPasswordAsync method.");
+
+ _signInsCounter = _meter.CreateCounter(
+ SignInsCounterName,
+ unit: "{sign_in}",
+ description: "The total number of calls to sign in user principals.");
+
+ _signOutsCounter = _meter.CreateCounter(
+ SignOutsCounterName,
+ unit: "{sign_out}",
+ description: "The total number of calls to sign out user principals.");
}
internal void CheckPasswordSignIn(string userType, SignInResult? result, Exception? exception = null)
@@ -54,9 +80,9 @@ internal void CheckPasswordSignIn(string userType, SignInResult? result, Excepti
_checkPasswordCounter.Add(1, tags);
}
- internal void AuthenticateSignIn(string userType, string authenticationScheme, SignInResult? result, SignInType signInType, bool? isPersistent, Exception? exception = null)
+ internal void AuthenticateSignIn(string userType, string authenticationScheme, SignInResult? result, SignInType signInType, bool? isPersistent, long startTimestamp, Exception? exception = null)
{
- if (!_authenticateCounter.Enabled)
+ if (!_authenticateDuration.Enabled)
{
return;
}
@@ -64,19 +90,20 @@ internal void AuthenticateSignIn(string userType, string authenticationScheme, S
var tags = new TagList
{
{ "aspnetcore.identity.user_type", userType },
- { "aspnetcore.identity.authentication_scheme", authenticationScheme },
+ { "aspnetcore.authentication.scheme", authenticationScheme },
{ "aspnetcore.identity.sign_in.type", GetSignInType(signInType) },
};
AddIsPersistent(ref tags, isPersistent);
AddSignInResult(ref tags, result);
AddErrorTag(ref tags, exception);
- _authenticateCounter.Add(1, tags);
+ var duration = ValueStopwatch.GetElapsedTime(startTimestamp, Stopwatch.GetTimestamp());
+ _authenticateDuration.Record(duration.TotalSeconds, tags);
}
internal void SignInUserPrincipal(string userType, string authenticationScheme, bool? isPersistent, Exception? exception = null)
{
- if (!_signInUserPrincipalCounter.Enabled)
+ if (!_signInsCounter.Enabled)
{
return;
}
@@ -84,17 +111,17 @@ internal void SignInUserPrincipal(string userType, string authenticationScheme,
var tags = new TagList
{
{ "aspnetcore.identity.user_type", userType },
- { "aspnetcore.identity.authentication_scheme", authenticationScheme },
+ { "aspnetcore.authentication.scheme", authenticationScheme },
};
AddIsPersistent(ref tags, isPersistent);
AddErrorTag(ref tags, exception);
- _signInUserPrincipalCounter.Add(1, tags);
+ _signInsCounter.Add(1, tags);
}
internal void SignOutUserPrincipal(string userType, string authenticationScheme, Exception? exception = null)
{
- if (!_signOutUserPrincipalCounter.Enabled)
+ if (!_signOutsCounter.Enabled)
{
return;
}
@@ -102,11 +129,11 @@ internal void SignOutUserPrincipal(string userType, string authenticationScheme,
var tags = new TagList
{
{ "aspnetcore.identity.user_type", userType },
- { "aspnetcore.identity.authentication_scheme", authenticationScheme },
+ { "aspnetcore.authentication.scheme", authenticationScheme },
};
AddErrorTag(ref tags, exception);
- _signOutUserPrincipalCounter.Add(1, tags);
+ _signOutsCounter.Add(1, tags);
}
internal void RememberTwoFactorClient(string userType, string authenticationScheme, Exception? exception = null)
@@ -119,7 +146,7 @@ internal void RememberTwoFactorClient(string userType, string authenticationSche
var tags = new TagList
{
{ "aspnetcore.identity.user_type", userType },
- { "aspnetcore.identity.authentication_scheme", authenticationScheme }
+ { "aspnetcore.authentication.scheme", authenticationScheme }
};
AddErrorTag(ref tags, exception);
@@ -136,7 +163,7 @@ internal void ForgetTwoFactorClient(string userType, string authenticationScheme
var tags = new TagList
{
{ "aspnetcore.identity.user_type", userType },
- { "aspnetcore.identity.authentication_scheme", authenticationScheme }
+ { "aspnetcore.authentication.scheme", authenticationScheme }
};
AddErrorTag(ref tags, exception);
@@ -152,7 +179,7 @@ private static void AddIsPersistent(ref TagList tags, bool? isPersistent)
{
if (isPersistent != null)
{
- tags.Add("aspnetcore.identity.sign_in.is_persistent", isPersistent.Value);
+ tags.Add("aspnetcore.authentication.is_persistent", isPersistent.Value);
}
}
diff --git a/src/Identity/Extensions.Core/src/Microsoft.Extensions.Identity.Core.csproj b/src/Identity/Extensions.Core/src/Microsoft.Extensions.Identity.Core.csproj
index a1315dd79254..538396395fc3 100644
--- a/src/Identity/Extensions.Core/src/Microsoft.Extensions.Identity.Core.csproj
+++ b/src/Identity/Extensions.Core/src/Microsoft.Extensions.Identity.Core.csproj
@@ -15,7 +15,9 @@
+
+
diff --git a/src/Identity/Extensions.Core/src/UserManager.cs b/src/Identity/Extensions.Core/src/UserManager.cs
index 073b36e9c426..e184534b41ce 100644
--- a/src/Identity/Extensions.Core/src/UserManager.cs
+++ b/src/Identity/Extensions.Core/src/UserManager.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
@@ -481,15 +482,17 @@ public virtual Task GenerateConcurrencyStampAsync(TUser user)
///
public virtual async Task CreateAsync(TUser user)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
+
try
{
var result = await CreateCoreAsync(user).ConfigureAwait(false);
- _metrics?.CreateUser(typeof(TUser).FullName!, result);
+ _metrics?.CreateUser(typeof(TUser).FullName!, result, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.CreateUser(typeof(TUser).FullName!, result: null, ex);
+ _metrics?.CreateUser(typeof(TUser).FullName!, result: null, startTimeStamp, ex);
throw;
}
}
@@ -523,16 +526,18 @@ private async Task CreateCoreAsync(TUser user)
///
public virtual async Task UpdateAsync(TUser user)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
+
try
{
ThrowIfDisposed();
ArgumentNullThrowHelper.ThrowIfNull(user);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.Update).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.Update, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.Update, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.Update, startTimeStamp, ex);
throw;
}
}
@@ -547,19 +552,21 @@ public virtual async Task UpdateAsync(TUser user)
///
public virtual async Task DeleteAsync(TUser user)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
+
try
{
ThrowIfDisposed();
ArgumentNullThrowHelper.ThrowIfNull(user);
var result = await Store.DeleteAsync(user, CancellationToken).ConfigureAwait(false);
- _metrics?.DeleteUser(typeof(TUser).FullName!, result);
+ _metrics?.DeleteUser(typeof(TUser).FullName!, result, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.DeleteUser(typeof(TUser).FullName!, result: null, ex);
+ _metrics?.DeleteUser(typeof(TUser).FullName!, result: null, startTimeStamp, ex);
throw;
}
}
@@ -625,6 +632,8 @@ public virtual async Task DeleteAsync(TUser user)
///
public virtual async Task CreateAsync(TUser user, string password)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
+
try
{
ThrowIfDisposed();
@@ -634,13 +643,13 @@ public virtual async Task CreateAsync(TUser user, string passwor
var result = await UpdatePasswordHash(passwordStore, user, password).ConfigureAwait(false);
if (!result.Succeeded)
{
- _metrics?.CreateUser(typeof(TUser).FullName!, result);
+ _metrics?.CreateUser(typeof(TUser).FullName!, result, startTimeStamp);
return result;
}
}
catch (Exception ex)
{
- _metrics?.CreateUser(typeof(TUser).FullName!, result: null, ex);
+ _metrics?.CreateUser(typeof(TUser).FullName!, result: null, startTimeStamp, ex);
throw;
}
@@ -710,6 +719,7 @@ public virtual async Task UpdateNormalizedUserNameAsync(TUser user)
/// The that represents the asynchronous operation.
public virtual async Task SetUserNameAsync(TUser user, string? userName)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -717,11 +727,11 @@ public virtual async Task SetUserNameAsync(TUser user, string? u
await Store.SetUserNameAsync(user, userName, CancellationToken).ConfigureAwait(false);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.UserName).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetUserName, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.UserName, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetUserName, startTimeStamp, ex);
throw;
}
}
@@ -781,8 +791,9 @@ public virtual async Task CheckPasswordAsync(TUser user, string password)
if (result == PasswordVerificationResult.SuccessRehashNeeded)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
await UpdatePasswordHash(passwordStore, user, password, validatePassword: false).ConfigureAwait(false);
- await UpdateUserAndRecordMetricAsync(user, UserUpdateType.PasswordRehash).ConfigureAwait(false);
+ await UpdateUserAndRecordMetricAsync(user, UserUpdateType.PasswordRehash, startTimeStamp).ConfigureAwait(false);
}
return (result, false);
@@ -817,15 +828,16 @@ public virtual Task HasPasswordAsync(TUser user)
///
public virtual async Task AddPasswordAsync(TUser user, string password)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await AddPasswordCoreAsync(user, password).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddPassword);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddPassword, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddPassword, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddPassword, startTimeStamp, ex);
throw;
}
}
@@ -863,15 +875,16 @@ private async Task AddPasswordCoreAsync(TUser user, string passw
///
public virtual async Task ChangePasswordAsync(TUser user, string currentPassword, string newPassword)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await ChangePasswordCoreAsync(user, currentPassword, newPassword).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ChangePassword);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ChangePassword, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ChangePassword, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ChangePassword, startTimeStamp, ex);
throw;
}
}
@@ -905,6 +918,7 @@ private async Task ChangePasswordCoreAsync(TUser user, string cu
///
public virtual async Task RemovePasswordAsync(TUser user)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -912,11 +926,11 @@ public virtual async Task RemovePasswordAsync(TUser user)
ArgumentNullThrowHelper.ThrowIfNull(user);
await UpdatePasswordHash(passwordStore, user, null, validatePassword: false).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemovePassword).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemovePassword, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemovePassword, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemovePassword, startTimeStamp, ex);
throw;
}
}
@@ -975,6 +989,7 @@ public virtual async Task GetSecurityStampAsync(TUser user)
///
public virtual async Task UpdateSecurityStampAsync(TUser user)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -982,11 +997,11 @@ public virtual async Task UpdateSecurityStampAsync(TUser user)
ArgumentNullThrowHelper.ThrowIfNull(user);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SecurityStamp).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.UpdateSecurityStamp, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SecurityStamp, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.UpdateSecurityStamp, startTimeStamp, ex);
throw;
}
}
@@ -1017,6 +1032,8 @@ public virtual Task GeneratePasswordResetTokenAsync(TUser user)
///
public virtual async Task ResetPasswordAsync(TUser user, string token, string newPassword)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
+
ThrowIfDisposed();
ArgumentNullThrowHelper.ThrowIfNull(user);
@@ -1024,17 +1041,17 @@ public virtual async Task ResetPasswordAsync(TUser user, string
if (!await VerifyUserTokenAsync(user, Options.Tokens.PasswordResetTokenProvider, ResetPasswordTokenPurpose, token).ConfigureAwait(false))
{
var failureResult = IdentityResult.Failed(ErrorDescriber.InvalidToken());
- _metrics?.UpdateUser(typeof(TUser).FullName!, failureResult, UserUpdateType.ResetPassword);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, failureResult, UserUpdateType.ResetPassword, startTimeStamp);
return failureResult;
}
var result = await UpdatePasswordHash(user, newPassword, validatePassword: true).ConfigureAwait(false);
if (!result.Succeeded)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ResetPassword);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ResetPassword, startTimeStamp);
return result;
}
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ResetPassword).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ResetPassword, startTimeStamp).ConfigureAwait(false);
}
///
@@ -1067,6 +1084,7 @@ public virtual async Task ResetPasswordAsync(TUser user, string
///
public virtual async Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -1077,11 +1095,11 @@ public virtual async Task RemoveLoginAsync(TUser user, string lo
await loginStore.RemoveLoginAsync(user, loginProvider, providerKey, CancellationToken).ConfigureAwait(false);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveLogin).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveLogin, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveLogin, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveLogin, startTimeStamp, ex);
throw;
}
}
@@ -1097,15 +1115,16 @@ public virtual async Task RemoveLoginAsync(TUser user, string lo
///
public virtual async Task AddLoginAsync(TUser user, UserLoginInfo login)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await AddLoginCoreAsync(user, login).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddLogin);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddLogin, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddLogin, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddLogin, startTimeStamp, ex);
throw;
}
}
@@ -1167,6 +1186,7 @@ public virtual Task AddClaimAsync(TUser user, Claim claim)
///
public virtual async Task AddClaimsAsync(TUser user, IEnumerable claims)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -1175,11 +1195,11 @@ public virtual async Task AddClaimsAsync(TUser user, IEnumerable
ArgumentNullThrowHelper.ThrowIfNull(claims);
await claimStore.AddClaimsAsync(user, claims, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.AddClaims).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.AddClaims, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddClaims, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddClaims, startTimeStamp, ex);
throw;
}
}
@@ -1196,6 +1216,7 @@ public virtual async Task AddClaimsAsync(TUser user, IEnumerable
///
public virtual async Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -1205,11 +1226,11 @@ public virtual async Task ReplaceClaimAsync(TUser user, Claim cl
ArgumentNullThrowHelper.ThrowIfNull(newClaim);
await claimStore.ReplaceClaimAsync(user, claim, newClaim, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ReplaceClaim).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ReplaceClaim, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ReplaceClaim, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ReplaceClaim, startTimeStamp, ex);
throw;
}
}
@@ -1239,6 +1260,7 @@ public virtual Task RemoveClaimAsync(TUser user, Claim claim)
///
public virtual async Task RemoveClaimsAsync(TUser user, IEnumerable claims)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -1247,11 +1269,11 @@ public virtual async Task RemoveClaimsAsync(TUser user, IEnumera
ArgumentNullThrowHelper.ThrowIfNull(claims);
await claimStore.RemoveClaimsAsync(user, claims, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveClaims).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveClaims, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveClaims, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveClaims, startTimeStamp, ex);
throw;
}
}
@@ -1282,15 +1304,16 @@ public virtual async Task> GetClaimsAsync(TUser user)
///
public virtual async Task AddToRoleAsync(TUser user, string role)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await AddToRoleCoreAsync(user, role).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddToRoles);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddToRoles, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddToRoles, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddToRoles, startTimeStamp, ex);
throw;
}
}
@@ -1321,15 +1344,16 @@ private async Task AddToRoleCoreAsync(TUser user, string role)
///
public virtual async Task AddToRolesAsync(TUser user, IEnumerable roles)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await AddToRolesCoreAsync(user, roles).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddToRoles);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddToRoles, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddToRoles, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddToRoles, startTimeStamp, ex);
throw;
}
}
@@ -1364,6 +1388,8 @@ private async Task AddToRolesCoreAsync(TUser user, IEnumerable
public virtual async Task RemoveFromRoleAsync(TUser user, string role)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
+
ThrowIfDisposed();
var userRoleStore = GetUserRoleStore();
ArgumentNullThrowHelper.ThrowIfNull(user);
@@ -1372,12 +1398,12 @@ public virtual async Task RemoveFromRoleAsync(TUser user, string
if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken).ConfigureAwait(false))
{
var failureResult = UserNotInRoleError(role);
- _metrics?.UpdateUser(typeof(TUser).FullName!, failureResult, UserUpdateType.RemoveFromRoles);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, failureResult, UserUpdateType.RemoveFromRoles, startTimeStamp);
return failureResult;
}
await userRoleStore.RemoveFromRoleAsync(user, normalizedRole, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveFromRoles).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveFromRoles, startTimeStamp).ConfigureAwait(false);
}
private IdentityResult UserAlreadyInRoleError(string role)
@@ -1409,15 +1435,16 @@ private IdentityResult UserNotInRoleError(string role)
///
public virtual async Task RemoveFromRolesAsync(TUser user, IEnumerable roles)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await RemoveFromRolesCoreAsync(user, roles).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.RemoveFromRoles);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.RemoveFromRoles, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveFromRoles, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveFromRoles, startTimeStamp, ex);
throw;
}
}
@@ -1495,6 +1522,7 @@ public virtual async Task IsInRoleAsync(TUser user, string role)
///
public virtual async Task SetEmailAsync(TUser user, string? email)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -1504,11 +1532,11 @@ public virtual async Task SetEmailAsync(TUser user, string? emai
await store.SetEmailAsync(user, email, CancellationToken).ConfigureAwait(false);
await store.SetEmailConfirmedAsync(user, false, CancellationToken).ConfigureAwait(false);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetEmail).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetEmail, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetEmail, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetEmail, startTimeStamp, ex);
throw;
}
}
@@ -1591,15 +1619,16 @@ public virtual Task GenerateEmailConfirmationTokenAsync(TUser user)
///
public virtual async Task ConfirmEmailAsync(TUser user, string token)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
var result = await ConfirmEmailCoreAsync(user, token).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ConfirmEmail);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ConfirmEmail, startTimeStamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ConfirmEmail, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ConfirmEmail, startTimeStamp, ex);
throw;
}
}
@@ -1661,20 +1690,19 @@ public virtual Task GenerateChangeEmailTokenAsync(TUser user, string new
///
public virtual async Task ChangeEmailAsync(TUser user, string newEmail, string token)
{
+ var startTimeStamp = Stopwatch.GetTimestamp();
try
{
- var result = await ChangeEmailCoreAsync(user, newEmail, token).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ChangeEmail);
- return result;
+ return await ChangeEmailCoreAsync(user, newEmail, token, startTimeStamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ChangeEmail, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ChangeEmail, startTimeStamp, ex);
throw;
}
}
- private async Task ChangeEmailCoreAsync(TUser user, string newEmail, string token)
+ private async Task ChangeEmailCoreAsync(TUser user, string newEmail, string token, long startTimestamp)
{
ThrowIfDisposed();
ArgumentNullThrowHelper.ThrowIfNull(user);
@@ -1688,7 +1716,7 @@ private async Task ChangeEmailCoreAsync(TUser user, string newEm
await store.SetEmailAsync(user, newEmail, CancellationToken).ConfigureAwait(false);
await store.SetEmailConfirmedAsync(user, true, CancellationToken).ConfigureAwait(false);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ChangeEmail).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ChangeEmail, startTimestamp).ConfigureAwait(false);
}
///
@@ -1715,6 +1743,7 @@ private async Task ChangeEmailCoreAsync(TUser user, string newEm
///
public virtual async Task SetPhoneNumberAsync(TUser user, string? phoneNumber)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -1724,11 +1753,11 @@ public virtual async Task SetPhoneNumberAsync(TUser user, string
await store.SetPhoneNumberAsync(user, phoneNumber, CancellationToken).ConfigureAwait(false);
await store.SetPhoneNumberConfirmedAsync(user, false, CancellationToken).ConfigureAwait(false);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetPhoneNumber).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetPhoneNumber, startTimestamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetPhoneNumber, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetPhoneNumber, startTimestamp, ex);
throw;
}
}
@@ -1746,15 +1775,16 @@ public virtual async Task SetPhoneNumberAsync(TUser user, string
///
public virtual async Task ChangePhoneNumberAsync(TUser user, string phoneNumber, string token)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await ChangePhoneNumberCoreAsync(user, phoneNumber, token).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ChangePhoneNumber);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ChangePhoneNumber, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ChangePhoneNumber, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ChangePhoneNumber, startTimestamp, ex);
throw;
}
}
@@ -2031,6 +2061,7 @@ public virtual async Task GetTwoFactorEnabledAsync(TUser user)
///
public virtual async Task SetTwoFactorEnabledAsync(TUser user, bool enabled)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -2039,11 +2070,11 @@ public virtual async Task SetTwoFactorEnabledAsync(TUser user, b
await store.SetTwoFactorEnabledAsync(user, enabled, CancellationToken).ConfigureAwait(false);
await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetTwoFactorEnabled).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetTwoFactorEnabled, startTimestamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetTwoFactorEnabled, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetTwoFactorEnabled, startTimestamp, ex);
throw;
}
}
@@ -2081,6 +2112,7 @@ public virtual async Task IsLockedOutAsync(TUser user)
///
public virtual async Task SetLockoutEnabledAsync(TUser user, bool enabled)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -2088,11 +2120,11 @@ public virtual async Task SetLockoutEnabledAsync(TUser user, boo
ArgumentNullThrowHelper.ThrowIfNull(user);
await store.SetLockoutEnabledAsync(user, enabled, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetLockoutEnabled).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetLockoutEnabled, startTimestamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetLockoutEnabled, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetLockoutEnabled, startTimestamp, ex);
throw;
}
}
@@ -2136,15 +2168,16 @@ public virtual async Task GetLockoutEnabledAsync(TUser user)
/// The that represents the asynchronous operation, containing the of the operation.
public virtual async Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await SetLockoutEndDateCoreAsync(user, lockoutEnd).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.SetLockoutEndDate);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.SetLockoutEndDate, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetLockoutEndDate, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetLockoutEndDate, startTimestamp, ex);
throw;
}
}
@@ -2173,6 +2206,7 @@ private async Task SetLockoutEndDateCoreAsync(TUser user, DateTi
/// The that represents the asynchronous operation, containing the of the operation.
public virtual async Task AccessFailedAsync(TUser user)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -2183,17 +2217,17 @@ public virtual async Task AccessFailedAsync(TUser user)
var count = await store.IncrementAccessFailedCountAsync(user, CancellationToken).ConfigureAwait(false);
if (count < Options.Lockout.MaxFailedAccessAttempts)
{
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.AccessFailed).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.IncrementAccessFailed, startTimestamp).ConfigureAwait(false);
}
Logger.LogDebug(LoggerEventIds.UserLockedOut, "User is locked out.");
await store.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(Options.Lockout.DefaultLockoutTimeSpan),
CancellationToken).ConfigureAwait(false);
await store.ResetAccessFailedCountAsync(user, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.AccessFailed).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.IncrementAccessFailed, startTimestamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AccessFailed, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.IncrementAccessFailed, startTimestamp, ex);
throw;
}
}
@@ -2205,15 +2239,16 @@ await store.SetLockoutEndDateAsync(user, DateTimeOffset.UtcNow.Add(Options.Locko
/// The that represents the asynchronous operation, containing the of the operation.
public virtual async Task ResetAccessFailedCountAsync(TUser user)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await ResetAccessFailedCountCoreAsync(user).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ResetAccessFailedCount);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.ResetAccessFailedCount, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ResetAccessFailedCount, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ResetAccessFailedCount, startTimestamp, ex);
throw;
}
}
@@ -2307,6 +2342,7 @@ public virtual Task> GetUsersInRoleAsync(string roleName)
/// Whether the user was successfully updated.
public virtual async Task SetAuthenticationTokenAsync(TUser user, string loginProvider, string tokenName, string? tokenValue)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -2317,11 +2353,11 @@ public virtual async Task SetAuthenticationTokenAsync(TUser user
// REVIEW: should updating any tokens affect the security stamp?
await store.SetTokenAsync(user, loginProvider, tokenName, tokenValue, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetAuthenticationToken).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.SetAuthenticationToken, startTimestamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetAuthenticationToken, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.SetAuthenticationToken, startTimestamp, ex);
throw;
}
}
@@ -2335,6 +2371,7 @@ public virtual async Task SetAuthenticationTokenAsync(TUser user
/// Whether a token was removed.
public virtual async Task RemoveAuthenticationTokenAsync(TUser user, string loginProvider, string tokenName)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -2344,11 +2381,11 @@ public virtual async Task RemoveAuthenticationTokenAsync(TUser u
ArgumentNullThrowHelper.ThrowIfNull(tokenName);
await store.RemoveTokenAsync(user, loginProvider, tokenName, CancellationToken).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveAuthenticationToken).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.RemoveAuthenticationToken, startTimestamp).ConfigureAwait(false);
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveAuthenticationToken, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemoveAuthenticationToken, startTimestamp, ex);
throw;
}
}
@@ -2373,12 +2410,21 @@ public virtual async Task RemoveAuthenticationTokenAsync(TUser u
/// Whether the user was successfully updated.
public virtual async Task ResetAuthenticatorKeyAsync(TUser user)
{
- ThrowIfDisposed();
- var store = GetAuthenticatorKeyStore();
- ArgumentNullThrowHelper.ThrowIfNull(user);
- await store.SetAuthenticatorKeyAsync(user, GenerateNewAuthenticatorKey(), CancellationToken).ConfigureAwait(false);
- await UpdateSecurityStampInternal(user).ConfigureAwait(false);
- return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ResetAuthenticatorKey).ConfigureAwait(false);
+ var startTimestamp = Stopwatch.GetTimestamp();
+ try
+ {
+ ThrowIfDisposed();
+ var store = GetAuthenticatorKeyStore();
+ ArgumentNullThrowHelper.ThrowIfNull(user);
+ await store.SetAuthenticatorKeyAsync(user, GenerateNewAuthenticatorKey(), CancellationToken).ConfigureAwait(false);
+ await UpdateSecurityStampInternal(user).ConfigureAwait(false);
+ return await UpdateUserAndRecordMetricAsync(user, UserUpdateType.ResetAuthenticatorKey, startTimestamp).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.ResetAuthenticatorKey, startTimestamp, ex);
+ throw;
+ }
}
///
@@ -2396,6 +2442,7 @@ public virtual string GenerateNewAuthenticatorKey()
/// The new recovery codes for the user. Note: there may be less than number returned, as duplicates will be removed.
public virtual async Task?> GenerateNewTwoFactorRecoveryCodesAsync(TUser user, int number)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
ThrowIfDisposed();
@@ -2409,7 +2456,7 @@ public virtual string GenerateNewAuthenticatorKey()
}
await store.ReplaceCodesAsync(user, newCodes.Distinct(), CancellationToken).ConfigureAwait(false);
- var update = await UpdateUserAndRecordMetricAsync(user, UserUpdateType.GenerateNewTwoFactorRecoveryCodes).ConfigureAwait(false);
+ var update = await UpdateUserAndRecordMetricAsync(user, UserUpdateType.GenerateNewTwoFactorRecoveryCodes, startTimestamp).ConfigureAwait(false);
if (update.Succeeded)
{
return newCodes;
@@ -2418,7 +2465,7 @@ public virtual string GenerateNewAuthenticatorKey()
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.GenerateNewTwoFactorRecoveryCodes, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.GenerateNewTwoFactorRecoveryCodes, startTimestamp, ex);
throw;
}
}
@@ -2508,15 +2555,16 @@ private static char GetRandomRecoveryCodeChar()
/// True if the recovery code was found for the user.
public virtual async Task RedeemTwoFactorRecoveryCodeAsync(TUser user, string code)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await RedeemTwoFactorRecoveryCodeCoreAsync(user, code).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.RedeemTwoFactorRecoveryCode);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.RedeemTwoFactorRecoveryCode, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RedeemTwoFactorRecoveryCode, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RedeemTwoFactorRecoveryCode, startTimestamp, ex);
throw;
}
}
@@ -2557,15 +2605,16 @@ public virtual Task CountRecoveryCodesAsync(TUser user)
/// Whether the passkey was successfully set.
public virtual async Task AddOrUpdatePasskeyAsync(TUser user, UserPasskeyInfo passkey)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await AddOrUpdatePasskeyCoreAsync(user, passkey).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddOrUpdatePasskey);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.AddOrUpdatePasskey, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddOrUpdatePasskey, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.AddOrUpdatePasskey, startTimestamp, ex);
throw;
}
}
@@ -2642,15 +2691,16 @@ public virtual Task> GetPasskeysAsync(TUser user)
///
public virtual async Task RemovePasskeyAsync(TUser user, byte[] credentialId)
{
+ var startTimestamp = Stopwatch.GetTimestamp();
try
{
var result = await RemovePasskeyCoreAsync(user, credentialId).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.RemovePasskey);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, UserUpdateType.RemovePasskey, startTimestamp);
return result;
}
catch (Exception ex)
{
- _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemovePasskey, ex);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result: null, UserUpdateType.RemovePasskey, startTimestamp, ex);
throw;
}
}
@@ -2922,10 +2972,10 @@ protected virtual async Task UpdateUserAsync(TUser user)
return await Store.UpdateAsync(user, CancellationToken).ConfigureAwait(false);
}
- private async Task UpdateUserAndRecordMetricAsync(TUser user, UserUpdateType updateType)
+ private async Task UpdateUserAndRecordMetricAsync(TUser user, UserUpdateType updateType, long startTimestamp)
{
var result = await UpdateUserAsync(user).ConfigureAwait(false);
- _metrics?.UpdateUser(typeof(TUser).FullName!, result, updateType);
+ _metrics?.UpdateUser(typeof(TUser).FullName!, result, updateType, startTimestamp);
return result;
}
diff --git a/src/Identity/Extensions.Core/src/UserManagerMetrics.cs b/src/Identity/Extensions.Core/src/UserManagerMetrics.cs
index 54c0f9f6a016..b54b24887a2c 100644
--- a/src/Identity/Extensions.Core/src/UserManagerMetrics.cs
+++ b/src/Identity/Extensions.Core/src/UserManagerMetrics.cs
@@ -6,6 +6,8 @@
using System.Diagnostics.Metrics;
using System.Linq;
using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Internal;
using static Microsoft.AspNetCore.Identity.UserManagerMetrics;
namespace Microsoft.AspNetCore.Identity;
@@ -14,35 +16,62 @@ internal sealed class UserManagerMetrics : IDisposable
{
public const string MeterName = "Microsoft.AspNetCore.Identity";
- public const string CreateCounterName = "aspnetcore.identity.user.create";
- public const string UpdateCounterName = "aspnetcore.identity.user.update";
- public const string DeleteCounterName = "aspnetcore.identity.user.delete";
- public const string CheckPasswordCounterName = "aspnetcore.identity.user.check_password";
- public const string VerifyTokenCounterName = "aspnetcore.identity.user.verify_token";
- public const string GenerateTokenCounterName = "aspnetcore.identity.user.generate_token";
+ public const string CreateDurationName = "aspnetcore.identity.user.create.duration";
+ public const string UpdateDurationName = "aspnetcore.identity.user.update.duration";
+ public const string DeleteDurationName = "aspnetcore.identity.user.delete.duration";
+ public const string CheckPasswordAttemptsCounterName = "aspnetcore.identity.user.check_password_attempts";
+ public const string VerifyTokenAttemptsCounterName = "aspnetcore.identity.user.verify_token_attempts";
+ public const string GenerateTokensCounterName = "aspnetcore.identity.user.generated_tokens";
private readonly Meter _meter;
- private readonly Counter _createCounter;
- private readonly Counter _updateCounter;
- private readonly Counter _deleteCounter;
- private readonly Counter _checkPasswordCounter;
- private readonly Counter _verifyTokenCounter;
- private readonly Counter _generateTokenCounter;
+ private readonly Histogram _createDuration;
+ private readonly Histogram _updateDuration;
+ private readonly Histogram _deleteDuration;
+ private readonly Counter _checkPasswordAttemptsCounter;
+ private readonly Counter _verifyTokenAttemptsCounter;
+ private readonly Counter _generateTokensCounter;
public UserManagerMetrics(IMeterFactory meterFactory)
{
_meter = meterFactory.Create(MeterName);
- _createCounter = _meter.CreateCounter(CreateCounterName, "{user}", "The number of users created.");
- _updateCounter = _meter.CreateCounter(UpdateCounterName, "{user}", "The number of users updated.");
- _deleteCounter = _meter.CreateCounter(DeleteCounterName, "{user}", "The number of users deleted.");
- _checkPasswordCounter = _meter.CreateCounter(CheckPasswordCounterName, "{check}", "The number of check password attempts. Only checks whether the password is valid and not whether the user account is in a state that can log in.");
- _verifyTokenCounter = _meter.CreateCounter(VerifyTokenCounterName, "{count}", "The number of token verification attempts.");
- _generateTokenCounter = _meter.CreateCounter(GenerateTokenCounterName, "{count}", "The number of token generation attempts.");
+
+ _createDuration = _meter.CreateHistogram(
+ CreateDurationName,
+ unit: "s",
+ description: "The duration of user creation operations.",
+ advice: new() { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
+
+ _updateDuration = _meter.CreateHistogram(
+ UpdateDurationName,
+ unit: "s",
+ description: "The duration of user update operations.",
+ advice: new() { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
+
+ _deleteDuration = _meter.CreateHistogram(
+ DeleteDurationName,
+ unit: "s",
+ description: "The duration of user deletion operations.",
+ advice: new() { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
+
+ _checkPasswordAttemptsCounter = _meter.CreateCounter(
+ CheckPasswordAttemptsCounterName,
+ unit: "{attempt}",
+ description: "The total number of check password attempts. Only checks whether the password is valid and not whether the user account is in a state that can log in.");
+
+ _verifyTokenAttemptsCounter = _meter.CreateCounter(
+ VerifyTokenAttemptsCounterName,
+ unit: "{attempt}",
+ description: "The total number of token verification attempts.");
+
+ _generateTokensCounter = _meter.CreateCounter(
+ GenerateTokensCounterName,
+ unit: "{count}",
+ description: "The total number of token generations.");
}
- internal void CreateUser(string userType, IdentityResult? result, Exception? exception = null)
+ internal void CreateUser(string userType, IdentityResult? result, long startTimestamp, Exception? exception = null)
{
- if (!_createCounter.Enabled)
+ if (!_createDuration.Enabled)
{
return;
}
@@ -54,12 +83,13 @@ internal void CreateUser(string userType, IdentityResult? result, Exception? exc
AddIdentityResultTags(ref tags, result);
AddErrorTag(ref tags, exception, result: result);
- _createCounter.Add(1, tags);
+ var duration = GetElapsedTime(startTimestamp);
+ _createDuration.Record(duration.TotalSeconds, tags);
}
- internal void UpdateUser(string userType, IdentityResult? result, UserUpdateType updateType, Exception? exception = null)
+ internal void UpdateUser(string userType, IdentityResult? result, UserUpdateType updateType, long startTimestamp, Exception? exception = null)
{
- if (!_updateCounter.Enabled)
+ if (!_updateDuration.Enabled)
{
return;
}
@@ -72,12 +102,13 @@ internal void UpdateUser(string userType, IdentityResult? result, UserUpdateType
AddIdentityResultTags(ref tags, result);
AddErrorTag(ref tags, exception, result: result);
- _updateCounter.Add(1, tags);
+ var duration = GetElapsedTime(startTimestamp);
+ _updateDuration.Record(duration.TotalSeconds, tags);
}
- internal void DeleteUser(string userType, IdentityResult? result, Exception? exception = null)
+ internal void DeleteUser(string userType, IdentityResult? result, long startTimestamp, Exception? exception = null)
{
- if (!_deleteCounter.Enabled)
+ if (!_deleteDuration.Enabled)
{
return;
}
@@ -89,12 +120,13 @@ internal void DeleteUser(string userType, IdentityResult? result, Exception? exc
AddIdentityResultTags(ref tags, result);
AddErrorTag(ref tags, exception, result: result);
- _deleteCounter.Add(1, tags);
+ var duration = GetElapsedTime(startTimestamp);
+ _deleteDuration.Record(duration.TotalSeconds, tags);
}
internal void CheckPassword(string userType, bool? userMissing, PasswordVerificationResult? result, Exception? exception = null)
{
- if (!_checkPasswordCounter.Enabled)
+ if (!_checkPasswordAttemptsCounter.Enabled)
{
return;
}
@@ -109,12 +141,12 @@ internal void CheckPassword(string userType, bool? userMissing, PasswordVerifica
}
AddErrorTag(ref tags, exception);
- _checkPasswordCounter.Add(1, tags);
+ _checkPasswordAttemptsCounter.Add(1, tags);
}
internal void VerifyToken(string userType, bool? result, string purpose, Exception? exception = null)
{
- if (!_verifyTokenCounter.Enabled)
+ if (!_verifyTokenAttemptsCounter.Enabled)
{
return;
}
@@ -130,12 +162,12 @@ internal void VerifyToken(string userType, bool? result, string purpose, Excepti
}
AddErrorTag(ref tags, exception);
- _verifyTokenCounter.Add(1, tags);
+ _verifyTokenAttemptsCounter.Add(1, tags);
}
internal void GenerateToken(string userType, string purpose, Exception? exception = null)
{
- if (!_generateTokenCounter.Enabled)
+ if (!_generateTokensCounter.Enabled)
{
return;
}
@@ -147,7 +179,12 @@ internal void GenerateToken(string userType, string purpose, Exception? exceptio
};
AddErrorTag(ref tags, exception);
- _generateTokenCounter.Add(1, tags);
+ _generateTokensCounter.Add(1, tags);
+ }
+
+ private static TimeSpan GetElapsedTime(long startTimestamp)
+ {
+ return ValueStopwatch.GetElapsedTime(startTimestamp, Stopwatch.GetTimestamp());
}
private static string GetTokenPurpose(string purpose)
@@ -215,10 +252,10 @@ private static string GetUpdateType(UserUpdateType updateType)
return updateType switch
{
UserUpdateType.Update => "update",
- UserUpdateType.UserName => "user_name",
+ UserUpdateType.SetUserName => "set_user_name",
UserUpdateType.AddPassword => "add_password",
UserUpdateType.ChangePassword => "change_password",
- UserUpdateType.SecurityStamp => "security_stamp",
+ UserUpdateType.UpdateSecurityStamp => "update_security_stamp",
UserUpdateType.ResetPassword => "reset_password",
UserUpdateType.RemoveLogin => "remove_login",
UserUpdateType.AddLogin => "add_login",
@@ -237,7 +274,7 @@ private static string GetUpdateType(UserUpdateType updateType)
UserUpdateType.SetTwoFactorEnabled => "set_two_factor_enabled",
UserUpdateType.SetLockoutEnabled => "set_lockout_enabled",
UserUpdateType.SetLockoutEndDate => "set_lockout_end_date",
- UserUpdateType.AccessFailed => "access_failed",
+ UserUpdateType.IncrementAccessFailed => "increment_access_failed",
UserUpdateType.ResetAccessFailedCount => "reset_access_failed_count",
UserUpdateType.SetAuthenticationToken => "set_authentication_token",
UserUpdateType.RemoveAuthenticationToken => "remove_authentication_token",
diff --git a/src/Identity/Extensions.Core/src/UserUpdateType.cs b/src/Identity/Extensions.Core/src/UserUpdateType.cs
index ed60fe9a1a9f..4e9eeb06baae 100644
--- a/src/Identity/Extensions.Core/src/UserUpdateType.cs
+++ b/src/Identity/Extensions.Core/src/UserUpdateType.cs
@@ -6,10 +6,10 @@ namespace Microsoft.AspNetCore.Identity;
internal enum UserUpdateType
{
Update,
- UserName,
+ SetUserName,
AddPassword,
ChangePassword,
- SecurityStamp,
+ UpdateSecurityStamp,
ResetPassword,
RemoveLogin,
AddLogin,
@@ -28,7 +28,7 @@ internal enum UserUpdateType
SetTwoFactorEnabled,
SetLockoutEnabled,
SetLockoutEndDate,
- AccessFailed,
+ IncrementAccessFailed,
ResetAccessFailedCount,
SetAuthenticationToken,
RemoveAuthenticationToken,
diff --git a/src/Identity/test/Identity.Test/SignInManagerTest.cs b/src/Identity/test/Identity.Test/SignInManagerTest.cs
index 2cddbeae36e3..c71662ecc295 100644
--- a/src/Identity/test/Identity.Test/SignInManagerTest.cs
+++ b/src/Identity/test/Identity.Test/SignInManagerTest.cs
@@ -39,8 +39,8 @@ public async Task PasswordSignInReturnsLockedOutWhenLockedOut()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateCounterName);
- using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInUserPrincipalCounterName);
+ using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateDurationName);
+ using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInsCounterName);
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user, meterFactory: testMeterFactory);
@@ -68,12 +68,12 @@ public async Task PasswordSignInReturnsLockedOutWhenLockedOut()
manager.Verify();
Assert.Collection(authenticate.GetMeasurementSnapshot(),
- m => MetricsHelpers.AssertContainsTags(m.Tags,
+ m => MetricsHelpers.AssertHasDurationAndContainsTags(m.Value, m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
KeyValuePair.Create("aspnetcore.identity.sign_in.type", "password"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", false),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", false),
KeyValuePair.Create("aspnetcore.identity.sign_in.result", "locked_out"),
]));
Assert.Empty(signInUserPrincipal.GetMeasurementSnapshot());
@@ -84,7 +84,7 @@ public async Task CheckPasswordSignInReturnsLockedOutWhenLockedOut()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var checkPasswordSignIn = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.CheckPasswordCounterName);
+ using var checkPasswordSignIn = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.CheckPasswordAttemptsCounterName);
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user, meterFactory: testMeterFactory);
@@ -348,8 +348,8 @@ public async Task ExternalSignInRequiresVerificationIfNotBypassed(bool bypass)
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateCounterName);
- using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInUserPrincipalCounterName);
+ using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateDurationName);
+ using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInsCounterName);
var user = new PocoUser { UserName = "Foo" };
const string loginProvider = "login";
@@ -392,31 +392,31 @@ public async Task ExternalSignInRequiresVerificationIfNotBypassed(bool bypass)
if (bypass)
{
Assert.Collection(authenticate.GetMeasurementSnapshot(),
- m => MetricsHelpers.AssertContainsTags(m.Tags,
+ m => MetricsHelpers.AssertHasDurationAndContainsTags(m.Value, m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
KeyValuePair.Create("aspnetcore.identity.sign_in.type", "external"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", false),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", false),
KeyValuePair.Create("aspnetcore.identity.sign_in.result", "success"),
]));
Assert.Collection(signInUserPrincipal.GetMeasurementSnapshot(),
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", false),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", false),
]));
}
else
{
Assert.Collection(authenticate.GetMeasurementSnapshot(),
- m => MetricsHelpers.AssertContainsTags(m.Tags,
+ m => MetricsHelpers.AssertHasDurationAndContainsTags(m.Value, m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
KeyValuePair.Create("aspnetcore.identity.sign_in.type", "external"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", false),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", false),
KeyValuePair.Create("aspnetcore.identity.sign_in.result", "requires_two_factor"),
]));
Assert.Empty(signInUserPrincipal.GetMeasurementSnapshot());
@@ -428,8 +428,8 @@ public async Task CanPasskeySignIn()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateCounterName);
- using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInUserPrincipalCounterName);
+ using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateDurationName);
+ using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInsCounterName);
var user = new PocoUser { UserName = "Foo" };
var passkey = new UserPasskeyInfo(null, null, default, 0, null, false, false, false, null, null);
@@ -469,20 +469,20 @@ public async Task CanPasskeySignIn()
auth.Verify();
Assert.Collection(authenticate.GetMeasurementSnapshot(),
- m => MetricsHelpers.AssertContainsTags(m.Tags,
+ m => MetricsHelpers.AssertHasDurationAndContainsTags(m.Value, m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
KeyValuePair.Create("aspnetcore.identity.sign_in.type", "passkey"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", false),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", false),
KeyValuePair.Create("aspnetcore.identity.sign_in.result", "success"),
]));
Assert.Collection(signInUserPrincipal.GetMeasurementSnapshot(),
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", false),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", false),
]));
}
@@ -778,7 +778,7 @@ public async Task SignInAsync_Failure()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInUserPrincipalCounterName);
+ using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInsCounterName);
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user, meterFactory: testMeterFactory);
@@ -800,7 +800,7 @@ public async Task SignInAsync_Failure()
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
KeyValuePair.Create("error.type", "System.InvalidOperationException"),
]));
}
@@ -814,7 +814,7 @@ public async Task CanResignIn(bool isPersistent, bool externalLogin)
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateCounterName);
+ using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateDurationName);
var user = new PocoUser { UserName = "Foo" };
var context = new DefaultHttpContext();
@@ -855,11 +855,11 @@ public async Task CanResignIn(bool isPersistent, bool externalLogin)
signInManager.Verify();
Assert.Collection(authenticate.GetMeasurementSnapshot(),
- m => MetricsHelpers.AssertContainsTags(m.Tags,
+ m => MetricsHelpers.AssertHasDurationAndContainsTags(m.Value, m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
- KeyValuePair.Create("aspnetcore.identity.sign_in.is_persistent", isPersistent),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.is_persistent", isPersistent),
KeyValuePair.Create("aspnetcore.identity.sign_in.result", "success"),
]));
}
@@ -868,8 +868,8 @@ public async Task CanResignIn(bool isPersistent, bool externalLogin)
public async Task ResignInNoOpsAndLogsErrorIfNotAuthenticated()
{
var testMeterFactory = new TestMeterFactory();
- using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateCounterName);
- using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInUserPrincipalCounterName);
+ using var authenticate = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.AuthenticateDurationName);
+ using var signInUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignInsCounterName);
var user = new PocoUser { UserName = "Foo" };
var context = new DefaultHttpContext();
@@ -892,10 +892,10 @@ public async Task ResignInNoOpsAndLogsErrorIfNotAuthenticated()
Times.Never());
Assert.Collection(authenticate.GetMeasurementSnapshot(),
- m => MetricsHelpers.AssertContainsTags(m.Tags,
+ m => MetricsHelpers.AssertHasDurationAndContainsTags(m.Value, m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
KeyValuePair.Create("aspnetcore.identity.sign_in.result", "failure"),
]));
Assert.Empty(signInUserPrincipal.GetMeasurementSnapshot());
@@ -1044,7 +1044,7 @@ public async Task RememberClientStoresUserId()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var rememberTwoFactorClient = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.RememberTwoFactorCounterName);
+ using var rememberTwoFactorClient = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.RememberedTwoFactorCounterName);
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user, meterFactory: testMeterFactory);
@@ -1069,7 +1069,7 @@ public async Task RememberClientStoresUserId()
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.TwoFactorRememberMe"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.TwoFactorRememberMe"),
]));
}
@@ -1078,7 +1078,7 @@ public async Task ForgetTwoFactorClient()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var forgetTwoFactorClient = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.ForgetTwoFactorCounterName);
+ using var forgetTwoFactorClient = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.ForgottenTwoFactorCounterName);
var user = new PocoUser { UserName = "Foo" };
var manager = SetupUserManager(user, meterFactory: testMeterFactory);
@@ -1101,7 +1101,7 @@ public async Task ForgetTwoFactorClient()
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.TwoFactorRememberMe"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.TwoFactorRememberMe"),
KeyValuePair.Create("error.type", "System.InvalidOperationException"),
]));
}
@@ -1152,7 +1152,7 @@ public async Task SignOutCallsContextResponseSignOut_Success()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var signOutUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignOutUserPrincipalCounterName);
+ using var signOutUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignOutsCounterName);
var manager = MockHelpers.TestUserManager(meterFactory: testMeterFactory);
var context = new DefaultHttpContext();
@@ -1172,7 +1172,7 @@ public async Task SignOutCallsContextResponseSignOut_Success()
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
- KeyValuePair.Create("aspnetcore.identity.authentication_scheme", "Identity.Application"),
+ KeyValuePair.Create("aspnetcore.authentication.scheme", "Identity.Application"),
]));
}
@@ -1181,7 +1181,7 @@ public async Task SignOutCallsContextResponseSignOut_Failure()
{
// Setup
var testMeterFactory = new TestMeterFactory();
- using var signOutUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignOutUserPrincipalCounterName);
+ using var signOutUserPrincipal = new MetricCollector(testMeterFactory, "Microsoft.AspNetCore.Identity", SignInManagerMetrics.SignOutsCounterName);
var manager = MockHelpers.TestUserManager(meterFactory: testMeterFactory);
var context = new DefaultHttpContext();
@@ -1197,7 +1197,7 @@ public async Task SignOutCallsContextResponseSignOut_Failure()
m => MetricsHelpers.AssertContainsTags(m.Tags,
[
KeyValuePair.Create