user16276760
user16276760

Reputation:

why inject ILoggerFactory instead of ILogger<T>?

I read some asp.net core source code and get confused about injecting a Logger, let's take a middleware for example:

public class CookiePolicyMiddleware {
   private readonly RequestDelegate _next;
   private readonly ILogger _logger;

   public CookiePolicyMiddleware(RequestDelegate next, IOptions<CookiePolicyOptions> options, ILoggerFactory factory) {
      Options = options.Value;
      _next = next;
      _logger = factory.CreateLogger<CookiePolicyMiddleware>();
   }
   // ...
}

so why not we just inject ILogger directly as:

public class CookiePolicyMiddleware {
   private readonly RequestDelegate _next;
   private readonly ILogger<CookiePolicyMiddleware> _logger;

   public CookiePolicyMiddleware(RequestDelegate next, IOptions<CookiePolicyOptions> options, ILogger<CookiePolicyMiddleware> logger) {
      Options = options.Value;
      _next = next;
      _logger = logger;
   }
   // ...
}

because the default CreateDefaultBuilder method in Program.cs will call services.AddLogging() which will registe ILogger<> as Logger<> (https://source.dot.net/#Microsoft.Extensions.Logging/LoggingServiceCollectionExtensions.cs,42)

Isn't the second approach more straightforward?

Upvotes: 1

Views: 1605

Answers (1)

Tseng
Tseng

Reputation: 64150

Well, not sure if your example is a copy & paste mistake and if you were meant to inject it a middleware's .Invoke.

In constructor injection, they act same and ILogger<T> should be preferred unless you are manually instantiating types and want pass a specific logger to it.

Inside .Invoke, the case is different, because the middleware runs as singleton.

If you inject ILogger<T> in the middle ware constructor, it will create a logger with the log level at the point when it was first created.

If you change the log in appsettings.json while the application runs, it won't use the new values in the middleware logger and still log according to the old settings until the application is restarted.

This is because Logger<T> is only a wrapper around ILoggerFactory.Create to easily inject an typed logger w/o going over to the factory. The actual logger class is Logger. When the logger is created, it gets a copy of the filter options (see source).

So the changes in filter settings will only be applied on newly created loggers.

What happens in the code above is, that the factory is injected and the logger created in the Invoke method, which creates a new logger on every request, thus also loading the most recent filter and settings from appsettings.json and allows live changing of log level without restarting of the application.

Upvotes: 2

Related Questions