Error CS0618: ‘ConsoleLogger’ is obsolete

This is a short note showing my fix to an error I encountered when migrating application from .NET Framework to the most recent (at the moment) .NET 6.

##[error]src\UnitTests.Common\SomeFileName.cs(66,34): Error CS0618: 'ConsoleLogger' is obsolete: 'This type is obsolete and will be removed in a future version. The recommended alternative is ConsoleLoggerProvider.'Code language: PHP (php)

I’m just pasting the rough code example of how this can be migrated, because:

  • I couldn’t find it anywhere in the Internet
  • I spent some boring hours on it and I’d rather never do it again

Custom console logger using old Microsoft.Extensions.Logging.Console 2.1.1

// Usage example:
// ILogger logger = new MyCustomLogger(categoryName, (s, level) => true, true);

private class MyCustomLogger : ConsoleLogger
{
    public MyCustomLogger(string name, Func<string, LogLevel, bool> filter, bool includeScopes) : base(name, filter, includeScopes) { }
    public MyCustomLogger(string name, Func<string, LogLevel, bool> filter, IExternalScopeProvider scopeProvider) : base(name, filter, scopeProvider) { }

    public override void WriteMessage(LogLevel logLevel, string logName, int eventId, string message, Exception exception)
    {
        var result = $"{GetType().Assembly.GetName().Name} {logLevel} {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{Thread.CurrentThread.ManagedThreadId}]{message}";
        base.WriteMessage(logLevel, logName, eventId, result, exception);
    }
}Code language: C# (cs)

Equivalent custom console logger using newer Microsoft.Extensions.Logging.Console 6.0.0

Today, the ConsoleLogger is obsolete and is now just an internal class, so we cannot use its constructor.

// Usage example:
// In .NET Framework, creating custom ILogger implementation without using obsolete methods is a bit more verbose, probably no way around it: https://stackoverflow.com/q/53690820/889779
//
// const string myCustomLoggerFormatterName = "CustomTestLoggerFormatter";
// var configureNamedOptions = new ConfigureNamedOptions<ConsoleLoggerOptions>("", options => options.FormatterName = myCustomLoggerFormatterName);
// var optionsFactory = new OptionsFactory<ConsoleLoggerOptions>(new []{ configureNamedOptions }, Enumerable.Empty<IPostConfigureOptions<ConsoleLoggerOptions>>());
// var optionsMonitor = new OptionsMonitor<ConsoleLoggerOptions>(optionsFactory, Enumerable.Empty<IOptionsChangeTokenSource<ConsoleLoggerOptions>>(), new OptionsCache<ConsoleLoggerOptions>());
// var loggerFilterOptions = new LoggerFilterOptions { MinLevel = LogLevel.Debug };
// var consoleLoggerProvider = new ConsoleLoggerProvider(optionsMonitor, new List<ConsoleFormatter>()
// {
//     new MyCustomLoggerFormatter(myCustomLoggerFormatterName)
// });
// var loggerFactory = new LoggerFactory(new[] {consoleLoggerProvider}, loggerFilterOptions);
// ILogger logger = loggerFactory.CreateLogger(categoryName);

class MyCustomLoggerFormatter : ConsoleFormatter
{
    public MyCustomLoggerFormatter(string name) : base(name) { }
    public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider scopeProvider, TextWriter textWriter)
    {
        textWriter.WriteLine($"{GetType().Assembly.GetName().Name} {logEntry.LogLevel} {DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} [{Thread.CurrentThread.ManagedThreadId}]{logEntry.State}"); 
        if (logEntry.Exception != null)
        {
            textWriter.WriteLine(logEntry.Exception);
        }
    }
}Code language: C# (cs)

Not very pretty, but I understand it’s now a lower-level class to build log formatters upon it and it’s not frequently needed to build a custom one.

If you don’t need to have too many customizations, maybe one of the pre-defined formatters like Simple Console Logger will be enough and you don’t need to write a custom one at all?

Leave a Comment