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?
No comments yet, you can leave the first one!