Skip to content

Commit 1f0c98b

Browse files
authored
Identity metrics clean up (#62671)
1 parent b9f43c1 commit 1f0c98b

File tree

3 files changed

+45
-43
lines changed

3 files changed

+45
-43
lines changed

src/Identity/Core/src/SignInManagerMetrics.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ internal sealed class SignInManagerMetrics : IDisposable
1414
public const string RememberTwoFactorCounterName = "aspnetcore.identity.sign_in.remember_two_factor";
1515
public const string ForgetTwoFactorCounterName = "aspnetcore.identity.sign_in.forget_two_factor";
1616
public const string CheckPasswordCounterName = "aspnetcore.identity.sign_in.check_password";
17-
public const string SignInUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_in_principal";
18-
public const string SignOutUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_out_principal";
17+
public const string SignInUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_in";
18+
public const string SignOutUserPrincipalCounterName = "aspnetcore.identity.sign_in.sign_out";
1919

2020
private readonly Meter _meter;
2121
private readonly Counter<long> _authenticateCounter;
@@ -29,12 +29,12 @@ public SignInManagerMetrics(IMeterFactory meterFactory)
2929
{
3030
_meter = meterFactory.Create(MeterName);
3131

32-
_authenticateCounter = _meter.CreateCounter<long>(AuthenticateCounterName, "count", "The number of authenticate attempts. The authenticate counter is incremented by sign in methods such as PasswordSignInAsync and TwoFactorSignInAsync.");
33-
_rememberTwoFactorClientCounter = _meter.CreateCounter<long>(RememberTwoFactorCounterName, "count", "The number of two factor clients remembered.");
34-
_forgetTwoFactorCounter = _meter.CreateCounter<long>(ForgetTwoFactorCounterName, "count", "The number of two factor clients forgotten.");
35-
_checkPasswordCounter = _meter.CreateCounter<long>(CheckPasswordCounterName, "count", "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.");
36-
_signInUserPrincipalCounter = _meter.CreateCounter<long>(SignInUserPrincipalCounterName, "count", "The number of calls to sign in user principals.");
37-
_signOutUserPrincipalCounter = _meter.CreateCounter<long>(SignOutUserPrincipalCounterName, "count", "The number of calls to sign out user principals.");
32+
_authenticateCounter = _meter.CreateCounter<long>(AuthenticateCounterName, "{count}", "The number of authenticate attempts. The authenticate counter is incremented by sign in methods such as PasswordSignInAsync and TwoFactorSignInAsync.");
33+
_rememberTwoFactorClientCounter = _meter.CreateCounter<long>(RememberTwoFactorCounterName, "{count}", "The number of two factor clients remembered.");
34+
_forgetTwoFactorCounter = _meter.CreateCounter<long>(ForgetTwoFactorCounterName, "{count}", "The number of two factor clients forgotten.");
35+
_checkPasswordCounter = _meter.CreateCounter<long>(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.");
36+
_signInUserPrincipalCounter = _meter.CreateCounter<long>(SignInUserPrincipalCounterName, "{sign_in}", "The number of calls to sign in user principals.");
37+
_signOutUserPrincipalCounter = _meter.CreateCounter<long>(SignOutUserPrincipalCounterName, "{sign_out}", "The number of calls to sign out user principals.");
3838
}
3939

4040
internal void CheckPasswordSignIn(string userType, SignInResult? result, Exception? exception = null)
@@ -49,7 +49,7 @@ internal void CheckPasswordSignIn(string userType, SignInResult? result, Excepti
4949
{ "aspnetcore.identity.user_type", userType },
5050
};
5151
AddSignInResult(ref tags, result);
52-
AddExceptionTags(ref tags, exception);
52+
AddErrorTag(ref tags, exception);
5353

5454
_checkPasswordCounter.Add(1, tags);
5555
}
@@ -69,7 +69,7 @@ internal void AuthenticateSignIn(string userType, string authenticationScheme, S
6969
};
7070
AddIsPersistent(ref tags, isPersistent);
7171
AddSignInResult(ref tags, result);
72-
AddExceptionTags(ref tags, exception);
72+
AddErrorTag(ref tags, exception);
7373

7474
_authenticateCounter.Add(1, tags);
7575
}
@@ -87,7 +87,7 @@ internal void SignInUserPrincipal(string userType, string authenticationScheme,
8787
{ "aspnetcore.identity.authentication_scheme", authenticationScheme },
8888
};
8989
AddIsPersistent(ref tags, isPersistent);
90-
AddExceptionTags(ref tags, exception);
90+
AddErrorTag(ref tags, exception);
9191

