-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Additional Diagnostics in Dependency Injection #56809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2355cd0
0b7e834
939cb23
5d4e323
56836bc
224d420
df09798
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,9 +2,11 @@ | |||||||||||||||||||||||||||||||
| // The .NET Foundation licenses this file to you under the MIT license. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| using System; | ||||||||||||||||||||||||||||||||
| using System.Collections.Generic; | ||||||||||||||||||||||||||||||||
| using System.Diagnostics.CodeAnalysis; | ||||||||||||||||||||||||||||||||
| using System.Diagnostics.Tracing; | ||||||||||||||||||||||||||||||||
| using System.Linq.Expressions; | ||||||||||||||||||||||||||||||||
| using System.Text; | ||||||||||||||||||||||||||||||||
| using Microsoft.Extensions.DependencyInjection.ServiceLookup; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| namespace Microsoft.Extensions.DependencyInjection | ||||||||||||||||||||||||||||||||
|
|
@@ -14,9 +16,16 @@ internal sealed class DependencyInjectionEventSource : EventSource | |||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| public static readonly DependencyInjectionEventSource Log = new DependencyInjectionEventSource(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Event source doesn't support large payloads so we chunk formatted call site tree | ||||||||||||||||||||||||||||||||
| public static class Keywords | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| public const EventKeywords ServiceProviderInitialized = (EventKeywords)0x1; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| // Event source doesn't support large payloads so we chunk large payloads like formatted call site tree and descriptors | ||||||||||||||||||||||||||||||||
| private const int MaxChunkSize = 10 * 1024; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| private readonly List<WeakReference<ServiceProvider>> _providers = new(); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| private DependencyInjectionEventSource() : base(EventSourceSettings.EtwSelfDescribingEventFormat) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
@@ -32,27 +41,27 @@ private DependencyInjectionEventSource() : base(EventSourceSettings.EtwSelfDescr | |||||||||||||||||||||||||||||||
| [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", | ||||||||||||||||||||||||||||||||
| Justification = "Parameters to this method are primitive and are trimmer safe.")] | ||||||||||||||||||||||||||||||||
| [Event(1, Level = EventLevel.Verbose)] | ||||||||||||||||||||||||||||||||
| private void CallSiteBuilt(string serviceType, string callSite, int chunkIndex, int chunkCount) | ||||||||||||||||||||||||||||||||
| private void CallSiteBuilt(string serviceType, string callSite, int chunkIndex, int chunkCount, int serviceProviderHashCode) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(1, serviceType, callSite, chunkIndex, chunkCount); | ||||||||||||||||||||||||||||||||
| WriteEvent(1, serviceType, callSite, chunkIndex, chunkCount, serviceProviderHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [Event(2, Level = EventLevel.Verbose)] | ||||||||||||||||||||||||||||||||
| public void ServiceResolved(string serviceType) | ||||||||||||||||||||||||||||||||
| public void ServiceResolved(string serviceType, int serviceProviderHashCode) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(2, serviceType); | ||||||||||||||||||||||||||||||||
| WriteEvent(2, serviceType, serviceProviderHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [Event(3, Level = EventLevel.Verbose)] | ||||||||||||||||||||||||||||||||
| public void ExpressionTreeGenerated(string serviceType, int nodeCount) | ||||||||||||||||||||||||||||||||
| public void ExpressionTreeGenerated(string serviceType, int nodeCount, int serviceProviderHashCode) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(3, serviceType, nodeCount); | ||||||||||||||||||||||||||||||||
| WriteEvent(3, serviceType, nodeCount, serviceProviderHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [Event(4, Level = EventLevel.Verbose)] | ||||||||||||||||||||||||||||||||
| public void DynamicMethodBuilt(string serviceType, int methodSize) | ||||||||||||||||||||||||||||||||
| public void DynamicMethodBuilt(string serviceType, int methodSize, int serviceProviderHashCode) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(4, serviceType, methodSize); | ||||||||||||||||||||||||||||||||
| WriteEvent(4, serviceType, methodSize, serviceProviderHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [Event(5, Level = EventLevel.Verbose)] | ||||||||||||||||||||||||||||||||
|
|
@@ -62,52 +71,206 @@ public void ScopeDisposed(int serviceProviderHashCode, int scopedServicesResolve | |||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [Event(6, Level = EventLevel.Error)] | ||||||||||||||||||||||||||||||||
| public void ServiceRealizationFailed(string? exceptionMessage) | ||||||||||||||||||||||||||||||||
| public void ServiceRealizationFailed(string? exceptionMessage, int serviceProviderHashCode) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(6, exceptionMessage, serviceProviderHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", | ||||||||||||||||||||||||||||||||
| Justification = "Parameters to this method are primitive and are trimmer safe.")] | ||||||||||||||||||||||||||||||||
| [Event(7, Level = EventLevel.Informational, Keywords = Keywords.ServiceProviderInitialized)] | ||||||||||||||||||||||||||||||||
| private void ServiceProviderBuilt(int serviceProviderHashCode, int singletonServices, int scopedServices, int transientServices) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(6, exceptionMessage); | ||||||||||||||||||||||||||||||||
| WriteEvent(7, serviceProviderHashCode, singletonServices, scopedServices, transientServices); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", | ||||||||||||||||||||||||||||||||
| Justification = "Parameters to this method are primitive and are trimmer safe.")] | ||||||||||||||||||||||||||||||||
| [Event(8, Level = EventLevel.Informational, Keywords = Keywords.ServiceProviderInitialized)] | ||||||||||||||||||||||||||||||||
| private void ServiceProviderDescriptors(int serviceProviderHashCode, string descriptors, int chunkIndex, int chunkCount) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteEvent(8, serviceProviderHashCode, descriptors, chunkIndex, chunkCount); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| public void ServiceResolved(Type serviceType) | ||||||||||||||||||||||||||||||||
| public void ServiceResolved(ServiceProvider provider, Type serviceType) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (IsEnabled(EventLevel.Verbose, EventKeywords.All)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| ServiceResolved(serviceType.ToString()); | ||||||||||||||||||||||||||||||||
| ServiceResolved(serviceType.ToString(), provider.GetHashCode()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| public void CallSiteBuilt(Type serviceType, ServiceCallSite callSite) | ||||||||||||||||||||||||||||||||
| public void CallSiteBuilt(ServiceProvider provider, Type serviceType, ServiceCallSite callSite) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (IsEnabled(EventLevel.Verbose, EventKeywords.All)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| string format = CallSiteJsonFormatter.Instance.Format(callSite); | ||||||||||||||||||||||||||||||||
| int chunkCount = format.Length / MaxChunkSize + (format.Length % MaxChunkSize > 0 ? 1 : 0); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| int providerHashCode = provider.GetHashCode(); | ||||||||||||||||||||||||||||||||
| for (int i = 0; i < chunkCount; i++) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| CallSiteBuilt( | ||||||||||||||||||||||||||||||||
| serviceType.ToString(), | ||||||||||||||||||||||||||||||||
| format.Substring(i * MaxChunkSize, Math.Min(MaxChunkSize, format.Length - i * MaxChunkSize)), i, chunkCount); | ||||||||||||||||||||||||||||||||
| format.Substring(i * MaxChunkSize, Math.Min(MaxChunkSize, format.Length - i * MaxChunkSize)), i, chunkCount, | ||||||||||||||||||||||||||||||||
| providerHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| public void DynamicMethodBuilt(Type serviceType, int methodSize) | ||||||||||||||||||||||||||||||||
| public void DynamicMethodBuilt(ServiceProvider provider, Type serviceType, int methodSize) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (IsEnabled(EventLevel.Verbose, EventKeywords.All)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| DynamicMethodBuilt(serviceType.ToString(), methodSize); | ||||||||||||||||||||||||||||||||
| DynamicMethodBuilt(serviceType.ToString(), methodSize, provider.GetHashCode()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| public void ServiceRealizationFailed(Exception exception) | ||||||||||||||||||||||||||||||||
| public void ServiceRealizationFailed(Exception exception, int serviceProviderHashCode) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (IsEnabled(EventLevel.Error, EventKeywords.All)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| ServiceRealizationFailed(exception.ToString()); | ||||||||||||||||||||||||||||||||
| ServiceRealizationFailed(exception.ToString(), serviceProviderHashCode); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| public void ServiceProviderBuilt(ServiceProvider provider) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| lock (_providers) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| _providers.Add(new WeakReference<ServiceProvider>(provider)); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| WriteServiceProviderBuilt(provider); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| public void ServiceProviderDisposed(ServiceProvider provider) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| lock (_providers) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| for (int i = _providers.Count - 1; i >= 0; i--) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| // remove the provider, along with any stale references | ||||||||||||||||||||||||||||||||
| WeakReference<ServiceProvider> reference = _providers[i]; | ||||||||||||||||||||||||||||||||
| if (!reference.TryGetTarget(out ServiceProvider target) || target == provider) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| _providers.RemoveAt(i); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| private void WriteServiceProviderBuilt(ServiceProvider provider) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (IsEnabled(EventLevel.Informational, Keywords.ServiceProviderInitialized)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| int singletonServices = 0; | ||||||||||||||||||||||||||||||||
| int scopedServices = 0; | ||||||||||||||||||||||||||||||||
| int transientServices = 0; | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| StringBuilder descriptorBuilder = new StringBuilder("{ \"descriptors\":[ "); | ||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally speaking, the pattern is to do less string formatting and to do more writing of events with payloads that can then be processed out-of-proc. This looks like it might be a place where building up the state in-proc is preferred, or that you have to string-ify things anyway, but just wanted to call that out. Definitely good that this is under its own keyword.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, here we want to dump a bunch of data - the list of registered DI services. We are doing something similar above already: runtime/src/libraries/Microsoft.Extensions.DependencyInjection/src/DependencyInjectionEventSource.cs Lines 80 to 94 in a1aeb13
|
||||||||||||||||||||||||||||||||
| bool firstDescriptor = true; | ||||||||||||||||||||||||||||||||
| foreach (ServiceDescriptor descriptor in provider.CallSiteFactory.Descriptors) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (firstDescriptor) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| firstDescriptor = false; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| descriptorBuilder.Append(", "); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| AppendServiceDescriptor(descriptorBuilder, descriptor); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| switch (descriptor.Lifetime) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| case ServiceLifetime.Singleton: | ||||||||||||||||||||||||||||||||
| singletonServices++; | ||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||
| case ServiceLifetime.Scoped: | ||||||||||||||||||||||||||||||||
| scopedServices++; | ||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||
| case ServiceLifetime.Transient: | ||||||||||||||||||||||||||||||||
| transientServices++; | ||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| descriptorBuilder.Append(" ] }"); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| int providerHashCode = provider.GetHashCode(); | ||||||||||||||||||||||||||||||||
| ServiceProviderBuilt(providerHashCode, singletonServices, scopedServices, transientServices); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| string descriptorString = descriptorBuilder.ToString(); | ||||||||||||||||||||||||||||||||
| int chunkCount = descriptorString.Length / MaxChunkSize + (descriptorString.Length % MaxChunkSize > 0 ? 1 : 0); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| for (int i = 0; i < chunkCount; i++) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| ServiceProviderDescriptors( | ||||||||||||||||||||||||||||||||
| providerHashCode, | ||||||||||||||||||||||||||||||||
| descriptorString.Substring(i * MaxChunkSize, Math.Min(MaxChunkSize, descriptorString.Length - i * MaxChunkSize)), i, chunkCount); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| [NonEvent] | ||||||||||||||||||||||||||||||||
| private static void AppendServiceDescriptor(StringBuilder builder, ServiceDescriptor descriptor) | ||||||||||||||||||||||||||||||||
eerhardt marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| builder.Append("{ \"serviceType\": \""); | ||||||||||||||||||||||||||||||||
| builder.Append(descriptor.ServiceType); | ||||||||||||||||||||||||||||||||
| builder.Append("\", \"lifetime\": \""); | ||||||||||||||||||||||||||||||||
| builder.Append(descriptor.Lifetime); | ||||||||||||||||||||||||||||||||
| builder.Append("\", "); | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| if (descriptor.ImplementationType is not null) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| builder.Append("\"implementationType\": \""); | ||||||||||||||||||||||||||||||||
| builder.Append(descriptor.ImplementationType); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| else if (descriptor.ImplementationFactory is not null) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| builder.Append("\"implementationFactory\": \""); | ||||||||||||||||||||||||||||||||
| builder.Append(descriptor.ImplementationFactory.Method); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| else if (descriptor.ImplementationInstance is not null) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| builder.Append("\"implementationInstance\": \""); | ||||||||||||||||||||||||||||||||
| builder.Append(descriptor.ImplementationInstance.GetType()); | ||||||||||||||||||||||||||||||||
| builder.Append(" (instance)"); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| builder.Append("\"unknown\": \""); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| builder.Append("\" }"); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| protected override void OnEventCommand(EventCommandEventArgs command) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (command.Command == EventCommand.Enable) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| // When this EventSource becomes enabled, write out the existing ServiceProvider information | ||||||||||||||||||||||||||||||||
| // because building the ServiceProvider happens early in the process. This way a listener | ||||||||||||||||||||||||||||||||
| // can get this information, even if they attach while the process is running. | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
| lock (_providers) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| foreach (WeakReference<ServiceProvider> reference in _providers) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (reference.TryGetTarget(out ServiceProvider provider)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| WriteServiceProviderBuilt(provider); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
@@ -117,13 +280,13 @@ internal static class DependencyInjectionEventSourceExtensions | |||||||||||||||||||||||||||||||
| // This is an extension method because this assembly is trimmed at a "type granular" level in Blazor, | ||||||||||||||||||||||||||||||||
| // and the whole DependencyInjectionEventSource type can't be trimmed. So extracting this to a separate | ||||||||||||||||||||||||||||||||
| // type allows for the System.Linq.Expressions usage to be trimmed by the ILLinker. | ||||||||||||||||||||||||||||||||
| public static void ExpressionTreeGenerated(this DependencyInjectionEventSource source, Type serviceType, Expression expression) | ||||||||||||||||||||||||||||||||
| public static void ExpressionTreeGenerated(this DependencyInjectionEventSource source, ServiceProvider provider, Type serviceType, Expression expression) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| if (source.IsEnabled(EventLevel.Verbose, EventKeywords.All)) | ||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||
| var visitor = new NodeCountingVisitor(); | ||||||||||||||||||||||||||||||||
| visitor.Visit(expression); | ||||||||||||||||||||||||||||||||
| source.ExpressionTreeGenerated(serviceType.ToString(), visitor.NodeCount); | ||||||||||||||||||||||||||||||||
| source.ExpressionTreeGenerated(serviceType.ToString(), visitor.NodeCount, provider.GetHashCode()); | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you might need to specify a keyword for the other events in this provider now. If you turn on keyword 0x1, you'll just get the ServiceProviderInitialized events. If you specify keyword 0, I'm not sure you'll get the others - worth checking via ETW.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my intention. The existing events all check for
EventKeywords.All:runtime/src/libraries/Microsoft.Extensions.DependencyInjection/src/DependencyInjectionEventSource.cs
Lines 80 to 82 in a1aeb13
So if you don't specify
All, you won't get those events.When I do
I don't get any events logged.
When I do
I get them all.
And when I do
I just get the 2 new ones.