Reputation: 82437
I have one part of my application where I only want to log to the EventLog. The rest of the time, I want to to log to all the normal event sinks that are setup for my ILogger
s.
I can make an ILogger in those parts by doing this:
var eventLogLoggerProvider = new Microsoft.Extensions.Logging.EventLog.EventLogLoggerProvider();
var eventLogger = eventLogLoggerProvider.CreateLogger("EventLogger");
eventLogger.LogWarning("We logged to the event log!");
But I feel like I should do it via dependency injection. But all the examples just show setting up one time for the whole application.
Is there a way to configure an ASP.Net Core 3.1 application to have two different kinds of ILoggers? (And allow injecting one or the other into a class?)
Upvotes: 2
Views: 2155
Reputation: 2923
There are several options at your disposal. However, none of them are going to be especially nice. The .NET Extensions DI is somewhat simplistic whilst your scenario seems rather advanced.
If you are so bound on using EventLog in a particular place of the application, maybe it would make sense to use it directly as the ILogger abstraction is basically in opposition to what you require.
With ILogger
dependency, you are saying "Give me a logger, whatever that is, I don't care". But you do care. So why not use EventLog directly? Or perhaps hide it behind an interface and adapter for testability and inject it.
Alternatively, you will encounter somewhat less friction if you configure the logging through appsettings.json so that EventLog has default LogLevel = None and LogLevel = Information or whatever you like in your event-logged assembly/namespace. And that the rest of the loggers have None LogLevel for the event-logged area. For example:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"My.EventLogged.Assembly": "None"
},
"EventLog": {
"Default": "None",
"My.EventLogged.Assembly": "Information"
}
}
}
This would work nicely if you have your code isolated into an assembly or a few namespaces but it's easy to add another place where you only want event log and forget to configure it as such.
For more information, see Logging in .NET Core and ASP.NET Core, Configuration section.
If the area where you only require event logging is easily separated, you can provide a facade with a singleton lifetime that will create a separate IServiceCollection/IServicePrivoder with event log being the only registered ILogger in that container.
Any call to your event-logged code should go through the facade which would invoke the expected implemenatation using the internal IServiceProvider. If you need to call from your event-logged code to the rest of your application, you will need to do the reverse.
This is not straightforward, but even ASP.NET Core itself does (or at least did) this in order to provide logging during startup, when services initialization is not complete yet.
But it definitely has element of surprise and could lead to some headaches with debugging and diagnosing service setup. There will also be duplicities within the setup. I do believe this is not a worthwhile approach.
Other containers such as autofac or castle might be able to resolve multiple services (in this case ILogger) based on instance identification using names. See e.g. AutoFac FAQ: How do I pick service implementation by context.
However, I cannot advise on how to do this with something as ILogger as the logging registration is rather complicated.
Those are just some directions you could take I could think of off top of my head. I don't believe there is a simple, cannonical answer to what you're requesting and you will have to research the options further based on your specific needs and situation.
Upvotes: 5