You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Dec 13, 2018. It is now read-only.
I've been working on a web app feature that does a bunch of task scheduling for operations that run on background threads. In order to do this, I've got some sort of Singleton object that contains an operation queue, and when one is done, we pop off the queue and perform the next Operation. Since an operation is async, I needed a way of having this running on a background thread, which means having a separate scope from the current HTTP request, which will end.
As such, I've been using IServiceScopeFactory in order to kick off a new application lifetime scope, as something like this:
Inside of the operations, I have logic that allows them to take the current IServiceScope, and grab whatever services they need from the current scope, specifically now that it's detached from any scope generated by an HTTP request. This works fine for pretty much everything except logging.
The dream we had was that any scoped sub-service requested down within this background task could also request a logger, and we'd be able to capture all logging events that happened only within that specific scope.
It's easy to write a custom ILogger and ILoggerProvider, but there's no current way that I can see for us to have an instance of an ILogger that knows to write to a specific operation running only within a specific IServiceScope. I've tried approaches where my ILogger is given an instance of a ServiceProvider, but that's still the top-level Service provider, and there's no way to get one for my current scope.
Since the implementation of ILoggerFactory is a singleton, and Logger just stores a mapping of string to ILogger, it seems like there is currently no clean way for someone to create an ILogger that has access to the current scope, short of doing something extremely convoluted.
I'm still using 1.1, and I know there's been some changes in the 2.0 Preview (#626) that have added some more DI capabilities, but just my initial look at the code doesn't seem to indicate that there's any way to create a logger that can react to the current scope it's being called on. Am I missing something, or is this a feature that would be useful to be implemented?
Note: I know that I can easily register a different Logging service that has nothing to do with the logger, and have it be scoped, taking in a reference to ILoggerFactory, but then I would be missing out on any other logs in services down the line that were using the existing Logging system, which is exactly what I need to capture. I need all logs that were executed within my custom scope. Additionally, since there's no HTTP request here, I can't grab the scope from an IHttpContextAccessor in a Logger. The only option was to have some form of Scoped logger, but I don't see a way for that to work with the current system.
Example
Here's a rather silly example that you wouldn't want to do, but for the sake of the example...
// This comes from DI normally but for the sake of example, let's forgive the newIScopeServiceFactoryserviceFactory=newConcreteScopeServiceFactory();using(varscope=serviceFactory.CreateScope()){scope.ServiceProvider.GetService<MyCurrentScopeObject>().CurrentScope="SomeId";scope.ServiceProvider.GetService<MyCustomService>().DoSomething();}
publicclassMyCustomService{publicMyCustomService(RandomOtherServiceros,ILoggerFactoryloggerFactory){_logger=loggerFactory.Create<MyCustomService>();//... save these to service.}publicvoidDoSomething(){_logger.Log(/* Log something */);}}
publicclassMyCustomLogger:ILogger{publicMyCustomLogger(...){}// This comes not from DI, but from a LoggerProviderpublicvoidLog<TState>(LogLevellogLevel,EventIdeventId,TStatestate,Exceptionexception,Func<TState,Exception,string>formatter){// if I had access to MyCurrentScopeObject I would do something with it. _myCurrentScopeObject.LogList.Add( ...);}}
Since the MyCustomLogger in the code above has to be created with new from an ILoggerProvider there's no way for a scoped DI object of a MyCurrentScopeObject to be passed in!
The text was updated successfully, but these errors were encountered:
You'll need to create an async local that stores your current scope and access that from the ILogger implementation. It would be the moral equivalent of the IHttpContextAccessor but for your custom scope.
Thanks @davidfowl - I suppose I've now got an implementation working with an AsyncLocal created right when my scope kicks off. I was hoping to avoid something like that, but, whatever - it solves the problem and does what it needs to. I suppose this can be closed, unless you all think there's value in actually thinking about a Scoped ILogger instance, which would fit in with a lot of the other moves toward being more DI-friendly that the logging code has been making.
The logger instance can't be scoped. There is no concept of a "current" scope in DI so it wouldn't really work. LoggerProviders and loggers are singletons
I've been working on a web app feature that does a bunch of task scheduling for operations that run on background threads. In order to do this, I've got some sort of Singleton object that contains an operation queue, and when one is done, we pop off the queue and perform the next
Operation
. Since an operation is async, I needed a way of having this running on a background thread, which means having a separate scope from the current HTTP request, which will end.As such, I've been using
IServiceScopeFactory
in order to kick off a new application lifetime scope, as something like this:Inside of the operations, I have logic that allows them to take the current
IServiceScope
, and grab whatever services they need from the current scope, specifically now that it's detached from any scope generated by an HTTP request. This works fine for pretty much everything except logging.The dream we had was that any scoped sub-service requested down within this background task could also request a logger, and we'd be able to capture all logging events that happened only within that specific scope.
It's easy to write a custom
ILogger
andILoggerProvider
, but there's no current way that I can see for us to have an instance of anILogger
that knows to write to a specific operation running only within a specific IServiceScope. I've tried approaches where myILogger
is given an instance of a ServiceProvider, but that's still the top-level Service provider, and there's no way to get one for my current scope.Since the implementation of
ILoggerFactory
is a singleton, andLogger
just stores a mapping ofstring
toILogger
, it seems like there is currently no clean way for someone to create anILogger
that has access to the current scope, short of doing something extremely convoluted.I'm still using 1.1, and I know there's been some changes in the 2.0 Preview (#626) that have added some more DI capabilities, but just my initial look at the code doesn't seem to indicate that there's any way to create a logger that can react to the current scope it's being called on. Am I missing something, or is this a feature that would be useful to be implemented?
Note: I know that I can easily register a different Logging service that has nothing to do with the logger, and have it be scoped, taking in a reference to
ILoggerFactory
, but then I would be missing out on any other logs in services down the line that were using the existing Logging system, which is exactly what I need to capture. I need all logs that were executed within my custom scope. Additionally, since there's no HTTP request here, I can't grab the scope from anIHttpContextAccessor
in a Logger. The only option was to have some form of Scoped logger, but I don't see a way for that to work with the current system.Example
Here's a rather silly example that you wouldn't want to do, but for the sake of the example...
Since the
MyCustomLogger
in the code above has to be created withnew
from anILoggerProvider
there's no way for a scoped DI object of aMyCurrentScopeObject
to be passed in!The text was updated successfully, but these errors were encountered: