Logging with log4net

2023-01-11 C# log4net logging DebugAppender LevelRangeFilter

For user support I usually found very useful to setup some kind of logging for each program I work on. A very flexible logging solution is log4net. It provides nice separation of actual logging in the application and configurable output. For long-running applications it also allows to change the configuration and add more details in the runtime.

Here is how to setup the logging in C# project. The App.config refers to log4net.config via appSettings section

<appSettings>
  <add key="log4net.Config" value="log4net.config" />
  <add key="log4net.Config.Watch" value="True" />
</appSettings>

The log4net.config sets up the minimal level of logging and appenders. I usually use the logging to inform about application progress (prints to standard output) and to produce rolled log

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <log4net>
        <root>
            <level value="Info" />
            <appender-ref ref="file" />
            <appender-ref ref="console" />
            <appender-ref ref="debug" />
        </root>

        <appender name="debug" type="log4net.Appender.DebugAppender">
            <category value="" />
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%file(%line): %message%newline" />
            </layout>
        </appender>
        
        <appender name="console" type="log4net.Appender.ConsoleAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%message%newline" />
            </layout>
        </appender>

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

A nice bonus is DebugAppender which prints into Visual Studio output console, including the place in source code.

Each appender can also filter entries, e.g. using LevelRangeFilter in the appender section.

<filter type="log4net.Filter.LevelRangeFilter">
  <levelMin value="DEBUG" />
  <levelMax value="FATAL" />
</filter>

In the application then just initialize a logger and use it

public class CodeManager
{
    private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

    public void GenerateOutputs()
    {
        log.Info("Generating outputs");

        ...

        try 
        {

        }
        catch(Exception e) 
        {
            log.Error($"Failed processing {file}: {e}");
        }
    }
}