Logging with log4net in .NET Core 3.0 Console App

I decided to write this post because with this seemingly simple thing, containing little bunch of code, I encountered extremely many problems and errors. In this post I will go through the setup of logging with log4net in .NET Core 3.0 console application and try to solve some of common issues you can encounter during this process.

Project setup

In this tutorial I will use .NET Core 3.0, log4net v2.0.8 and Visual Studio Community 2019. Start with creating a new project using Console App (.NET Core) template.

Log4Net Installation

When your solution is ready, you need to add log4net package to your project. To do this run following command in your nuget console:

PM> Install-Package log4net

If you’re using Visual Studio you can do this also through NuGet Package Manager window. Click RMB on your project in Solution Explorer window and choose Manage Nuget Packages…. Then search for log4net in Browse tab. Click on log4net and install the latest version of package.

NuGet Package installation window.

Add config file

Add new file called log4net.config in the project root level and populate it with the content from code frame below. It adds two types of log appenders – one which will save our application logs to file and second one which print them into console window.

<log4net>
    <root>
        <level value="ALL" />
        <appender-ref ref="console" />
        <appender-ref ref="file" />
    </root>
    <appender name="console" type="log4net.Appender.ConsoleAppender">
        <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date %level %logger - %message%newline" />
        </layout>
    </appender>
    <appender name="file" type="log4net.Appender.RollingFileAppender">
        <file value="main.log" />
        <appendToFile value="true" />
        <rollingStyle value="Size" />
        <maxSizeRollBackups value="5" />
        <maximumFileSize value="25MB" />
        <staticLogFileName value="true" />
        <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
        </layout>
    </appender>
</log4net>

Load Configuration

When configuring log4net in my project, I followed this tutorial. According to this, in point no. 3 I should add a line at the bottom of AssemblyInfo.cs file, but… I didn’t have this file. It turns out that in .NET Core 3.0 assembly file is generated automatically, and whole configuration should be done through csproj file. After quick research I’ve found out that configuration can be manually loaded from log4net.config file in the application code level, before any other code will be executed.

using log4net;
using log4net.Config;
using System;
using System.IO;
using System.Reflection;

namespace NetCore3Log4Net.Tutorial.ConsoleApp
{
    class Program
    {
        private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        static void Main(string[] args)
        {
            // Load configuration
            var logRepository = LogManager.GetRepository(Assembly.GetEntryAssembly());
            XmlConfigurator.Configure(logRepository, new FileInfo("log4net.config"));

            Console.WriteLine("Hello world!");

            // Log some things
            log.Info("Hello logging world!");
            log.Error("Error!");
            log.Warn("Warn!");

            Console.ReadLine();
        }
    }
}

If we run our program now, the console still displays only “Hello world!” text. The reason of this behavior is that by default log4net.config file is not copied to output directory, which means that Configure method which we’ve setuped in the previous step can’t find the file to load configuration. To fix this issue, right click on log4net.config file and choose Properties. Then change option under Copy to Output Directory build action into Copy if newer or Copy always.

Change Copy to Output Directory build action into Copy if newer.

Here it is! Our logging configuration is completed. We can see our logs in the console, and also they’re also stored in a text file, which is by default saved under the path:

~\<project_name>\bin\Debug\netcoreapp3.0

Colored Console Appender

Our logging is ready, but as you can see in the screen above, at first glance it’s difficult to distinguish which logs indicate application errors, and which are only informational. Hopefully, log4net provides specific appender to make console logs colorful. As I found here, it just needs replacement of the regular ConsoleAppender with the ColoredConsoleAppender and adding a few lines to the configuration file, containing log types mapping into individual colors. But, it doesn’t work for me.

After quite a long research about my issue and 100 times verifications that I did make no mistake in the configuration file, I found this repository. And exactly this comment:

https://gist.github.com/mizanRahman/4484020

I’ve followed the suggestion and replaced ColoredConsoleAppender with ManagedColoredConsoleAppender. Et… voila! Our colored console logging works perfectly.

And final look on log4net.config file:

<log4net>
  <root>
    <level value="ALL" />
    <appender-ref ref="console" />
    <appender-ref ref="file" />
  </root>
  
  <!--File Appender-->
  <appender name="file" type="log4net.Appender.RollingFileAppender">
    <file value="main.log" />
    <appendToFile value="true" />
    <rollingStyle value="Size" />
    <maxSizeRollBackups value="5" />
    <maximumFileSize value="25MB" />
    <staticLogFileName value="true" />
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%date [%thread] %level %logger - %message%newline" />
    </layout>
  </appender>
  
  <!--Console appender-->
  <appender name="console" type="log4net.Appender.ManagedColoredConsoleAppender">
    <mapping>
      <level value="INFO" />
      <forecolor value="Green" />
    </mapping>
    <mapping>
      <level value="WARN" />
      <forecolor value="Yellow" />
    </mapping>
    <mapping>
      <level value="ERROR" />
      <forecolor value="Red" />
    </mapping>
    <mapping>
      <level value="DEBUG" />
      <forecolor value="Blue" />
    </mapping>
    <layout type="log4net.Layout.PatternLayout">
      <conversionpattern value="%date [%thread] %-5level - %message%newline" />
    </layout>
  </appender>
</log4net>

I hope that my post will prove useful, help you prepare your logging mechanism quickly and make this process as nice as possible.

Sources

7 thoughts on “Logging with log4net in .NET Core 3.0 Console App

  1. Aw, this was quite a good post. In concept I have to place in writing similar to this moreover – spending time and actual effort to make a excellent article… but what / things I say… I procrastinate alot and no indicates often get something carried out.

    Like

  2. Thanks for this tip – it saved me a lot of frustration!
    I love the color logger, but I think log4net is starting to die in the .NET Core world.
    One thing – the color configs in the .config file are slightly different – before we had “HighIntensity” (e.g. “Red, HighIntensity” but this does not work any more. They need to be here:
    https://docs.microsoft.com/en-us/dotnet/api/system.consolecolor?redirectedfrom=MSDN&view=net-5.0

    Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s