In my opinion, log4net is the best logging library available for .NET. It combines simplicity with extensibility and has proven its value in many other languages on a number of platforms through sister projects like log4j, log4Cxx, …

The official log4net FAQ recommends you to create a static reference to an ILogger instance in each class. Although you could state that this is the fastest way to access the logger for your class, this approach has a few drawbacks which make it worth considering a different way of doing things.

I feel that having a static logger instance in each class has the following disadvantages:

Fragmentation
every class has to have a static ‘log’ field, usually looking up the calling type through reflection to avoid copy-paste errors when copying the declaration to other classes
Barrier to start logging
if I want to log something from a class that does not have a log field yet, I’ll have to look for a class that has one so I can copy the field declaraction (because that’s how lazy I am :))
Lack of polymorphism
if something is logged in a method of a base class, I want to know what the instance is that actually triggered the logging. Using the standard static ‘log’ field approach, the name of the logger will be the name of the base class.

To get by this, I have created a static Logger util class which exposes the most commonly used ILogger functionality, but provides a way of passing the calling type so the correct logger will be used. For calling it from instance members it has an object parameter in which you can pass ‘this’, and for calls from static members, a Type parameter is provided.

class FooBar {
  private void Foo(int a) {
    if (Logger.IsDebugEnabled(this) {
      Logger.Debug(this, "a = " + a);
      Logger.DebugFormat(this, "a = {0}", a);
    }
  }
 
  private static void Bar(int a) {
    if (Logger.IsDebugEnabled(typeof(FooBar)) {
      Logger.Debug(typeof(FooBar), "a = " + a);
      Logger.DebugFormat(typeof(FooBar), "a = {0}", a);
    }
  }
}

Of course it is also possible to pass a string to explicitly pass the name of the logger if you are using descriptive functional names for the loggers:

public DataTable ExecuteQuery(string sql) {
  Logger.Debug("SQL", "Query: {0}", sql);
}

The Logger class has these kind of methods for all default log levels, as well as the IsLevelEnabled porperties. As a bonus, each log method has a levelFormat equivalent which accepts a string.Format() template and its parameters.

Some may say that obtaining a reference to the log4net logger on each call to the logging method will have a negative impact on performance, and that using a static logger instance in the class is faster. My experience is that the performance loss in using this static Logger utility class is theoretical and negligeable. The cost for writing the log entry (to a FileAppender for instance) will probably be much greater than looking up the logger instance.

You can get the Logger.cs file from this link (it is a .txt file for viewing inside your browser).