Logging
Describes the logging functionality in Optimizely Content Management System (CMS), and how to implement logging with log4net, which is one of the logging providers that can be used.
Note
If you ever want to change the underlying logging framework or are using Optimizely Digital Experience Platform (DXP), use the log abstraction
EPiServer.Logging.LogManager
.
The Logging API shipped with Optimizely Content Management System (CMS) is an abstraction for writing log messages from the system. It does not compete with existing logging frameworks such as log4net; it works as a façade for such frameworks. To manage the logger's configuration and output, refer to the API of the implementing framework.
The API is used internally by the CMS assemblies for logging, but it is also open to be used by any third-party product or implementation. Use this API to develop modules and add-ons for the CMS platform.
Note
When you create 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.
Log 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 that uses it and store the logger in a static variable, such as:
private static readonly ILogger Logger = LogManager.GetLogger();
This code creates a logger instance with the same name as the type where it is instantiated, including namespace. You can also explicitly pass in another type or name directly to the logger, which could be useful to simulate log messages from another source. This method is guaranteed to return an instance, regardless of whether it finds any implementation, 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 provided overloads, depending on the message's criticality. The following examples show the Debug level, but equivalent methods are available for other levels (Trace, Information, Warning, Error, Critical).
// 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 does this before it tries to write it. If there is a cost to constructing the log message, such as an expensive value serialization, use any overloads that take 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 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' ILoginterface that matches their log4net equivalents, which in most cases should enable 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.
Implement the API
CMS provides an implementation for log4net through the EPiServer.Logging.Log4Net
package, but it is relatively simple for anyone to replace this implementation with another.
Implement ILogger
and ILoggerFactory
.
ILogger
writes a message of a specified level to the logging framework of choice.ILoggerFactory
createsILogger
instances.
Add the LoggerFactoryAttribute
to your assembly to register the implementation and define 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 it uses the first factory type it can find when scanning assemblies. Make sure you remove the EPiServer.Logging.Log4Net
assembly before you deploy another implementation.
Updated 6 months ago