-
Notifications
You must be signed in to change notification settings - Fork 763
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
[Tracing] Improve dependency injection support in tracing build-up using SDK #3533
[Tracing] Improve dependency injection support in tracing build-up using SDK #3533
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #3533 +/- ##
==========================================
+ Coverage 87.02% 87.34% +0.31%
==========================================
Files 277 280 +3
Lines 9953 10056 +103
==========================================
+ Hits 8662 8783 +121
+ Misses 1291 1273 -18
|
… that there is no breakage during upgrades.
[Obsolete("Call ConfigureServices instead this method will be removed in a future version.")] | ||
public static IServiceCollection? GetServices(this TracerProviderBuilder tracerProviderBuilder) |
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'm beginning to question if we should be less conservative here. That is, just dump GetServices
. Likewise dump Configure
.
Yes, it'll break folks who are currently using OpenTelemetry.Extensions.Hosting
, but my sense of these methods are that they're less frequently used.
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.
@alanwest I pushed an update which removed them from SDK but I left them in Hosting and added [Obsolete]
there. I don't feel passionately that we shouldn't remove them outright, but I feel like the Hosting API has existed for so long it would be nice for us to not break anyone. LMK what you think about that.
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 this is definitely the right direction. It'll be good to land this sooner than later to unblock bringing these patterns to metrics and logs. I think there'll be ample opportunity to continue to iron things out as needed.
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.
LGTM.
We need to document/add some examples demonstrating the new capabilities ( i.e everything from PR desc. into docs/examples) later, so people can easily leverage these.
Totally! Once I am done getting traces/metrics/logs all squared away I'll take a stab at spinning up some documentation. |
Fixes #1215 - Multiple registrations now all configure the same builder/provider
Relates to #3086 - Adds a mechanism to do this (see scenarios)
Relates to #1642 - Moves all of the dependency bits into SDK, only thing in "hosting" is the
IHostedService
. May or may not help with the name 😄Relates to #2980 - Makes it possible to solve this
Relates to #2971 - Makes it possible to solve this
Changes
Moves dependency injection features based on
ServiceCollection
from hosting library directly into SDK so they are universally available. This is similar to what was done on [Logs] Support dependency injection in logging build-up #3504 for logs.Enabled a few more detached scenarios.
We decided on the SIG meeting 8/2/2022 that only a single provider should be supported in a given
ServicesCollection
this PR makes that a reality.SDK public API
OpenTelemetry.Extensions.Hosting public API
Existing scenarios made available in SDK
All of this stuff you could already do using the hosting library. But now you can do it just with the SDK. That makes it more universal. Notice below the root is
Sdk.CreateTracerProviderBuilder
previously that builder had zero support for any kind dependency injection. Now it has the same surface as the builder returned by theAddOpenTelemetryTracing
API. All of this will work for .NET Framework as well as .NET/Core.The hidden value being created here is really for library/extension authors. Now I can build a library with this extension...
...and it will work equally well for .NET Framework users as it will .NET/Core users, with only a reference to SDK.
It also allows us to clean up some of the strange registration code we have. For example this...
...becomes this...
New scenarios enabled
Register an exporter with the builder
This can be done either by providing the exporter instance or using dependency injection.
The
BatchExportActivityProcessorOptions
used (when batching is configured) is retrieved through the options API. Users will be able to bindBatchExportActivityProcessorOptions
toIConfiguration
and manage it through the configuration pipeline (JSON, envvars, command-line, whatever they happen to have configured). There is a bit more work to smooth out how environment variables are retrieved (which is what #2980 is about) but I'll tackle that separately.Detached configuration method
Some users like @martinjt have asked for a way to configure things completely detached from the builder.
The SDK
ConfigureOpenTelemetryTracing
extension is safe to be called multiple times. Only oneTracerProvider
will exist in theIServiceProvider
and multiple calls will all contribute to its configuration, in order. This makes it possible to detach from theTracerProviderBuilder
. This enables a scenario like this...Design details
TracerProviderBuilderBase
has 3 ctors which drive its 2 phases.Phase one: Service configuration
The first phase is used to register services before the
IServiceProvider
is ready. Everything done on the builder in this phase is queued up into theIServiceCollection
. Previously the builder had some state and certain calls likeAddProcessor
would modify that state. Other things likeConfigure/Builder
would be queued up for later. Moving everything to the queue is how we are now able to callAddOpenTelemetryTracing
multiple times. Previously that would result in state needing to be managed for each builder, now everything just dumps intoIServiceCollection
. Also now everything will happen in the order of the builder invocation. Previously some stuff would happen instantly via the state, some things would happen later on. The order now should be predictable.The two ctors:
Phase two: Build-up
At some point the
IServiceProvider
is ready and services are closed. In the case ofSdk.CreateTracerProviderBuilder()
this happens whenBuild()
is called. In the case ofAddOpenTelemetryTracing
the host controls that and we don't build until something asks for aTracerProvider
from theIServiceProvider
. In either case phase two is executed here:opentelemetry-dotnet/src/OpenTelemetry/Trace/TracerProviderSdk.cs
Lines 52 to 56 in 9e02797
We create a state object (
TracerProviderBuilderState
) and then execute all the queued configuration actions against that state.We use this ctor:
Which tells the builder to modify the state instead of queuing things up.
The
TracerProvider
is created using the state after all the configuration is applied.I'm sure this all feels very non-standard but actually it is very close to the built-in patterns. For example,
AddLogging
immediately invokes the configuration callback on aLoggingBuilder
which only modifies theIServiceCollection
. Nothing actually happens until theLoggerFactory
is created at which point everything is retrieved from theIServiceProvider
.Our case is more complicated because we weren't disciplined about using interfaces registered for all the
TracerProvider
"services"/features, and we have a callback for configuring the builder onceIServiceProvider
is available, but the underlying mechanisms are essentially the same.TODOs
CHANGELOG.md
updated for non-trivial changes