Logging from static members with Microsoft.Extensions.Logging

Viewed 10200

According to https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging, the suggested way to use Microsoft.Extensions.Logging seems to be via dependency injection of ILogger objects.

What is the suggested pattern in situations where dependency injection doesn't work (or doesn't work well), such as in extension methods, type initializers, static properties, and other static members where passing an ILogger would be very cumbersome?

With log4net (which my team used before), a common pattern is this:

public static class SomeExtensions
{
  private static readonly ILog s_log = LogManager.GetLogger(typeof(SomeExtensions));

  public static void ExtensionMethod (this SomeType someType)
  {
    s_log.Info("...");
  }
}

Is there a similar established or recommended pattern with Microsoft.Extensions.Logging?

4 Answers

Thanks @chris-pratt and @shad for pointing out that the ASP.NET Core loggers approach doesn't play nicely with statics and for actually finding according documentation.

However, there are situations where avoiding statics is difficult or (subjectively) undesirable. So the point of my question was to ask if there was any established pattern for working with the Microsoft.Extensions.Logging in such situations.

The only real answer to that question was in a comment by @alexandre-pires, who pointed me to this Stackify article. Among other things, it shows how to set up a centralized ILoggerFactory that can be used from a static context. However, its conclusion is to just continue using NLog or Serilog and forwarding Microsoft.Extensions.Logging to that library.

You can use Serilog with something like this:

using Serilog;

private static readonly ILogger log = Log.ForContext(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

TLDR : No, never cross on any recommandation about, and mostly it's indicated to never use or use the least of static instance in .NET Core.

=== EDIT ===

The recommended way is to do not use static nor direct instantiation, and prefer correct DI or lifecycle instruction. DOC here

Long version :

For static class, I ran into a discussion about how to setup the Logger without depending on DI, and how bad are DI for static class.

From the discussion, it appear that static are not wanted in NET core application and have to be managed carefully in lifecycle.

As the Logger extension is a typical middleware using DI in NET Core, there is no (at my knowledge) recommended way to build it in static class, because "by design" it's not meant to be.

So you'd better roll your own or reuse another logger.

In case of it could help, here's the way to build a Logger without DI (but still not static) :

private readonly ILoggerFactory _logfactory;
private readonly ILogger _logger;

==== IN CONSTRUCTOR
_logfactory = (ILoggerFactory) new LoggerFactory();
_logger = new Logger<YourClass>(_logfactory);

Obviously, you can simplify it by not stocking the ILoggerFactory.

Hoped it answer your question.

===== EDIT ======

I had found in the lifecycle documentation the sentence that enforce what I said earlier : link here

The said sentence is :

Best practices are to:

  • Design services to use dependency injection to obtain their dependencies.
  • Avoid stateful, static classes and members. Design apps to use singleton services instead, which avoid creating global state.
  • Avoid direct instantiation of dependent classes within services. Direct instantiation couples the code to a particular implementation.
  • Make app classes small, well-factored, and easily tested.

So I think that, as it is the official Microsoft Documentation, it make the final point on the subject.

Related