I recently was developing a console application in .net core, where I had to use log4net logging.
In the standard asp.net core approach we can use:
public void Configure(IApplicationBuilder app, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory)
{
loggerFactory.AddLog4Net();
}
But this is .net core console application, where I’m creating LoggerFactory on my own, so it would not work.

In order to solve it, I had to implement my own Log4NetProvider, that would implement ILoggerProvider.
public class Log4NetProvider : ILoggerProvider
{
private readonly string _log4NetConfigFile;
private readonly bool _skipDiagnosticLogs;
private readonly ConcurrentDictionary<string, ILogger> _loggers =
new ConcurrentDictionary<string, ILogger>();
public Log4NetProvider(string log4NetConfigFile, bool skipDiagnosticLogs)
{
_log4NetConfigFile = log4NetConfigFile;
_skipDiagnosticLogs = skipDiagnosticLogs;
}
public ILogger CreateLogger(string categoryName)
{
return _loggers.GetOrAdd(categoryName, CreateLoggerImplementation);
}
public void Dispose()
{
_loggers.Clear();
}
private ILogger CreateLoggerImplementation(string name)
{
return new Log4NetLogger(name, new FileInfo(_log4NetConfigFile), _skipDiagnosticLogs);
}
}
And the implementation of an actual logger:
public class Log4NetLogger : ILogger
{
private readonly string _name;
private readonly ILog _log;
private readonly bool _skipDiagnosticLogs;
private ILoggerRepository _loggerRepository;
public Log4NetLogger(string name, FileInfo fileInfo, bool skipDiagnosticLogs)
{
_name = name;
_loggerRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
_log = LogManager.GetLogger(_loggerRepository.Name, name);
_skipDiagnosticLogs = skipDiagnosticLogs;
log4net.Config.XmlConfigurator.Configure(_loggerRepository, fileInfo);
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
switch (logLevel)
{
case LogLevel.Critical:
return _log.IsFatalEnabled;
case LogLevel.Debug:
case LogLevel.Trace:
return _log.IsDebugEnabled && AllowDiagnostics();
case LogLevel.Error:
return _log.IsErrorEnabled;
case LogLevel.Information:
return _log.IsInfoEnabled && AllowDiagnostics();
case LogLevel.Warning:
return _log.IsWarnEnabled;
default:
throw new ArgumentOutOfRangeException(nameof(logLevel));
}
}
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func<TState, Exception, string> formatter)
{
if (!IsEnabled(logLevel))
{
return;
}
if (formatter == null)
{
throw new ArgumentNullException(nameof(formatter));
}
string message = $"{formatter(state, exception)} {exception}";
if (!string.IsNullOrEmpty(message) || exception != null)
{
switch (logLevel)
{
case LogLevel.Critical:
_log.Fatal(message);
break;
case LogLevel.Debug:
case LogLevel.Trace:
_log.Debug(message);
break;
case LogLevel.Error:
_log.Error(message);
break;
case LogLevel.Information:
_log.Info(message);
break;
case LogLevel.Warning:
_log.Warn(message);
break;
default:
_log.Warn($"Encountered unknown log level {logLevel}, writing out as Info.");
_log.Info(message, exception);
break;
}
}
}
private bool AllowDiagnostics()
{
if (!_skipDiagnosticLogs)
{
return true;
}
return !(_name.ToLower().StartsWith("microsoft")
|| _name == "IdentityServer4.AccessTokenValidation.Infrastructure.NopAuthenticationMiddleware");
}
}
One last touch is adding an extension for ILoggerFactory to be able to use AddLog4Net.
public static class Log4netExtensions
{
public static ILoggerFactory AddLog4Net(this ILoggerFactory factory, bool skipDiagnosticLogs)
{
factory.AddProvider(new Log4NetProvider("log4net.config", skipDiagnosticLogs));
return factory;
}
}
In my DI container registration, I added code:
var loggerFactory = new Microsoft.Extensions.Logging.LoggerFactory(); loggerFactory.AddLog4Net(true); Container.RegisterInstance<Microsoft.Extensions.Logging.ILoggerFactory>(loggerFactory);
Now it will all works!
To see the whole code, go to my GitHub repository and check this commit: https://github.com/mikuam/console-app-net-core/commit/650ac5348886d3e0238dfec07076b959d62bd4ba
Hope that works for you!