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: // // 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