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.
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;
}
}