Adding Log4Net to .Net Core

Log4Net has become somewhat a de facto standard for logging in .Net applications, and I personally have used it in nearly every application I’ve written for quite some time.

Although .Net Core does have some baked in logging, if you prefer to use Log4Net (or need to), then try this, it’s quite simple.

This article is primarily aimed at those that know Log4Net, but if need a configuration file then see Log4Net Configuration below.

Install the Nuget Package

Install the Log4Net Nuget package

PM> Install-Package log4net

If you are using Dependency Injection then also install this package…

PM> install-package Microsoft.Extensions.Logging.Log4Net.AspNetCore

Loading the Configuration

Add this following code to your Program.cs – or somewhere global, to load the configuration file.

// Load Log4Net configuration
var logRepository = log4net.LogManager.GetRepository(Assembly.GetEntryAssembly());
log4net.Config.XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));

Without Dependency Injection

Using

Use as normal

public class Log4NetTester
{
	private log4net.ILog log4logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

	public void TestLog4Net()
	{
		try
		{
			log4logger.Info("About to Throw an error");
			throw new Exception("Log4Net Test");
		}
		catch (Exception e)
		{
			log4logger.Error("An error occurred", e);
		}
	}
}

With Dependency Injection

Configuring the Logger

Make sure you have included the Microsoft.Extensions.Logging.Log4Net.AspNetCore package above.

Here is an example of how to add the logger to Program.cs

builder.Services.AddLogging(loggingBuilder =>
    {
        // configure Logging
        loggingBuilder.ClearProviders();
        loggingBuilder.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace); // this is the minimum for sending to the logger, logger has it's own minimum
        loggingBuilder.AddLog4Net(); // add the Log4Net logger
    });

If you are using an older framework, add it to the ConfigureServices method like so (use the same AddLogging delegate are above)

private static IServiceProvider ConfigureServices(IConfiguration config)
{
	return new ServiceCollection()
	   .AddTransient<Runner>() // Runner is the custom class
	   .AddLogging(...)
	   .BuildServiceProvider();
}

Using

Then just use as a normal logger. Dependency Injection wraps loggers in an ILogger interface.

// declare the logger
private readonly ILogger<Runner> _logger;
private Debtor _client;
// add logger to the constructor
public Runner(ILogger<Runner> logger)
{
	_logger = logger;
}

// send to logger
logger.LogError(e, "error with {Action}", name);

Troubleshooting

If it doesn’t work, check the that the configuration file is copied to the output directory – a simple mistake that catches the best of us.

Make sure you are Loading the Configuration.

If using Dependency Injection then make sure you have included the Microsoft.Extensions.Logging.Log4Net.AspNetCore package.

Log4Net Configuration

This is the standard configuration that I use.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- standard configuration sections items. -->
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
 
  <log4net>
  <!-- Console Appender-->
  <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
    <layout type="log4net.Layout.PatternLayout">
      <param name="ConversionPattern" value="%date [%thread] %-5level %logger [%ndc] - %message%newline" />
    </layout>
    <filter type="log4net.Filter.LevelMatchFilter">
      <levelToMatch value="ERROR"/>
    </filter>
    <threshold value="ERROR"/>
  </appender>

  <!-- File Appender -->
  <appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender">
    <file value="app.log" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="3" />
    <maximumFileSize value="10MB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date %-5level %logger.%method - %message%newline" />
    </layout>
  </appender>


    
  <!-- Setup the root category, add the appenders and set the default level
       Comment out those appenders you don't want-->
    <root>
    <level value="ALL" />
    <appender-ref ref="ConsoleAppender"/>
    <appender-ref ref="RollingFileAppender"/>
  </root>
    <!-- Layout Pattern format expressions
    See http://www.beefycode.com/post/log4net-tutorial-pt-4-layouts-and-patterns.aspx or http://www.codeproject.com/Articles/140911/log-net-Tutorial
    Note that single character notation is now deprecated
    
    %appdomain  the friendly name of the appdomain from which the log entry was made
    %date	      the local datetime when the log entry was made
    %utcdate	  the UTC datetime when the log entry was made
    %exception	a formatted form of the exception object in the log entry, if the entry contains an exception; otherwise, this format expression adds nothing to the log entry
    %file	      the file name from which the log entry was made; note that using %file has a significant performance impact and I don't recommend using it
    %level	    the severity level of the log entry (DEBUG,INFO, etc)
    %line	      the source code line number from which the log entry was made; slow
    %location	  some rudimentary call stack information, including file name and line number at which the log entry was made; using
    %logger	    the name of the logger making the entry; more on this in a bit
    %method	    the name of the method in which the log entry was made; also slow
    %message	  the log message itself (don't forget this part!)
    %newline	  the value of Environment.NewLine
    %timestamp	the milliseconds between the start of the application and the time the log entry was made
    %type	      the full typename of the object from which the log entry was made
    %username	  the Windows identity of user making the log entry; slow
    %identity	  the user name of the active user logging the entry; this one is less reliable than %username; note that using %identity has a significant performance impact and I don't recommend using it
    %thread     This will give you the name of the thread that the entry was made on (or the number if the thread is not named).
    %%	        a percent sign (%)
    
    numbers in the pattern e.g. %-5level
    x   = minimum number of charters, padded to the left        e.g. %6level = "  INFO"
    -x  = minimum number of charters, padded to the right       e.g. %-6level = "INFO  "
    .x  = maximum number of characters, truncated from the left e.g. %.4level = "RROR" (instead of "ERROR")
    -->
  </log4net>
</configuration>

You don’t need all the comments at the bottom, but I keep it in to remind me of the notation.

Leave a Reply

Your email address will not be published. Required fields are marked *