Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 354 Vote(s) - 3.51 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Should I take ILogger, ILogger<T>, ILoggerFactory or ILoggerProvider for a library?

#1
This may be somewhat related to [Pass ILogger or ILoggerFactory to constructors in AspNet Core?](

[To see links please register here]

), however this is specifically about **Library Design**, not about how the actual application that uses those libraries implement its logging.

I am writing a .net Standard 2.0 Library that will be installed via Nuget, and to allow people using that Library to get some debug info, I'm depending on [Microsoft.Extensions.Logging.Abstractions](

[To see links please register here]

) to allow a standardized Logger to be injected.

However, I'm seeing multiple interfaces, and sample code on the web sometimes uses `ILoggerFactory` and creates a logger in the ctor of the class. There's also `ILoggerProvider` which looks like a read-only version of the Factory, but implementations may or may not implement both interfaces, so I'd have to pick. (Factory seems more common than Provider).

Some code I've seen uses the non-generic `ILogger` interface and might even share one instance of the same logger, and some take an `ILogger<T>` in their ctor and expect the DI container to support open generic types or explicit registration of each and every `ILogger<T>` variation my library uses.

Right now, I do think that `ILogger<T>` is the right approach, and maybe a ctor that doesn't take that argument and just passes a Null Logger instead. That way, if no logging is needed, none is used. However, some DI containers pick the largest ctor and thus would fail anyway.

I'm curious of what I'm _supposed_ to be doing here to create the least amount of headache for users, while still allowing proper logging support if desired.
Reply

#2
The default approach is meant to be `ILogger<T>`. This means that in the log the logs from the specific class will be clearly visible because they will include the full class name as the context. For example if the full name of your class is `MyLibrary.MyClass` you will get this in the log entries created by this class. For example:

> MyLibrary.MyClass:Information: My information log

You should use the `ILoggerFactory` if you want to specify your own context. For example that all the logs from your library have the same log context instead every class. For example:

loggerFactory.CreateLogger("MyLibrary");

And then the log will look like this:

> MyLibrary:Information: My information log


If you do that in all classes then the context will be just MyLibrary for all classes. I imagine you would want to do that for a library if you don't want to expose the inner class structure in the logs.

Regarding the optional logging. I think you should always require the ILogger or ILoggerFactory in the constructor and leave it to the consumer of the library to turn it off or provide a Logger that does nothing in the dependency injection if they don't want logging. It is very easy to turn of the logging for a specific context in the configuration. For example:

{
"Logging": {
"LogLevel": {
"Default": "Warning",
"MyLibrary": "None"
}
}
}


Reply

#3
Sticking to the question, I believe `ILogger<T>` is the right option, considering downside of other options:

1. Injecting `ILoggerFactory` force your user to give away the control of the mutable global logger factory to your class library. Moreover, by accepting `ILoggerFactory` your class now can write to log with any arbitrary category name with `CreateLogger` method. While `ILoggerFactory` is usually available as a singleton in DI container, I as a user would doubt why any library would need to use it.
2. While the method `ILoggerProvider.CreateLogger` looks like it, it is not intended for injection. It is used with `ILoggerFactory.AddProvider` so the factory can create aggregated `ILogger` that writes to multiple `ILogger` created from each registered providers. This is clear when you inspect [the implementation of `LoggerFactory.CreateLogger`][1]
3. Accepting `ILogger` also looks like the way to go, but it is impossible with .NET Core DI. This actually sounds like the reason why they needed to provide `ILogger<T>` at the first place.

So after all, we have no better choice than `ILogger<T>`, if we were to choose from those classes.

Another approach would be to inject something else that wraps non-generic `ILogger`, which in this case should be non-generic one. The idea is that by wrapping it with your own class, you take full control of how user could configure it.

[1]:

[To see links please register here]

Reply

#4
Those are all valid except for `ILoggerProvider`. `ILogger` and `ILogger<T>` are what you're supposed to use for logging. To get an `ILogger`, you use an `ILoggerFactory`. `ILogger<T>` is a shortcut to get a logger for a particular category (shortcut for the type as the category).

When you use the `ILogger` to perform logging, each registered `ILoggerProvider` gets a chance to handle that log message. It's not really valid for consuming code to call into the `ILoggerProvider` directly.
Reply

#5
I would prefer to keep it simple and inject the non generic ILogger

This seems to be non-default behavior - but is easily wired up with the following:

services.AddTransient(s => s.GetRequiredService<ILoggerFactory>().CreateLogger(""));

Reply

#6
The `ILogger<T>` was the actual one that is made for DI. The `ILogger<T>` came in order to help implement the factory pattern much more easily, instead of you writing on your own all the DI and Factory logic, that was one of the smartest decisions in ASP.NET Core

You can choose between:

`ILogger<T>` if you have a need to use factory and DI patterns in your code **or** you could use the `ILogger`, to implement simple logging with no DI needed.

Given that, the `ILoggerProvider` is just a bridge to handle each of the registered log's messages. There is no need to use it, as it does not effect anything that you should intervene in code. It listens to the registered `ILoggerProvider` and handles the messages. That's about it.

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through