Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serilog DI in ASP.NET Core, which ILogger interface to inject?

Context

I've successfully configured Serilog in my ASP.NET Core application, only the DI part remains.

Question

Now I have two ILogger interfaces, one is Serilog.ILogger the other is Microsoft.Extensions.Logging.ILogger. Both works based on my Serilog config, and I do not know which to use? (I mean, after Serilog config in place Microsoft.Extensions.Logging.ILogger also correctly logging through Serilog, so my config is honored)

In case Microsoft.Extensions.Logging.ILogger I do know how to configure DI to make it work. However in case of Serilog.ILogger I see that Serilog has a static Log.Logger instance (probably a singleton)

I do not want to use this static property in my code, mainly for testing reasons, so I would like to to constructor inject it. The solution would be:

services.AddSingleton(Log.Logger); // Log.Logger is a singleton anyway

..but I am concerning about this singleton in a Web Application when many multiple threads will use this very same instance concurrently. Is it thread safe? If it is not, then what would be the solution to use Serilog.ILogger with DI?

like image 982
g.pickardou Avatar asked Apr 24 '20 15:04

g.pickardou


2 Answers

Choosing which interface to use within your application is a matter of taste, really. If you prefer Serilog's ILogger shorter method names (e.g. log.Error vs log.LogError), go with that, otherwise use the Microsoft's generic ILogger<>. You have control over all the dependencies you use in your own projects, so there's no strong technical reason to prefer one over the other.

You might be interested in reading this issue on Serilog's repo:

Should I use Microsoft.Extensions.Logging.ILogger or Serilog.ILogger?.

I personally use Serilog's ILogger across all my projects not only because I do prefer the shorter method names, but also because I prefer not to inject a logger in every single constructor of every class, and it's also easy to have a contextual logger for every class using Log.ForContext<>, which is useful when troubleshooting issues. E.g.

public class SomeService
{
    private readonly ILogger _log = Log.ForContext<SomeService>();
    // ...
}

public class SomeRepository
{
    private readonly ILogger _log = Log.ForContext<SomeRepository>();
    // ...
}

If you were developing a library though, I'd recommend using Microsoft's generic ILogger<>, of course, instead of taking a dependency on Serilog and force consumers of your library to also take a dependency on Serilog.


Log.Logger is thread-safe, thus registering as a singleton as you are doing above is correct if you want all classes to share the same instance (without SourceContexts) - nothing wrong with that.

like image 192
C. Augusto Proiete Avatar answered Sep 21 '22 14:09

C. Augusto Proiete


You should setup logging in your Program.cs file as part of the Host setup as described in the documentation (https://github.com/serilog/serilog/wiki/Getting-Started).

You should not manually add anything to your ServiceCollection as you show above.

For DI, you should inject the Microsoft generic ILogger<> as described in the documentation (https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/#create-logs). This ILogger<> instance will automatically log to all the providers you have configured (this could include Serilog but also any additional loggers configured such as file, console, etc.).

like image 36
crgolden Avatar answered Sep 20 '22 14:09

crgolden