9292
_signInUserPrincipalCounter.Add(1, tags);
9393
}
@@ -104,7 +104,7 @@ internal void SignOutUserPrincipal(string userType, string authenticationScheme,
104104
{ "aspnetcore.identity.user_type", userType },
105105
{ "aspnetcore.identity.authentication_scheme", authenticationScheme },
106106
};
107-
AddExceptionTags(ref tags, exception);
107+
AddErrorTag(ref tags, exception);
108108

109109
_signOutUserPrincipalCounter.Add(1, tags);
110110
}
@@ -121,7 +121,7 @@ internal void RememberTwoFactorClient(string userType, string authenticationSche
121121
{ "aspnetcore.identity.user_type", userType },
122122
{ "aspnetcore.identity.authentication_scheme", authenticationScheme }
123123
};
124-
AddExceptionTags(ref tags, exception);
124+
AddErrorTag(ref tags, exception);
125125

126126
_rememberTwoFactorClientCounter.Add(1, tags);
127127
}
@@ -138,7 +138,7 @@ internal void ForgetTwoFactorClient(string userType, string authenticationScheme
138138
{ "aspnetcore.identity.user_type", userType },
139139
{ "aspnetcore.identity.authentication_scheme", authenticationScheme }
140140
};
141-
AddExceptionTags(ref tags, exception);
141+
AddErrorTag(ref tags, exception);
142142

143143
_forgetTwoFactorCounter.Add(1, tags);
144144
}
@@ -164,7 +164,7 @@ private static void AddSignInResult(ref TagList tags, SignInResult? result)
164164
}
165165
}
166166

167-
private static void AddExceptionTags(ref TagList tags, Exception? exception)
167+
private static void AddErrorTag(ref TagList tags, Exception? exception)
168168
{
169169
if (exception != null)
170170
{
@@ -182,7 +182,7 @@ private static string GetSignInType(SignInType signInType)
182182
SignInType.TwoFactor => "two_factor",
183183
SignInType.External => "external",
184184
SignInType.Passkey => "passkey",
185-
_ => "_UNKNOWN"
185+
_ => "_OTHER"
186186
};
187187
}
188188

src/Identity/Extensions.Core/src/UserManagerMetrics.cs

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ internal sealed class UserManagerMetrics : IDisposable
3232
public UserManagerMetrics(IMeterFactory meterFactory)
3333
{
3434
_meter = meterFactory.Create(MeterName);
35-
_createCounter = _meter.CreateCounter<long>(CreateCounterName, "count", "The number of users created.");
36-
_updateCounter = _meter.CreateCounter<long>(UpdateCounterName, "count", "The number of user updates.");
37-
_deleteCounter = _meter.CreateCounter<long>(DeleteCounterName, "count", "The number of users deleted.");
38-
_checkPasswordCounter = _meter.CreateCounter<long>(CheckPasswordCounterName, "count", "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.");
39-
_verifyTokenCounter = _meter.CreateCounter<long>(VerifyTokenCounterName, "count", "The number of token verification attempts.");
40-
_generateTokenCounter = _meter.CreateCounter<long>(GenerateTokenCounterName, "count", "The number of token generation attempts.");
35+
_createCounter = _meter.CreateCounter<long>(CreateCounterName, "{user}", "The number of users created.");
36+
_updateCounter = _meter.CreateCounter<long>(UpdateCounterName, "{user}", "The number of users updated.");
37+
_deleteCounter = _meter.CreateCounter<long>(DeleteCounterName, "{user}", "The number of users deleted.");
38+
_checkPasswordCounter = _meter.CreateCounter<long>(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.");
39+
_verifyTokenCounter = _meter.CreateCounter<long>(VerifyTokenCounterName, "{count}", "The number of token verification attempts.");
40+
_generateTokenCounter = _meter.CreateCounter<long>(GenerateTokenCounterName, "{count}", "The number of token generation attempts.");
4141
}
4242

4343
internal void CreateUser(string userType, IdentityResult? result, Exception? exception = null)
@@ -52,7 +52,7 @@ internal void CreateUser(string userType, IdentityResult? result, Exception? exc
5252
{ "aspnetcore.identity.user_type", userType }
5353
};
5454
AddIdentityResultTags(ref tags, result);
55-
AddExceptionTags(ref tags, exception);
55+
AddErrorTag(ref tags, exception, result: result);
5656

5757
_createCounter.Add(1, tags);
5858
}
@@ -70,7 +70,7 @@ internal void UpdateUser(string userType, IdentityResult? result, UserUpdateType
7070
{ "aspnetcore.identity.user.update_type", GetUpdateType(updateType) },
7171
};
7272
AddIdentityResultTags(ref tags, result);
73-
AddExceptionTags(ref tags, exception);
73+
AddErrorTag(ref tags, exception, result: result);
7474

