Hide menu Last updated: Sep 21 2015

Logging

This topic describes the logging functionality in Episerver, and how to implement logging with log4net, which is one of the logging providers that can be used. 

How it works

The Logging API shipped with Episerver is an abstraction for writing log messages from the system. It is not meant to compete with existing logging frameworks such as log4net, as it merely works as a façade for such frameworks. To manage the configuration and output of the logger, refer to the API of the implementing framework.

The API is used internally by the Episerver assemblies for all logging, but it also is open to be used by any third-party product or implementation. Use this API if you are developing modules and add-ons for the Episerver platform.

Note: When creating new CMS sites using the Visual Studio integration, the package EPiServer.Logging.Log4Net is installed by default, which is the log4net implementation of the API.

Logging a message

When you want to log a message, retrieve a logger instance using the LogManager class. Only retrieve the logger once for each class where it is used and store the logger in a static variable, such as:

private static readonly ILogger Logger = LogManager.GetLogger();

This creates a logger instance with the same name as the type where it is instantiated, including namespace. It also is possible to explicitly pass in another type or name directly to the logger, which could be useful if you want to simulate log messages from another source. This method is guaranteed to return a new instance, regardless if any implementation is found, so you can safely use the logger without performing any null checks.

After the logger instance is available in your class, you can call any of the provided overloads, depending on the criticality of the message. The following examples show the Debug level, but equivalent methods are available for all other available levels (Trace, Information, Warning, Error, Critical) as well.

// Log simple message
logger.Debug("Some message");

// Log message and exception
logger.Debug("Some message", exception);

// Log message formatted with any number of arguments
logger.Debug("Some format {0},{1}", arg0, arg1);

// Log object state formatted with the provided formatting method
logger.Debug(someObject, s => "someObject is currently: " + s.SomeCostlyMethod());

// Log object state and exception formatted with the provided formatting method
logger.Debug(someObject, someException, (s,ex) => "someObject: " + s.SomeCostlyMethod() + " threw an exception: " + ex);

While the API exposes an IsEnabled method on the logger, you do not need to check this before writing a message because it is done before it tries to write the message. If there is a cost to constructing the log message, such as an expensive serialization of a value, use any of the overloads that takes a message formatter delegate and pass in a method that constructs your log message. This delegate is not called until the enabled state is verified, thus avoiding unnecessary work if the logger is disabled.

Note: Most of the logging methods of the logger are provided through extension methods, so it is necessary to import the EPiServer.Logging namespace to get easy access to these.

Backwards compatibility

If you are currently using log4net for logging and want to start using the new API in an existing project, there is a dedicated namespace called EPiServer.Logging.Compatibility that will help with the migration. This namespace contains a LogManager class and an ILog interface that matches their log4net equivalents which in most cases should enable a simple a search-and-replace between log4net and EPiServer.Logging.Compatibility to maintain the same logging.

Note: This compatibility layer only is suggested as a short term solution to speed up the migration and that we are recommending everyone to use the standard API in the longer term.

Implementing the API

Episerver provides an implementation for log4net through the EPiServer.Logging.Log4Net package but it is relatively simple for anyone to replace this implementation with another.

To create an implementation, there are two interfaces that need to be implemented; ILogger and ILoggerFactory. ILogger is responsible for writing a message of a specified level to the logging framework of choice and ILoggerFactory for creating new ILogger instances.

The implementation is registered by adding the LoggerFactoryAttribute to your assembly, defining the type of your logger factory. The type implementing ILoggerFactory is required to have a public parameter-less constructor.

[assembly: LoggerFactory(typeof(MyLoggerFactory))]

The Logging API currently only supports one logger type and the API uses the first factory type it can find when it scans assemblies. Make sure you remove the EPiServer.Logging.Log4Net assembly before you deploy another implementation.

Related topic

Comments