Skip to content

Custom extension of Logger interface

Rolf Kristensen edited this page May 25, 2024 · 26 revisions

Introduction

There can be different reasons for extending the NLog logging interface:

  • Extend logging interface to automatically add relevant context when logging.
  • Create an abstract interface to avoid direct NLog dependency in source-code.

Abstract Interface Libraries

There already exists several libraries that provides an abstract interface:

Extended logging interface

There are two ways to extend the NLog Logger.

  • Inherit from the NLog Logger and add your own custom extensions.
  • Create a custom wrapper around the NLog Logger and forward the logevents to the NLog Logger.

Custom Wrapper and callsite

NLog has a special Callsite feature, that allows it to automatically capture the location in source code that performed the logging. This feature has a huge overhead (logging becomes 20 times slower, together with lots of bonus allocations), because the capture of StackTrace and scanning for source location is expensive.

When creating a custom wrapper around the NLog Logger-interface (or extension methods), then the callsite logic will think the custom wrapper is the origin of the log-statement. This can be solved by using Logger.Log(Type wrapperType, LogEventInfo logEvent)-method when writing the LogEvent, and providing the typeof(MyCustomWrapper) as first parameter.

public class MyLogger
{
   private readonly NLog.Logger Logger;

   public MyLogger(string name)
   {
      Logger = NLog.LogManager.GetLogger(name);
   }

   public void WriteMessage(string message)
   {
      NLog.LogEventInfo logEvent = NLog.LogEventInfo.Create(NLog.LogLevel.Info, null, message);
      Logger.Log(typeof(MyLogger), logEvent);
   }
}

When the custom wrapper provides its own Type as wrapperType, then the callsite logic will not see the custom wrapper as being the origin of the log-statement. If extending the NLog Logger-interface without providing the correct wrapperType, then Callsite will stop working.

Note NLog 5.0 adds full support for using Caller Information-attributes that was introduced with .NET 4.5. When having called LogEventInfo.SetCallerInfo(...) then StackTrace capture is not needed for the Callsite feature.

public class MyLogger
{
   private readonly NLog.Logger Logger;

   public MyLogger(string name)
   {
      Logger = NLog.LogManager.GetLogger(name);
   }

   public void WriteMessage(string message,
        [CallerMemberName] string callerMemberName = "",
        [CallerFilePath] string callerFilePath = "",
        [CallerLineNumber] int callerLineNumber = 0)
   {
      NLog.LogEventInfo logEvent = NLog.LogEventInfo.Create(NLog.LogLevel.Info, null, message);
      logEvent.SetCallerInfo(null, callerMemberName, callerFilePath, callerLineNumber);
      Logger.Log(typeof(MyLogger), logEvent);
   }
}
Clone this wiki locally