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.