An introduction to the Common Logging API for .NET

Most developers know that logging is an invaluable tool especially when trying to troubleshoot issues with code running on production. In .Net, there is a plethora of tools to choose from such as Log4Net, nLog, Elmah etc. Each tool has its pros and cons so the decision on which one to use is usually based around the project requirements, complexity, performance and so on.

What the Common Logging API brings to the game is a lightweight “infrastructure” logging platform that allows developers to focus on the logging requirements instead of the logging tools and required configuration. The Common Logging API abstracts the logging requirements of any project making it ridiculously easy to swap logging providers should the need arises at any point.

The current Common Logging release is 3.3.0 and the source code can be found on GitHub. Unfortunately, you will find that the documentation is slightly out of date, especially the ReadMe file on GitHub. That’s one downside of open-source projects so I would recommend that you grab the latest dlls from NuGet.

So, let’s get started with the walk through on how to add and use the API in your application.

1. Add the Common Logging API to your project

Create a new console/desktop/web project using Visual Studio. In this example I will work with a console app. Open NuGet (console or GUI) and search for “Common Logging”. Install the package as per the picture below:

Your project references should now look like this:
Solution Explorer References

Next we need to add the necessary configuration settings for the API. There are two ways to configure the API:

  • An xml configuration
  • Programmatically

In this example I will go with the xml option. If you are using a console app, right click on the project and add an app.config file (application configuration file). Open the file in Visual Studio and paste the following xml. If you are adding the xml in an app.config already in use, make sure you only copy paste the relevant parts and don’t overwrite your settings.

    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging"/>
      <factoryAdapter type="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging">
        <arg key="level" value="ALL"/>
        <arg key="showLogName" value="true"/>
        <arg key="showDataTime" value="true"/>
        <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff"/>

This will configure the API and also create a ConsoleOutLoggerFactoryAdapter, a built-in adapter and will be used to output the logs. The adapter is configured to capture all levels of logs. There are also other, third-party adapters you can use with the Common Logging API but more on this later.

2. Using the Common Logging API in code.

The first thing we need to do is instantiate a log object that implements the ILog interface. This can all be done in one line, like this:
private static ILog log = LogManager.GetCurrentClassLogger();

That’s all. We are now ready to start logging things. The ILog interface comes with a variety of methods that cover all log levels from Trace to Fatal and allow you to log messages and/or objects and format the output. The full ILog definition can be found in the documentation. However for the purpose of this example we will use the following methods:

void Trace(object message);  
void Debug(object message);  
void Info(object message);  
void Warn(object message);  
void Error(object message);  
void Fatal(object message);  

Now, let’s add some logging commands to our application. To log a message, you can call the ILog implementation with the appropriate level, like this:

log.Debug(“hello world”);

To put this to practice, I’ve added the following sample methods to the Program class and then I call them accordingly:

NOTE: the LogManager.GetCurrentClassLogger() has been marked as obsolete. Now, when you need to instantiate a Logger for your current class you need to use the new syntax: LogManager.GetLogger<YourCurrentClassName>();

When I run the application, I get in the follwing output
Full logging output

As you can see, it took minimal effot to start logging messages!

3. Changing the minimum log level

If you want to only capture and output messages of a specific level and above, then you need to change the config settings. Let’s turn TRACE level off for now. Open the app.config and edit the following line as per the example below:
Turn Trace level off

If you run the application again, you will notice that only logs with level Debug and above are displayed. This is because of the configuration change.

4. Log level filtering and deferred execution

Sometimes, you may only want to log a message if the appropriate level is switched on. In the past, you would do something like this:

if (log.IsDebugEnabled)  
  log.Debug("Calling an expensive argument: {0}”, someArgument);

A very handy feature of the Common.Logging interface is the ability to use lamda expressions to do the same thing as the code above but also defer the execution of any code inside the lamda expression until the message is actually logged. So now we can rewrite the code like this:

log.Debug( m => m("Calling an expensive-slow argument: {0}”, someArgument));  

Awesome, right?

5. Logging Adapters

The Common Logging API comes with the following 3 adapters straight out-of-the-box

  • NoOpLoggerFactoryAdapter – Does nothing
  • ConsoleOutLoggerFactoryAdapter – Logs to console
  • TraceLoggerFactoryAdapter – Logs to trace so you can use the “Debug View” in VS to check the logs

Supported third-party adapters:

  • Log4NetLoggerFactoryAdapter – Log4Net
  • NLogLoggerFactoryAdapter - NLog
  • Enterprise Library Logging Adapter – Microsoft’s Enterprise Library Logger
  • ElmahAdapter – Write logs to Elmah

In my next post, I describe how you can integrate Log4Net with the Common Logging API.

  • Share this post on
comments powered by Disqus