Chapter 13. Common Logging

13.1. Introduction

Spring uses a simple logging abstraction in order to provide a layer of indirection between logging calls made by Spring and the specific logging library used in your application (log4net, EntLib logging, NLog). Many other .NET projects have done a similar task. As such this library is to be moved out of the Spring project and into a more general open source project. Stay tuned for further information.

This logging abstraction goes by the name 'Common.Logging' and is simply a more packaged version of the logging abstraction used inside the iBATIS project. Many thanks to them! The library is available for .NET 1.0, 1.1, and 2.0 with both debug and strongly signed assemblies.

Spring ships with the base logging library, Common.Logging, that provides console and trace based loggers. The libraries are located under lib/logging. There are two enterprise logging implementations, one for log4net 1.2.9 and another for log4net 1.2.10. The need for two log4net versions is due to the fact that each is signed with a different strong key making assembly redirection impossible.

Note that it is not the intention of this library to be a replacement for the many fine logging libraries that are out there. The API is incredibly minimal and will very likely stay that way. Only use this library if you truely need to support multiple logging APIs.

13.2. Using Common.Logging API

Usage of the Logging API is fairly simple. First you need to obtain a logger from the LogManager and call the appropriate logging method:

using Common.Logging; 
... 
ILog log = LogManager.GetLogger(this.GetType()); 
log.Debug("hello world");

A logger instance provides the following methods for logging:

public interface ILog
{
  void Debug( object message );
  void Debug( object message, Exception exception );
  void Error( object message );
  void Error( object message, Exception exception );
  void Fatal( object message );
  void Fatal( object message, Exception exception );
  void Info( object message );
  void Info( object message, Exception exception );
  void Warn( object message );
  void Warn( object message, Exception exception );

  bool IsDebugEnabled { get; }
  bool IsErrorEnabled { get; }
  bool IsFatalEnabled { get; }
  bool IsInfoEnabled  { get; }
  bool IsWarnEnabled  { get; }
}

You can get a reference to an instance of an ILog using the LoggingManager class. Its API is shown below:

public sealed class LogManager
{
  public static ILog GetLogger( Type type ) ... 
  public static ILog GetLogger( string name ) ...

  public static ILoggerFactoryAdapter Adapter ...

}

The Adapter property is used by the framework itself.

13.3. Configuring Logging

There are 2 ways of configuring logging in your application - either declaratively or programmatically.

13.3.1. Declarative Configuration

Logging configuration can be done declaratively in your app.config

<configuration>
  <configSections>
    <sectionGroup name="common">
      <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
    </sectionGroup>
  </configSections>

  <common>
    <logging>
      <factoryAdapter type="Common.Logging.Simple.TraceLoggerFactoryAdapter, Common.Logging">
        <arg key="level" value="DEBUG" />
        <arg key="showLogName" value="true" />
        <arg key="showDataTime" value="true" />
        <arg key="dateTimeFormat" value="yyyy/MM/dd HH:mm:ss:fff" />
      </factoryAdapter>
    </logging>
  </common>
</configuration>
[Note]Note

The concrete set of <arg> elements you may specify depends on the FactoryAdapter being used.

13.3.2. Configuring Logging in your code

You may manually configure logging by setting a LoggerFactoryAdapter in your code.

// create properties
NameValueCollection properties = new NameValueCollection();
properties["showDateTime"] = "true";

// set Adapter
Common.Logging.LogManager.Adapter = new Common.Logging.Simple.TraceLoggerFactoryAdapter(properties);
[Note]Note

The concrete set of properties you may specify depends on the FactoryAdapter being used.

13.4. Logging Adapters

There are simple out-of-the-box implementations coming with Common.Logging itself. For connecting to log4net, separate adapters do exist.

13.4.1. NoOpLoggerFactoryAdapter

This is the default FactoryAdapter if logging is not configured. It simply does nothing.

13.4.2. ConsoleOutLoggerFactoryAdapter

ConsoleOutLoggerFactoryAdapter uses Console.Out for logging output.

Table 13.1. Configuration Properties

KeyPossible Value(s)Description
levelAll Debug Info Warn Error Fatal OffDefines the global maximum level of logging.
showDateTimetrue|falseoutput timestamp?
showLogNametrue|falseoutput logger name?
dateTimeFormatany formatstring accepted by DateTime.ToString()defines the format to be used for output the timestamp. If no format is specified DateTime.ToString() will be used.

13.4.3. TraceLoggerFactoryAdapter

TraceLoggerFactoryAdapter uses System.Diagnostics.Trace for logging output. For viewing it's output you can use any tool that is capable of capturing calls to Win32 OutputDebugString() - e.g. the tool "DebugView" from www.sysinternals.com.

Table 13.2. Configuration Properties

KeyPossible Value(s)Description
levelAll Debug Info Warn Error Fatal OffDefines the global maximum level of logging.
showDateTimetrue|falseoutput timestamp?
showLogNametrue|falseoutput logger name?
dateTimeFormatany formatstring accepted by DateTime.ToString()defines the format to be used for output the timestamp. If no format is specified DateTime.ToString() will be used.

13.4.4. Log4NetLoggerFactoryAdapter

There are two implementations, both configured similarly.

  • Common.Logging.Log4Net

    is linked against log4net 1.2.10.0

  • Common.Logging.Log4Net129

    is linked against log4net 1.2.9.0

The only difference is in the type specified to the factory adapter. Both Adapters accept the following configuration properties:

Table 13.3. Configuration Properties

KeyPossible Value(s)Description
configType

FILE

FILE-WATCH

INLINE

EXTERNAL

INLINE will simply call XmlConfigurator.Configure()

EXTERNAL expects log4net being configured somewhere else in your code and does nothing.

FILE, FILE-WATCH: see property "configFile" below.

configFile<path to your log4net.config file>if configType is FILE or FILE-WATCH, the value of "configFile" is passed to XmlConfigurator.Configure (FileInfo) / ConfigureAndWatch(FileInfo) method.

The example below will configure log4net 1.2.10.0 using the file log4net.config from your application's root directory by calling XmlConfigurator.ConfigureAndWatch():

 <common>
    <logging>
      <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net">
        <arg key="configType" value="FILE-WATCH" />
        <arg key="configFile" value="~/log4net.config" />
      </factoryAdapter>
    </logging>
  </common>

For log4net 1.2.9, change the assembly name Common.Logging.Log4Net129

13.5. Advanced Logging Tasks

13.5.1. Implementing a custom FactoryAdapter

f you want to plug in a new, yet unsupported logging library, you need to implement the Common.Logging.ILoggerFactoryAdapter interface.

Important: Any implementation must provide a public constructor accepting a NameValueCollection parameter as shown in the example below:

public class MyLoggingFactoryAdapter :  ILoggerFactoryAdapter
{
  public MyLoggingFactoryAdapter(NameValueCollection properties)
  {
     // configure according to properties
  }

  public ILog GetLogger(Type type) { ... }
  public ILog GetLogger(string name) { ... }
}