Comments (8)
In the current system I'm not sure how to do that since it's two completely separate operations. You'd effectively have to keep every graph open forever "just in case" there's a child resolve that happens as part of one of these things.
It very much reminds me of distributed tracing in microservices and I wonder if there's something to adopt there. It also reminds me of a previous tracer that was getting developed for a while that was more like... an event handler would listen for events inside Autofac and write them to a named pipe. A listening UI/tracer would listen on that named pipe for messages and write them out. (That's something we could easily do now.)
You'd need the listener to the events to keep a database of all the operations going on, lifetime scope IDs, etc. As new resolve requests and operations occur, they get added to the database. When you view the trace, it's "whatever information we have at the time" - maybe the Func<T>
resolve hasn't happened yet. In a minute or so, maybe it has. Viewing the graph at that point in time will be different.
I think that's the only way to solve it. It'd be a tremendous memory leak to try to do that inside the tracer in Autofac.
I think it may require a change in core Autofac, which might mean you want to move this to that repo instead of the graph repo, which is: All lifetime scope IDs (and component IDs, etc.) would need to be reasonably serializable. You'd want to be able to feed that information to the database and have it stored somehow, and compared later. I think right now lifetime scopes are all identified by their tags, which is just an object
for an anonymous lifetime scope. You can't really serialize object equality.
from autofac.diagnostics.dotgraph.
Possibly, but I don't think it needs to be quite that complicated...I was just thinking of using AsyncLocal
to store the current graph/diagnostics info instead of a concurrent dictionary, so anything fancy like Owned knows about the parent operation when it starts feeding diagnostic data back.
In addition any resolves of ILifetimeScope
that we can't tie back to something concrete could add an explicit node that says "there's a dynamic dependency going on here, watch for that"?
from autofac.diagnostics.dotgraph.
I dunno, I feel like it might be more complicated than that, but maybe I'm overcomplicating it. Like, Func<Owned<T>>
is going to be weird. It resolves a thing, but that thing has its own child lifetime scope. And in Func<T>
they aren't necessarily guaranteed to actually execute it, so maybe there is something and maybe there's not.
I think AsyncLocal
is going to get really messy when you combine injecting things through construction, Func<T>
sorts of things, and manual service resolution based on HttpContext.RequestServices
and such. A that point it's not really about graphing the resolve operation anymore - it's about graphing lifetime scope traces and I think... I think that's maybe outside the scope here. I mean, I get that it might be interesting, but I also think it's a different thing to be tracing.
That could potentially be assembled from distributed traces, since you'd have lifetime scope IDs, parent/child relationships, service/component relationships, all that. But, like, this:
public class Consumer
{
private T _item;
public Consumer(Func<T> factory)
{
_item = factory();
}
}
is no different than this:
public class Consumer
{
private T _item;
public Consumer(ILifetimeScope scope)
{
_item = scope.Resolve<T>();
}
}
or, in ASP.NET Core controllers, this:
public class Consumer
{
private T _item;
public Consumer()
{
_item = this.HttpContext.RequestServices.GetService<T>();
}
}
In an ASP.NET Core context, yeah, there's sort of a logical correlation between lifetime scope and request. (Except when folks create unit of work scopes inside controller actions, which seems to be a common practice. I've seen a lot of StackOverflow questions come through about that.)
In other app types, there's not really as clear-cut a notion of one-lifetime-scope-per-logical-request sort of semantics. And if you add in multitenant scopes, that also gets interesting.
Point being... I think while some sort of AsyncLocal
request stack might work in ASP.NET Core, I think what is actually stored and managed there is going to be complex; and I don't think that would work the way we expect in a console app or a Windows service or whatever.
However... you could totally address all of those situations if you were able to stream out IDs and activities and all that. The viewer/reporter could handle visualizing or filtering or whatever. You could even enable something such that the tracer could get data from the execution environment (maybe accessing HttpContext
via IHttpContextAccessor
to add metadata to a given graph and allow tying the resolution chain to a specific request. "Find me all the resolutions that happened during request ABCD1234" - and that would even tie to any other distributed trace data you might have.
That's really, really ASP.NET Core specific, of course.
In a Windows service TopShelf project, maybe you stream out stuff and want to see what happened in a certain time window rather than a certain resolve hierarchy because in your service everything resolves from the same lifetime scope. As a single graph, that'd suck. You'd want different ways to view the data based on different app types.
from autofac.diagnostics.dotgraph.
On reflection there's probably a significant amount of work here to make the diagnostics capture 'perfect', which we don't really need to do now, on this first cut of diagnostic support.
Perhaps for now we leave the behaviour mostly as it is, but with two (hopefully straightforward) proposed changes:
-
If the graph sees a resolve of
ILifetimeScope
orIComponentContext
, we show a slightly different box, with words
to the effect of "Possible Deferred Resolve Operation" or something, just to indicate to someone that they may need to
go look at other traces. -
The builder puts a counter somewhere on the generated diagram which is a global 'trace number'. This trace number is
determined at the start of an operation, rather than the end, so if you see an indicator that you need to go look elsewhere,
you may at least be able to correlate the two together by knowing which operation was logically 'next'.In a multi-threaded app, that trace number might not always literally be the next value, but at least it will imply some sense of
order.
from autofac.diagnostics.dotgraph.
I like the ILifetimeScope
different box type thing, I think that's doable.
On the trace number - I'll see your trace number and raise you "put DateTime.UtcNow down to the ms or us" so the ordering is based on time rather than sequence number. (Or, alternatively, use DateTime.UtcNow.Ticks as the number.) Sequence can be determined by the absolute time when the op starts.
from autofac.diagnostics.dotgraph.
I can add that in after the first PR/commit has been brought in, I think?
from autofac.diagnostics.dotgraph.
Yeah, I've merged that in now, so we can make these changes separately.
Time may be fine, yeah, but the granularity is going to be interesting, because there could be an extremely small time period between an operation and a nested operation.
from autofac.diagnostics.dotgraph.
Just adding this to the v6 release so we can track it.
from autofac.diagnostics.dotgraph.
Related Issues (5)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from autofac.diagnostics.dotgraph.