Search code examples
.netilogger

Microsoft.Extensions.Logging, ILogger, get a count of errors?


When using Microsoft.Extensions.Logging in a .NET application, is there a way to get the current count of errors that have been written to the log?

I figure I can probably implement a custom ILogger that tracks the error count, but if this already exists out-of-the-box, I*d much prefer that.


Solution

  • It seems like this is where I'll need a custom StatisticsLogger:

    Note: The intended use for this is in a simple console app that's going to run as a single instance. No attempt has been made to accomodate multi-threading!

    public class StatisticsLogger : ILogger
    {
        public int CriticalsCount { get; private set; } = 0;
        public int ErrorsCount { get; private set; } = 0;
        public int WarningsCount { get; private set; } = 0;
    
        public IDisposable BeginScope<TState>(TState state) where TState : notnull
        {
            return null;
        }
    
        public bool IsEnabled(LogLevel logLevel)
        {
            return true;
        }
    
        public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (logLevel == LogLevel.Critical)
            {
                CriticalsCount++;
            }
    
            if (logLevel == LogLevel.Error)
            {
                ErrorsCount++;
            }
    
            if (logLevel == LogLevel.Warning)
            {
                ErrorsCount++;
            }
        }
    }
    

    A logger provider that retains the instance of the StatisticsLogger:

    public class StatisticsLoggerProvider : ILoggerProvider
    {
        public StatisticsLogger Logger {get; private set;}
    
        public StatisticsLoggerProvider()
        {
            Logger = new StatisticsLogger();
        }
    
        public ILogger CreateLogger(string categoryName)
        {
            return Logger;
        }
    
        public void Dispose()
        {
        }
    }
    

    A helper for adding this to the ApplicationHostBuilder:

    public static class HostApplicationBuilderExtensions
    {
        public static HostApplicationBuilder AddCustomLoggers(this HostApplicationBuilder builder)
        {
            // Adding custom loggers on the builder instead of builder.Logging allows access to builder.Configuration :)
            builder.Logging.AddProvider(new StatisticsLoggerProvider());
    
            return builder;
        }
    }
    

    And using it in the Program Main

    class Program
    {
        static async Task Main(string[] args)
        {
            var builder = Host.CreateApplicationBuilder(args);
    
            builder.Services.AddSingleton<Batch>();
    
            builder.Logging
                .SetMinimumLevel(LogLevel.Trace)
                .AddConsole();
    
            builder.AddCustomLoggers();
    
            var host = builder.Build();
    
            // This could maybe be handled better...
            var statisticsLoggerProvider = host.Services.GetServices<ILoggerProvider>()
                .First(x => x is StatisticsLoggerProvider) as StatisticsLoggerProvider;
    
            var statisticsLogger = statisticsLoggerProvider.Logger;
    
            var criticalsCount = statisticsLogger.CriticalsCount;
    
            var errorsCount = statisticsLogger.ErrorsCount;
    
            var warningsCount = statisticsLogger.WarningsCount;
        }
    }