Logging
Introduction
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 we refer to the API of the implementing framework.
The API is used internally by the EPiServer assemblies for all logging, but it is also open to be used by any third-party product or implementation. It is recommended to use this API if you are developing modules and add-ons for the EPiServer platform.
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, the first step is retrieve a logger instance using the LogManager class. It is recommended that you 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 is also 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 always return a new instance regardless if any implementation has been found, so you can safely use the logger without performing any null checks.
Once the logger instance is available in your class, you can call any of the provided overloads depending on the criticality of the message. The examples below 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, it is not necessary to check this before writing a message as 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, it is recommended to use any of the overloads that takes a message formatter delegate and pass in a method that constructs your log message. This delegate will not be called until the enabled state has been verified, thus avoiding any unnecessary work if the logger is disabled.
Note that 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 that this compatibility layer is only 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 is providing 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. Note that 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 will use the first factory type it can find when scanning assemblies. It is therefore recommended that you make sure that the EPiServer.Logging.Log4Net assembly is removed before deploying another implementation.
See also
Last updated: Feb 23, 2015