Repository: dotnet/aspnetcore
File: src/Identity/Extensions.Core/src/UserManagerMetrics.cs (C#)

Code before:

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";

    private readonly Meter _meter;
    private readonly Counter<long> _createCounter;
    private readonly Counter<long> _updateCounter;
    private readonly Counter<long> _deleteCounter;
    private readonly Counter<long> _checkPasswordCounter;
    private readonly Counter<long> _verifyTokenCounter;
    private readonly Counter<long> _generateTokenCounter;

    public UserManagerMetrics(IMeterFactory meterFactory)
    {
        _meter = meterFactory.Create(MeterName);
        _createCounter = _meter.CreateCounter<long>(CreateCounterName, "count", "The number of users created.");
        _updateCounter = _meter.CreateCounter<long>(UpdateCounterName, "count", "The number of user updates.");
        _deleteCounter = _meter.CreateCounter<long>(DeleteCounterName, "count", "The number of users deleted.");
        _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.");
        _verifyTokenCounter = _meter.CreateCounter<long>(VerifyTokenCounterName, "count", "The number of token verification attempts.");
        _generateTokenCounter = _meter.CreateCounter<long>(GenerateTokenCounterName, "count", "The number of token generation attempts.");
    }

    internal void CreateUser(string userType, IdentityResult? result, Exception? exception = null)
    {
        if (!_createCounter.Enabled)
        {
            return;
        }

        var tags = new TagList
        {
            { "aspnetcore.identity.user_type", userType }
        };
        AddIdentityResultTags(ref tags, result);
        AddExceptionTags(ref tags, exception);

        _createCounter.Add(1, tags);
    }

    internal void UpdateUser(string userType, IdentityResult? result, UserUpdateType updateType, Exception? exception = null)
    {
        if (!_updateCounter.Enabled)

Review comment (security):
Is the unit supposed to be singular or plural? I see "{bytes}" in some places like PinnedBlockMemoryPoolMetrics, but then we use "{request}" in AuthorizationMetrics, and "{exception}" in DiagnosticsMetrics? I'm guessing it's PinnedBlockMemoryPoolMetrics that should change to be singular, but I'm not sure.

Code after:

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";

    private readonly Meter _meter;
    private readonly Counter<long> _createCounter;
    private readonly Counter<long> _updateCounter;
    private readonly Counter<long> _deleteCounter;
    private readonly Counter<long> _checkPasswordCounter;
    private readonly Counter<long> _verifyTokenCounter;
    private readonly Counter<long> _generateTokenCounter;

    public UserManagerMetrics(IMeterFactory meterFactory)
    {
        _meter = meterFactory.Create(MeterName);
        _createCounter = _meter.CreateCounter<long>(CreateCounterName, "{user}", "The number of users created.");
        _updateCounter = _meter.CreateCounter<long>(UpdateCounterName, "{user}", "The number of users updated.");
        _deleteCounter = _meter.CreateCounter<long>(DeleteCounterName, "{user}", "The number of users deleted.");
        _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.");
        _verifyTokenCounter = _meter.CreateCounter<long>(VerifyTokenCounterName, "{count}", "The number of token verification attempts.");
        _generateTokenCounter = _meter.CreateCounter<long>(GenerateTokenCounterName, "{count}", "The number of token generation attempts.");
    }

    internal void CreateUser(string userType, IdentityResult? result, Exception? exception = null)
    {
        if (!_createCounter.Enabled)
        {
            return;
        }

        var tags = new TagList
        {
            { "aspnetcore.identity.user_type", userType }
        };
        AddIdentityResultTags(ref tags, result);
        AddErrorTag(ref tags, exception, result: result);

        _createCounter.Add(1, tags);
    }

    internal void UpdateUser(string userType, IdentityResult? result, UserUpdateType updateType, Exception? exception = null)
    {
        if (!_updateCounter.Enabled)