Making use of Sitecore’s Switcher to manage logger contexts

I’m sure you’ve used Sitecore.Common.Switcher<T> in your Sitecore projects numerous times, for example when disabling all security checks when editing items in code using the SecurityDisabler:

 using(new SecurityDisabler()){
   // Edit Sitecore items
 }

SecurityDisabler indirectly inherits Sitecore.Common.Switcher<T> which allows such behavior. There are other examples such as SiteContextSwitcher or DatabaseSwitcher. The cool thing about this is that it allows you to disable security or switch site or context item for a limited part of the code only. Outside the using statement everything runs normally using the normal context available.

This context switching also applies to other methods that have been called inside the using scope directly or indirectly. So you don’t have to edit or pass special parameter to any other parts of your application.

Last week I had the need to create a custom logger that allows me to log communication requests and responses with a third-party service. Other info or errors logged should be logged in Sitecore’s default log, even code in the same integration class.

The HTTP client needed gets created in a helper class which already has logging that logs the requests. In my integration class, I receive the response and log it. In order to achieve the above requirements with the least amount of code changes, I decided to use Sitecore’s Switcher class.

Logger Class

Luckily our project had a wrapper class around Sitecore’s log to reduce future code changes for such requirements.

public class Logger : ILogger
{
   public void Debug(string message)
   {
       Sitecore.Diagnostics.Log.Debug(message, this);
   }

   public void Info(string message)
   {
       Sitecore.Diagnostics.Log.Info(message, this);
   }
}

As I mentioned this logger class was used everywhere in our system, in our integration class and in other helpers and classes that the integration class uses.

LoggerSwitcher

I created a new class named LoggerSwitcher which inherits Switcher<string>. The string parameter determines that I will be using a string to identify my context using the logger name.

I only created a constructor in this class that takes loggerName as a parameter, which is then passed to the base class (Switcher) constructor, and that’s it, our logger Switcher is ready:

public class LoggerSwitcher : Switcher<string>
{
   public LoggerSwitcher(string loggerName)
   : base(loggerName)
   {}
}

All switching logic and state management is controlled in the Switcher class.

To allow my logger class to be aware of this logger switching I had to update our Logger wrapper class:

public class LogEntry : ILogger
{
   private ILog _logger;

   protected void GetCustomLogger()
   {
      var loggerName = LoggerSwitcher.CurrentValue;

      if (string.IsNullOrWhiteSpace(loggerName) == false)
      _logger = LogManager.GetLogger(loggerName);
   }

   public void Debug(string message)
   {
      GetCustomLogger();

      if (_logger != null)
         _logger.Debug(message);
      else
         Sitecore.Diagnostics.Log.Debug(message, this);
   }

   public void Info(string message)
   {
      GetCustomLogger();

      if (_logger != null)
         _logger.Info(message);
      else
         Sitecore.Diagnostics.Log.Info(message, this);
   }

The key part here is the LoggerSwitcher.CurrentValue. CurrentValue is a static property of type T (Switcher<T>) part of the Switcher class that returns the value passed to its constructor, which is in our case the logger name.

If a LoggerSwitcher scope is wrapping the current execution of the logger class, the CurrentValue will contain the logger name passed, otherwise it will by null. So in my GetCustomLogger I check if there is a CurrentValue, and if there is I initialize my _logger field with the new custom logger to be used, otherwise it will keep the _logger null and thus use Sitecore’s default logger class.

The way I use this whole logging mechanism now looks like this:

_logger.LogInfo("This will be logged in Sitecore's default log file");
using (new LoggerSwitcher("MyCustomLoggerName"))
{
   _logger.LogInfo("This will be logged in my new custom log file");

   // logic here
}
_logger.LogInfo("This will be logged in Sitecore's default log file");
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s