-
Notifications
You must be signed in to change notification settings - Fork 151
NLog GetCurrentClassLogger and Microsoft ILogger
Microsoft ILogger
should be injected as input-parameter for the class-constructor. Instead of having NLog Logger as static class variable:
public class MyClass
{
private readonly ILogger Logger;
public MyClass(ILogger<MyClass> logger)
{
Logger = logger;
}
}
This introduces some extra noise for all class constructors, which have to be resolved using dependency injection. But it also makes it possible to have multiple Host-applications within the same process. And also gives better isolation when running unit-tests in parallel.
NLog GetCurrentClassLogger
finds its Logger-Name using reflection tricks, but the generic Microsoft ILogger<MyClass>
extracts the Logger-Name from the generic-type. The Microsoft Dependency Injection has a small memory allocation overhead, as it will always allocate a new class-object for every ILogger<MyClass>
-parameter. And you must specify the generic ILogger<T>
as constructor-parameter, or else the dependency injection will fail with System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger'
.
If the class wants to generate output to multiple logger-objects, then NLog provides LogManager.GetLogger("BonusLogger")
. But for Microsoft ILogger then one must request ILoggerFactory as input:
public class MyClass
{
private readonly ILogger Logger;
private readonly ILogger BonusLogger;
public MyClass(ILogger<MyClass> logger, ILoggerFactory loggerFactory)
{
Logger = logger;
BonusLogger = loggerFactory.CreateLogger("BonusLogger");
}
}
.NET Core 2 introduced NullLogger and NullLoggerFactory so one can do this:
public class MyClass
{
private readonly ILogger Logger;
public MyClass(ILogger<MyClass> logger = null)
{
Logger = logger ?? NullLogger.Instance;
}
}
This can be useful in unit-testing scenarios, or for utility-classes where logging output is not always necessary.
.NET Core 3 introduced LoggerFactory.Create that can be useful for application startup logging, before the dependency injection system is fully initialized
var loggerFactory = LoggerFactory.Create(builder => builder.AddConsole());
var logger = loggerFactory.CreateLogger("StartupLogger");
logger.LogInformation("Starting...");
This can also be used for unit-testing scenarios, as each test-scenario can have their own local LoggerFactory.
Maybe consider using Lazy<LoggerFactory>
for creating a singleton, and then use it as custom fallback value (instead of NullLoggerFactory
).
If just wanting NLog and optimal performance then instead of using LoggerFactory.Create
, then use new NLogLoggerFactory
.
Microsoft ILogger
has support for structured logging with support of message-templates:
_logger.LogDebug("Logon from {userid}", request.UserId);
It is also possible to Capture custom LogEvent Properties
Pros of using NLog directly
- Best performance by remove layer of indirection and allowing deferred formatting.
- More options with the logger API, e.g.
Logger.WithProperty(..)
- Works in all platforms
- No Dependency Injection needed which saves complexity.
Pros of using NLog via Microsoft.Extensions.Logging:
- Fully integrated with ASP.NET Core, e.g. Microsoft also writes to the logger API and that will be also captured (and possible filtered) by NLog
- Writing to the logging abstraction will make your code log-library independent.
- Works well with .NET Core Dependency injection
- Load NLog configuration from appsettings.json, instead of using XML file NLog.config.