Skip to content
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

This is a POC implementation of OTEP 74, global instance management #724

Closed
wants to merge 3 commits into from

Conversation

jkwatson
Copy link
Contributor

See open-telemetry/oteps#74

This PR only handles the replacement of Tracer instances, but it gives a good indication of what it would look like for Meters as well.

@codecov-io
Copy link

codecov-io commented Dec 30, 2019

Codecov Report

Merging #724 into master will decrease coverage by 0.01%.
The diff coverage is 88.5%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #724      +/-   ##
============================================
- Coverage     78.58%   78.57%   -0.02%     
- Complexity      778      796      +18     
============================================
  Files           101      102       +1     
  Lines          2779     2824      +45     
  Branches        268      269       +1     
============================================
+ Hits           2184     2219      +35     
- Misses          493      500       +7     
- Partials        102      105       +3
Impacted Files Coverage Δ Complexity Δ
.../io/opentelemetry/trace/DefaultTracerRegistry.java 100% <100%> (ø) 7 <4> (+2) ⬆️
...ava/io/opentelemetry/SpiOpenTelemetryProvider.java 100% <100%> (ø) 11 <11> (?)
.../src/main/java/io/opentelemetry/OpenTelemetry.java 76.47% <73.33%> (-20.97%) 13 <13> (-2)
...ain/java/io/opentelemetry/trace/DefaultTracer.java 93.22% <90%> (-2.24%) 15 <13> (+8)
...elemetry/opentracingshim/SpanContextShimTable.java 89.28% <0%> (-7.15%) 7% <0%> (-1%)
...elemetry/sdk/trace/export/BatchSpansProcessor.java 89.65% <0%> (+0.86%) 7% <0%> (ø) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update bd4f373...cf65412. Read the comment docs.

* @param tracerFactory A fully configured and ready to operate {@link TracerFactory}
* implementation.
*/
public static void setTracerFactory(TracerFactory tracerFactory) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want to offer a set we need to have thin wrappers that allow changing the implementation.

TraceFactoryWrapper extends TraceFactory {
private volatile TraceFactory implementation;

// redirects all calls to the implementation.
}

This solves the problem when users hold a static reference to the factory, but does not solve it when the user holds a reference to a Tracer.

I think in Java we already solved the otep 74 by providing dynamic loading for the TraceFactory implementation and we don't need a set method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe that to be the case. If instrumentation gets a handle to a Tracer before the SDK has been initialized, then it will never be replaced with an implementation that has a functional Tracer implementation behind it. This sample POC provides for the API Tracer to have it's implementation swapped out when the SDK is initialized.

for (Entry<TracerKey, DefaultTracer> entry : existingTracers.entrySet()) {
TracerKey key = entry.getKey();
entry.getValue().setImplementation(tracerFactory.get(key.getName(), key.getVersion()));
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bogdandrutu here is where the tracer implementation is swapped out after the SDK has been initialized.

@@ -73,7 +84,10 @@ public static TracerFactory getTracerFactory() {
* @since 0.1.0
*/
public static MeterFactory getMeterFactory() {
return getInstance().meterFactory;
if (instance.meterFactory.get() == null) {
setMeterFactory(SpiOpenTelemetryProvider.makeSpiMeterFactory());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was expecting to see some logic that uses a global "deferred" factory here. I see two cases:
(1) The user is planning to call setXXXerFactory() later; they want a handle they can store now which becomes functional later
(2) The user has planned for dependency injection, in which case we can bypass the user of a deferred factory here and use the injected value.
What I see here looks different. If the value is used it forces a decision about SPI to happen--what if there's no value injected and the user is still planning to call setXXXFactory? I don't see how that will work.
What I read in the code here is that if someone accesses the global

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR doesn't include having done anything with the Meter implementation, only Tracers.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now. Inside the call to makeSpiXXXFactory you get a default "deferred" impl if there's no SPI value.

@@ -73,7 +84,10 @@ public static TracerFactory getTracerFactory() {
* @since 0.1.0
*/
public static MeterFactory getMeterFactory() {
return getInstance().meterFactory;
if (instance.meterFactory.get() == null) {
setMeterFactory(SpiOpenTelemetryProvider.makeSpiMeterFactory());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see now. Inside the call to makeSpiXXXFactory you get a default "deferred" impl if there's no SPI value.

@bogdandrutu
Copy link
Member

Is this still needed? I think that offering the ServiceLoader option as the only option is good enough, here are the reasons why:

  1. If there is a need for a deferred initialization an implementation can implement exactly your logic and allow implementation to be swapped.
  2. If needed we can change the current TracerSdk to generate no-op Spans until exporter, config, idgenerator are installed (which becomes almost the same code as you have in this PR).

@jkwatson
Copy link
Contributor Author

I'm unclear on the state of the relevant OTEP. Our current implementation on master doesn't implement the OTEP fully. This is only here as an example of what it would take to implement the OTEP fully for the TracerSdk. If we want to close it, I'm fine with that, since it wasn't intended to be a final implementation, in any case. :)

@bogdandrutu
Copy link
Member

For the moment trying to understand if just SPI is enough. As I tried to explain in the first reason someone can implement a "Swappable" tracer implementation using SPI, by having the Swappable implementation loaded with SPI and installing the real implementation by calling into the Swappable implementation.

@bogdandrutu
Copy link
Member

Currently the OTEP says that if language supports SPI we should use that and don't do all the other work.

@jkwatson
Copy link
Contributor Author

Yep. I understand it. As I said, I'm fine with closing this. I'm not sure if we're going to work with Spring Framework, and archaic J2EE containers yet, but we can cross that bridge when @kbrockhoff gets to it. ;)

@jkwatson jkwatson closed this Feb 20, 2020
@bogdandrutu
Copy link
Member

What I want is a hidden thing :)). I want to make you work a bit to prove me wrong/right that someone can or cannot build an implementation of the API (using SPI) that supports delayed initialization for the Tracer class.

@jkwatson
Copy link
Contributor Author

Heh. I'm 100% sure it can be done. I mostly wanted to do this as an exercise to see what it might look like.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants