Extend the Common.Logging API with Log4Net

In an earlier post I described how the Common.Logging API can help us abstract logging in our application by hiding the implementation details and allowing us to use different logging providers (NLog, Log4Net etc) in a modular, plug-n-play way.

In this post, we will examine how to combine Common.Logging with Log4Net in order to output log messages to a file.

1. Install the right NuGet packages in the right order

Before beginning, I will assume that all your assemblies already implement the Common.Logging API. If not, then go through my post to see how to add logging to your assembly(ies). The Log4Net NuGet package should only be added to the executable assembly of your solution. So if your solution consists of 1 console and 3 library projects then your NuGet packages should be installed like this:

  • Library Projects: Common.Logging
  • Console Project:
    • Commong.Logging
    • Common.Logging.Log4Net

Unfortunately, if you add the Common.Logging.Log4Net last, then you will come across issues at run time, because the Log4Net provider also installs a specific, most likely earlier, version of Common.Logging. For this reason, I would advise you to remove all versions of Common.Logging and let Common.Logging.Log4Net to install it as a dependency. I know, this is messed up!

So, to re-iterate, these are the steps you need to follow:

  1. Remove the Common.Logging NuGet package from all projects in the solution
  2. Install the Common.Logging.Log4Net package to the console (executable) project
  3. Use the "Manage NuGet Packages for solution" (right-click on the solution in Solution Explorer) option to re-add the already installed Common.Logging to all the other projects.

2. Configure Log4Net

By default, adding the Common.Logging.Log4Net package will not do anything. No outputs, no logs. You need to tell (configure) Log4Net how and where to log things and this can be done in a number of ways as per the Log4Net documentation. I have attached a simple configuration example below:

<log4net>
    <appender name="MyRollingFileAppender" type="log4net.Appender.RollingFileAppender">
      <file value="C:\Temp\Mylog.txt" />
      <appendToFile value="true"/>
      <rollingStyle value="Size" />
      <maximumFileSize value="10MB" />
      <staticLogFileName value="true" />
      <maxSizeRollBackups value="10" />
      <layout type="log4net.Layout.PatternLayout">
        <header value="DateTime | Thread | Level | ClassName | Message&#13;&#10;" />
        <conversionPattern value="%date | %thread | %-5level | %logger | %message%newline" />
      </layout>
    </appender>

    <root>
      <level value="ALL" />
      <appender-ref ref="MyRollingFileAppender" />
    </root>
  </log4net>

A quick explanation of the settings above:

  • appender name="MyRollingFileAppender" : the name of your appender
  • type="log4net.Appender.RollingFileAppender" : it outputs to a file and rolls over to a new file when a precondition is met
  • file value="C:\Temp\Mylog.txt" :the destination file where all the logs will be written
  • appendToFile value="true" : append or overwrite
  • rollingStyle value="Size" : the roll precondition is Size
  • maximumFileSize value="10MB": roll the file when it reaches 10MB
  • maxSizeRollBackups value="10": how many rolled files to keep. After that, the files will be overwritten starting with the earliest.
  • level value="ALL": output all messages. You will want to change this in production to ERROR and only set it to ALL or DEBUG if you need to troubleshoot. The reason for this is that if you set it ALL, then your log files will be full of noise and may grow substantially in size. Change this with care!

There are a lot more settings for Log4Net so please make sure you check the official documentation to find the right logging solution for you.

3. Plug the Log4Net in Common.Logging

Finally, we will add the Log4Net logger to the Common.Loggin API to allow logs from all referenced assemblies to be written. Open the same app/web.config as in step 2 and append the following:

<configSections>
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
    </sectionGroup>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>
  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4Net">
        <arg key="configType" value="INLINE" />
      </factoryAdapter>
    </logging>
  </common>

This is all you need to configure solution-wide logging using the Common.Logging API and the Log4Net provider.

You can download the complete App.config file here.

Did you find this useful? Let me know if you come across any problems setting this up.

P.S Make sure you follow me on @christosmatskas for more up-to-date news, articles and tips.