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
The Options configuration mechanism relies on the fact that the underlying options object is created once and can be configured additively multiple times. This is why the Configure methods exist the way they do, and why you can implement multiple IConfigureOptions classes, as well as have the PostConfigure approach.
When an options model has a Func property for attaching event handlers, it goes against this principle as it is exceedingly hard to "add" extra handlers. Here is an example of an extension method we created to support this behavior:
(PS: this is on top of a fairly old version of the AspNetCore instrumentation package, so it might not match exactly with the newer interface)
publicstaticvoidAddStopActivityEnrichment(thisAspNetCoreInstrumentationOptionsoptions,Action<Activity,HttpResponse>enrichmentAction){_=options??thrownewArgumentNullException(nameof(options));_=enrichmentAction??thrownewArgumentNullException(nameof(enrichmentAction));varpreviousEnrichmentAction=options.Enrich;options.Enrich=(activity,eventName,context)=>{previousEnrichmentAction?.Invoke(activity,eventName,context);if(eventNameis"OnStopActivity"){// The 'OnStopActivity' event passes a 'HttpResponse' object so this is a safe cast.enrichmentAction(activity,(HttpResponse)context);}};}
This allows us to call AddStopActivityEnrichment multiple times and "accumulate" the various handlers.
The main reason we came up with this was because it is extremely common for us to have multiple enrichments being done from libraries etc, where each can implement their own logic and be used together.
Here is an example of how we've used this in an implementation of IConfigureOptions:
It allows us to extract enrichment logic into isolated implementations like this and reuse them across many projects.
I believe the way instrumentation packages expose enrichment today is bad because it doesn't cleanly allow one to "add" enrichment handlers. You either have to do something like we did here (a custom method that uses closures to capture and accumulate func calls), or a completely custom abstraction that can itself be composed and used inside of the Func only once.
I suggest the team reconsider this design for all instrumentation libraries and go with something more robust for this purpose, like IObservable. I mentioned using events in the title but those are mostly considered legacy at this point since the IObserable interface tends to be superior to it in every way.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
The
Options
configuration mechanism relies on the fact that the underlying options object is created once and can be configured additively multiple times. This is why theConfigure
methods exist the way they do, and why you can implement multipleIConfigureOptions
classes, as well as have the PostConfigure approach.When an options model has a
Func
property for attaching event handlers, it goes against this principle as it is exceedingly hard to "add" extra handlers. Here is an example of an extension method we created to support this behavior:(PS: this is on top of a fairly old version of the AspNetCore instrumentation package, so it might not match exactly with the newer interface)
This allows us to call
AddStopActivityEnrichment
multiple times and "accumulate" the various handlers.The main reason we came up with this was because it is extremely common for us to have multiple enrichments being done from libraries etc, where each can implement their own logic and be used together.
Here is an example of how we've used this in an implementation of
IConfigureOptions
:This is then added via an extension method on
TracerProviderBuilder
:It allows us to extract enrichment logic into isolated implementations like this and reuse them across many projects.
I believe the way instrumentation packages expose enrichment today is bad because it doesn't cleanly allow one to "add" enrichment handlers. You either have to do something like we did here (a custom method that uses closures to capture and accumulate func calls), or a completely custom abstraction that can itself be composed and used inside of the
Func
only once.I suggest the team reconsider this design for all instrumentation libraries and go with something more robust for this purpose, like
IObservable
. I mentioned using events in the title but those are mostly considered legacy at this point since theIObserable
interface tends to be superior to it in every way.Beta Was this translation helpful? Give feedback.
All reactions