7575
_updateCounter.Add(1, tags);
7676
}
@@ -87,7 +87,7 @@ internal void DeleteUser(string userType, IdentityResult? result, Exception? exc
8787
{ "aspnetcore.identity.user_type", userType }
8888
};
8989
AddIdentityResultTags(ref tags, result);
90-
AddExceptionTags(ref tags, exception);
90+
AddErrorTag(ref tags, exception, result: result);
9191

9292
_deleteCounter.Add(1, tags);
9393
}
@@ -105,9 +105,9 @@ internal void CheckPassword(string userType, bool? userMissing, PasswordVerifica
105105
};
106106
if (userMissing != null || result != null)
107107
{
108-
tags.Add("aspnetcore.identity.user.password_result", GetPasswordResult(result, passwordMissing: null, userMissing));
108+
tags.Add("aspnetcore.identity.password_check_result", GetPasswordResult(result, passwordMissing: null, userMissing));
109109
}
110-
AddExceptionTags(ref tags, exception);
110+
AddErrorTag(ref tags, exception);
111111

112112
_checkPasswordCounter.Add(1, tags);
113113
}
@@ -128,7 +128,7 @@ internal void VerifyToken(string userType, bool? result, string purpose, Excepti
128128
{
129129
tags.Add("aspnetcore.identity.token_verified", result == true ? "success" : "failure");
130130
}
131-
AddExceptionTags(ref tags, exception);
131+
AddErrorTag(ref tags, exception);
132132

133133
_verifyTokenCounter.Add(1, tags);
134134
}
@@ -145,14 +145,14 @@ internal void GenerateToken(string userType, string purpose, Exception? exceptio
145145
{ "aspnetcore.identity.user_type", userType },
146146
{ "aspnetcore.identity.token_purpose", GetTokenPurpose(purpose) },
147147
};
148-
AddExceptionTags(ref tags, exception);
148+
AddErrorTag(ref tags, exception);
149149

150150
_generateTokenCounter.Add(1, tags);
151151
}
152152

153153
private static string GetTokenPurpose(string purpose)
154154
{
155-
// Purpose could be any value and can't be used as a tag value. However, there are known purposes
155+
// Purpose could be any value and can't be used directly as a tag value. However, there are known purposes
156156
// on UserManager that we can detect and use as a tag value. Some could have a ':' in them followed by user data.
157157
// We need to trim them to content before ':' and then match to known values.
158158
ReadOnlySpan<char> trimmedPurpose = purpose;
@@ -161,15 +161,16 @@ private static string GetTokenPurpose(string purpose)
161161
{
162162
trimmedPurpose = purpose.AsSpan(0, colonIndex);
163163
}
164-
164+
165+
// These are known purposes that are specified in ASP.NET Core Identity.
165166
return trimmedPurpose switch
166167
{
167168
"ResetPassword" => "reset_password",
168169
"ChangePhoneNumber" => "change_phone_number",
169170
"EmailConfirmation" => "email_confirmation",
170171
"ChangeEmail" => "change_email",
171172
"TwoFactor" => "two_factor",
172-
_ => "_UNKNOWN"
173+
_ => "_OTHER"
173174
};
174175
}
175176

@@ -183,15 +184,16 @@ private static void AddIdentityResultTags(ref TagList tags, IdentityResult? resu
183184
tags.Add("aspnetcore.identity.result", result.Succeeded ? "success" : "failure");
184185
if (!result.Succeeded && result.Errors.FirstOrDefault()?.Code is { Length: > 0 } code)
185186
{
186-
tags.Add("aspnetcore.identity.result_error_code", code);
187+
tags.Add("aspnetcore.identity.error_code", code);
187188
}
188189
}
189190

