-
Notifications
You must be signed in to change notification settings - Fork 10k
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
Consider changing diagnostic events to use public declared types as their payload #48616
Comments
The "long list of hints to the trimmer" isn't for in-process listeners, but instead of out-of-proc listeners like See also - dotnet/runtime#87064. |
@mitchdenny This sounds like a mechanical change for a meaningful quality-of-life improvement, but I'm not sure where it falls on our AOT priority list. Can you please take a look? |
@JamesNK had you had any thoughts about this for the gRPC side of things? I think that we are going to end up with a bunch of public loose types hanging around that we might want to put into a consistent namespace (or namespaces). For example: So there would be a Thoughts? |
The events produced by ASP.NET to the diagnostic listener pass a payload object which is consumed by several different tools/libraries. For some of the events the payload object uses a public defined type and thus the consumer can directly cast it and access all the relevant data. But for some events the event uses either declared but internal type or just anonymous type, in these cases the consumer has to use reflection to access the relevant data.
This has distinct disadvantages in performance impact and trim/AOT compatibility. Currently for example Open Telemetry library uses several different tools to overcome these:
DynamicDependencyAttribute
andDynamicallyAccessedMembersAttribute
attributes to hint trimmer/AOT compiler to keep properties on the payload objectThere are still unsolved problems though. The trimmer compatibility is not verifiable by any tools, since it relies on the combination of attributes in the ASP.NET code and careful reflection usage in the consuming library. The consuming library has to use suppressions which is always fragile.
Another observation is that the shape of the payload object is effectively a public contract, since the consuming libraries hardcodes the name of the properties and then cast the value of those properties to public types (like Exception). If the framework changed the name of the property, it would be an effective breaking change, even though technically it's not changing any public property.
Some events were already changed like this, for example #11730.
What remains based on OpenTelemetry usage:
Microsoft.ASpNetCore.Hosting.UnhandledException
uses a private typeUnhandledExceptionData
.Microsoft.AspNetCore.Diagnostics.UnhandledException
uses anonymous type.Currently we mitigate these problems by maintaining annotations on the type used as well as the logging method. These preserve the properties we know of are accessed dynamically (through reflection) by some of the consumers. This list is inherently incomplete and fragile. It also means that the consumer will get trim/AOT warnings due to reflection usage and it has to suppress these relying on annotations in the framework. This relationship is unverifiable by any tooling and thus fragile.
Note that there are other events which seem to have the same problem, they're just not used by OpenTelemetry which is the consumer I've been looking at:
Microsoft.AspNetCore.Hosting.BeginRequest
- uses private typeMicrosoft.AspNetCore.Hosting.EndRequest
- uses private typeMicrosoft.AspNetCore.Hosting.HttpRequestIn.Start
- uses public type (HttpContext
), but still maintain a long list of hints to the trimmer - maybe this would be worth revisiting in the consumers (for example OpenTelemetry doesn't use reflection in this case at all).Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop
- uses public type (HttpContext
), but still maintain a long list of hints to the trimmer - maybe this would be worth revisiting in the consumers (for example OpenTelemetry doesn't use reflection in this case at all).Microsoft.AspNetCore.Diagnostics.HandledException
- uses anonymous typeMicrosoft.AspNetCore.NodeServices.Npm.NpmStarted
- uses anonymous typeMicrosoft.AspNetCore.Server.Kestrel.BadRequest
- uses internal typeHttpProtocol
Additionally, in some cases the naming of the properties is inconsistent. For example the public types use typical Pascal casing of property names, e.g.
Request
orException
. But most of the anonymous types use lower case names, likeexception
. This requires the consumers to perform case insensitive search for the property making it less performant (they typically loop over all properties to achieve this).Related to #45910 and open-telemetry/opentelemetry-dotnet#3429.
/cc @Yun-Ting, @eerhardt, @LakshanF
The text was updated successfully, but these errors were encountered: