Add NLog to your EPiServer site, the easy way

Though the API is still in pre release, I looked into adding NLog logging to EPiServer in an easy way, as a LoggerFactory. Turns out it’s not very difficult and the API seems to work perfectly ok.

Basically you have a logging factory, that needs to implement the ‘ ILoggerFactory’ interface

    public class NLoggerFactory : ILoggerFactory
    {
       public ILogger Create(string name)
        {
            return new NLogger(name);
        }
    }

The logger itself needs to implement the ‘ILogger’ interface. You will need to map the EPiServer levels to the NLog levels

   public class NLogger : ILogger
    {
       private readonly Logger logger;

       public NLogger(string name)
        {
            this.logger = LogManager.GetLogger(name);
        }

       public bool IsEnabled(Level level)
        {
            return this.IsEnabled(MapLevel(level));
        }

       public void Log<TState, TException>(
            Level level,
            TState state,
            TException exception,
            Func<TState, TException, string> messageFormatter) where TException : Exception
        {
            if (messageFormatter == null)
            {
                return;
            }

            LogLevel mappedLevel = MapLevel(level);

            if (this.IsEnabled(mappedLevel))
            {
                this.logger.Log(mappedLevel, messageFormatter(state, exception), exception);
            }
        }

         public bool IsEnabled(LogLevel level)
        {
            return this.logger.IsEnabled(level);
        }

        private static LogLevel MapLevel(Level level)
        {
            switch (level)
            {
                case Level.Trace:
                    return LogLevel.Trace;
                case Level.Debug:
                    return LogLevel.Debug;
                case Level.Information:
                    return LogLevel.Info;
                case Level.Warning:
                    return LogLevel.Warn;
                case Level.Error:
                    return LogLevel.Error;
                case Level.Critical:
                    return LogLevel.Fatal;
                default:
                    throw new ArgumentOutOfRangeException("level");
            }
        }
    }

Last you will need to add an attribute to your assembly, registering the factory as a LoggerFactory

[assembly: LoggerFactory(typeof(NLoggerFactory))]

To take advantage of this with your custom logging you will of course need to use the new LogManager in your code, like

private ILogger logger = LogManager.GetLogger(typeof(MyController));

That’s it.

The complete code is on GitHub.

It is available on NuGet as well, as a pre-release package, as the API is still in pre-release. You will need to enable "Include Prerelease" to install.

6 thoughts on “Add NLog to your EPiServer site, the easy way

  1. Great write-up Jeroen and good to hear that you found it easy to implement! Hopefully this is just the first of many implementations for different loggers.

    Some minor things that I thought I would clarify in regards to the registration of the logger factory. The logging API will (currently) only use the first logger factory it finds when scanning for assembly attributes. This means two things, you don’t have to worry about two logs unless you or any third party assemblies are using log4net directly, but you do need to worry about that the scanner finds the log4net factory before your own one. This can be ensured by removing the EPiServer.Logging.Log4Net assembly, but you can also get around it by manually registering your LoggerFactory by calling the LogManager.Instance.AddFactory() method. If a factory has been manually assigned, this will always be selected before anyone found through attribute scanning.
    This behavior is very much pre-release behavior though, as we are considering adding support for running multiple logger types in parallel.

    Like

    1. Hi Henrik,
      Thnx for the feedback. Manually registering is a safer option then I guess. In an initialization module I assume?
      Few questions though.
      -As EPiServer.CMS.Core has a dependency on “EPiServer.Logging.Log4Net”, won’t it just come back after it gets updated? In the case of deleting it I mean.
      -My assembly got registered with the attribute, but EPiServer also logged, so I guess some parts of EPiServer still log to log4net directly? Or are two factories supported already? I tested with the latest release.

      Like

      1. Manually registering would be the safe option, but in this specific case I would do it even earlier since there are logging happening during the initialization as well.

        Yes, that suggestion is somewhat problematic at the moment. We made the decision to keep that dependency for now as not all products have been updated to make use of the Logging API yet and we didn’t want to unexpectedly stop peoples existing logging from happening. But the plan is to remove it in the near future, but expect there to be some clear communications around this at the time.

        There should not be any logging happening directly to log4net in the CMS.Core, CMS.UI or Commerce. But if you have Find install it will be. If this is not the case, could you send over a log4net log or a list of classes that are logging to log4net and I can have a look at it?

        Like

  2. Thnx Henrik Fransas & Valdis.
    @Henrik Nystrom: Initialzing earlier stopped EPiServer logging to log4net on initialization.
    @Valdis, the package has been accepted. Just uploaded a new version with the earlier initialization, hopefully it will be accepted tomorrow. Don’t forget to enable pre releases, else you will not see it.

    Like

Leave a Reply to Valdis Iljuconoks (@tech_fellow) Cancel 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