190-
private static void AddExceptionTags(ref TagList tags, Exception? exception)
191+
private static void AddErrorTag(ref TagList tags, Exception? exception, IdentityResult? result = null)
191192
{
192-
if (exception != null)
193+
var value = exception?.GetType().FullName ?? result?.Errors.FirstOrDefault()?.Code;
194+
if (value != null)
193195
{
194-
tags.Add("error.type", exception.GetType().FullName!);
196+
tags.Add("error.type", value);
195197
}
196198
}
197199

@@ -204,7 +206,7 @@ private static string GetPasswordResult(PasswordVerificationResult? result, bool
204206
(PasswordVerificationResult.Failed, false, false) => "failure",
205207
(null, true, false) => "password_missing",
206208
(null, false, true) => "user_missing",
207-
_ => "_UNKNOWN"
209+
_ => "_OTHER"
208210
};
209211
}
210212

@@ -244,7 +246,7 @@ private static string GetUpdateType(UserUpdateType updateType)
244246
UserUpdateType.RedeemTwoFactorRecoveryCode => "redeem_two_factor_recovery_code",
245247
UserUpdateType.SetPasskey => "set_passkey",
246248
UserUpdateType.RemovePasskey => "remove_passkey",
247-
_ => "_UNKNOWN"
249+
_ => "_OTHER"
248250
};
249251
}
250252

src/Identity/test/Identity.Test/UserManagerTest.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ public async Task DeleteCallsStore_Failure()
174174
[
175175
KeyValuePair.Create<string, object>("aspnetcore.identity.user_type", "Microsoft.AspNetCore.Identity.Test.PocoUser"),
176176
KeyValuePair.Create<string, object>("aspnetcore.identity.result", "failure"),
177-
KeyValuePair.Create<string, object>("aspnetcore.identity.result_error_code", "ConcurrencyFailure")
177+
KeyValuePair.Create<string, object>("aspnetcore.identity.error_code", "ConcurrencyFailure")
178178
]));
179179
}
180180

@@ -664,7 +664,7 @@ public async Task CheckPasswordWillRehashPasswordWhenNeeded()
664664
Assert.Collection(checkPassword.GetMeasurementSnapshot(),
665665
m => MetricsHelpers.AssertContainsTags(m.Tags,
666666
[
667-
KeyValuePair.Create<string, object>("aspnetcore.identity.user.password_result", "success_rehash_needed")
667+
KeyValuePair.Create<string, object>("aspnetcore.identity.password_check_result", "success_rehash_needed")
668668
]));
669669
}
670670

@@ -871,7 +871,7 @@ public async Task CheckPasswordWithNullUserReturnsFalse()
871871
Assert.Collection(checkPassword.GetMeasurementSnapshot(),
872872
m => MetricsHelpers.AssertContainsTags(m.Tags,
873873
[
874-
KeyValuePair.Create<string, object>("aspnetcore.identity.user.password_result", "user_missing")
874+
KeyValuePair.Create<string, object>("aspnetcore.identity.password_check_result", "user_missing")
875875
]));
876876
}
877877

@@ -952,13 +952,13 @@ await Assert.ThrowsAsync<NotSupportedException>(
952952
Assert.Collection(generateToken.GetMeasurementSnapshot(),
953953
m => MetricsHelpers.AssertContainsTags(m.Tags,
954954
[
955-
KeyValuePair.Create<string, object>("aspnetcore.identity.token_purpose", "_UNKNOWN"),
955+
KeyValuePair.Create<string, object>("aspnetcore.identity.token_purpose", "_OTHER"),
956956
KeyValuePair.Create<string, object>("error.type", "System.NotSupportedException"),
957957
]));
958958
Assert.Collection(verifyToken.GetMeasurementSnapshot(),
959959
m => MetricsHelpers.AssertContainsTags(m.Tags,
960960
[
961-
KeyValuePair.Create<string, object>("aspnetcore.identity.token_purpose", "_UNKNOWN"),
961+
KeyValuePair.Create<string, object>("aspnetcore.identity.token_purpose", "_OTHER"),
962962
KeyValuePair.Create<string, object>("error.type", "System.NotSupportedException"),
963963
]));
964964
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy