29

According to https://learn.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?

Fabian Schmied
  • 3,885
  • 3
  • 30
  • 49
  • 2
    The first thing that comes on my mind is a Factory. Hope this article helps https://stackify.com/net-core-loggerfactory-use-correctly/. – afnpires Sep 29 '17 at 08:12
  • Either use the service locator anit-pattern, or expose a public static member that can be configured during startup to allow the static class ot function as desired. – Nkosi Sep 29 '17 at 11:51
  • @AlexandrePires Thanks for the link, I'll probably go for the "centrally located static class" option. – Fabian Schmied Oct 01 '17 at 13:24
  • @Nkosi Yeah, I'd actually like to know if there is an established pattern with `Microsoft.Extensions.Logging`. (As in "most people use a service locator" or "the ASP.NET Core team recommend using a singleton configured during startup".) – Fabian Schmied Oct 01 '17 at 13:26
  • Possible duplicate of [Implementation and usage of logger wrapper for Microsoft.Extensions.Logging](https://stackoverflow.com/questions/39610056/implementation-and-usage-of-logger-wrapper-for-microsoft-extensions-logging) – Dmitry Pavlov Jan 08 '18 at 17:12
  • 1
    @DmitryPavlov That question doesn't seem to mention logging from static places. – Fabian Schmied Jan 15 '18 at 06:59

4 Answers4

7

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.

Fabian Schmied
  • 3,885
  • 3
  • 30
  • 49
3

DI doesn't play nice with statics. They're sort of opposing design philosophies in one sense. ASP.NET made heavy use of statics (HttpContext, anyone?) and that made using dependency injection very difficult in many respects. ASP.NET Core chose to eschew statics and go with a 100% DI model.

In short, if you want to use dependency injection, your use of statics should dissipate. In most cases this is actually a very good thing. While they can be useful for certain things the are abused and greatly so in most cases. There's no much you can do with a static that you couldn't also do with a dependency injected class in singleton scope, and the latter gives you much greater abstraction and re-usability.

The one use of statics that can't really be replaced is extensions. Of course there's a whole school of thought arguing you should not ever use extensions, anyways. However, if you need or want to have extensions, then you either can't log from those or you'd have to pass in a logger instance as a param. In many cases, having to pass in a logger would severely limit the usefulness of the extension, so you'll likely land on not logging at all. However, even if you're of the school that believes extensions are fine and dandy, most would agree that they should also be limited in scope: i.e. they should just do something simple that doesn't need a lot of code. If that's the case, the need to actually log reduces dramatically.

Long and short, it simply boils down to design decisions you'll have to make. If you want to go the dependency injection route, statics will be a plague on your house, and you should avoid them as such.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • 4
    Thanks for the design discussion. My question was really about whether there is any suggested or established pattern for using `Microsoft.Extensions.Logging` in static contexts (as there is for log4net, for example). From the comments and answers so far, I deduce there doesn't seem to be one. Avoiding statics can often help avoid the problem, sure. But in a large application, there will be at least some situations where logging from a static context is useful or necessary, and I'd like to know how other people do this. – Fabian Schmied Mar 31 '18 at 20:04
  • Well, that depends. Presumably, if you're the one adding logging, then you're also the one in charge of the code around that. My point was that if you want to go the DI route, you should not write static code. That then negates the problem. It's simply an approach thing, if you want to use statics, then, you should go with something like Common.Logging. However, having playing both sides, I can say, at least for me, code quality, testability, and such, are dramatically improved when you simply start with the premise of just avoiding statics altogether. – Chris Pratt Apr 02 '18 at 13:00
1

You can use Serilog with something like this:

using Serilog;

private static readonly ILogger log = Log.ForContext(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
lost in binary
  • 544
  • 1
  • 4
  • 11
  • 2
    Thank you, that's a good idea. However, I was asking about a similar idiom or practice for `Microsoft.Extensions.Logging`. – Fabian Schmied Mar 31 '21 at 19:34
  • Yes, sorry, I didnt mean to answer your question directly. I just thought it would be helpful for others looking for a quick solution to your issue (I just had the same issue). – lost in binary Apr 01 '21 at 08:38
0

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.

Shad
  • 57
  • 1
  • 10
  • _I ran into a discussion about how to setup the Logger without depending on DI, and how bad are DI for static class_ Could you post a link to that discussion, please? – Fabian Schmied Oct 26 '19 at 17:53
  • Sorry, I have searched it for hours, didn't grab it :/ . It was on Microsoft forums. – Shad Oct 31 '19 at 08:34
  • @FabianSchmied Answer updated, I have found the said documentation :) the conversation I ran into was talking about this point. – Shad Nov 14 '19 at 10:21
  • RELATED : https://stackoverflow.com/questions/39610056/implementation-and-usage-of-logger-wrapper-for-microsoft-extensions-logging?noredirect=1&lq=1 – Shad Nov 15 '19 at 12:41
  • I am agree DI is bad for static class, it also happen on Spring Boot. static class won't be auto injection by spring boot auto wire, however there is a ugly workaround. – Cheung Jun 23 '22 at 09:04