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

Split SpanContext into interface / impl #1935

Merged
merged 5 commits into from
Dec 1, 2020

Conversation

anuraaga
Copy link
Contributor

@codecov
Copy link

codecov bot commented Oct 30, 2020

Codecov Report

Merging #1935 (09df67d) into master (49b3e68) will decrease coverage by 0.04%.
The diff coverage is 77.77%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master    #1935      +/-   ##
============================================
- Coverage     85.04%   85.00%   -0.05%     
  Complexity     2170     2170              
============================================
  Files           246      247       +1     
  Lines          8318     8320       +2     
  Branches        924      924              
============================================
- Hits           7074     7072       -2     
- Misses          907      910       +3     
- Partials        337      338       +1     
Impacted Files Coverage Δ Complexity Δ
...n/java/io/opentelemetry/api/trace/SpanContext.java 77.77% <66.66%> (-11.70%) 9.00 <6.00> (-5.00)
.../opentelemetry/api/trace/ImmutableSpanContext.java 83.33% <83.33%> (ø) 5.00 <5.00> (?)
...try/sdk/metrics/aggregator/LongMinMaxSumCount.java 95.91% <0.00%> (-4.09%) 6.00% <0.00%> (ø%)

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 49b3e68...09df67d. Read the comment docs.

@Oberon00
Copy link
Member

This seems to make the code more complicated and arguably does not implement the "SHOULD" in "The API MUST implement methods to create a SpanContext. These methods SHOULD be the only way to create a SpanContext." since you can now create a SpanContext by deriving from the interface and instantiate the derived class.
So can you please state the reasons for these changes here?


@Immutable
@AutoValue
abstract class ImmutableSpanContext implements SpanContext {
Copy link
Member

Choose a reason for hiding this comment

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

Since the interface is also annotated @Immutable and according to the spec any SpanContext must be Immutable, this is maybe not the best name to distinguish it from possible other implementations which would also be Immutable. Maybe DefaultSpanContext?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I had the same impression - we have Immutable* as a pattern in many AutoValue implementations of interfaces currently. Renaming them all to Default seems fine to me, or even *Impl so the implementation orders next to the interface in the filetree.

Copy link
Contributor

Choose a reason for hiding this comment

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

No strong opinion. I'd keep this name for this PR, and we can always rename later, since this is an internal detail.

@anuraaga
Copy link
Contributor Author

@Oberon00 Weren't all the reasons in the long discussion in open-telemetry/opentelemetry-specification#969 and open-telemetry/opentelemetry-specification#970 ? :-) The short answer is for agent users, it will always be the agent's version of the API, not the user's version of the API, that instantiates a SpanContext. I thought we agreed this is ok in that issue.

Also one point of note is that we don't lose any protection with this PR since it's already an abstract class. Of course, we could stop using AutoValue to prevent that, just an observation. With #1937 I am thinking of a general question on whether we should just avoid classes at all in the API - it's an API after all. If a custom SDK (which our auto instrumentation agent effectively is) finds a reason to override the implementation and satisfies a use case with it, why block it?

@Oberon00
Copy link
Member

I suspected as much 😃 But I thought it was better to document it on the PR that does the change.

So the interface makes it even easier for the auto-instrumentation than the previous abstract class?

@anuraaga
Copy link
Contributor Author

anuraaga commented Oct 30, 2020

@Oberon00 Yeah - one class can implement both the agent (shaded) API interface and application API interface, but with abstract classes we wouldn't be able to do that so end up copying between two classes instead.

Copy link
Contributor

@jkwatson jkwatson left a comment

Choose a reason for hiding this comment

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

If it helps auto-instrumentation and doesn't hurt the end-user experience, I'm all in favor.

@@ -17,23 +15,15 @@
* traceState} and the {@link boolean remote} flag.
*/
@Immutable
Copy link
Member

Choose a reason for hiding this comment

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

Does this still make sense on an interface?

Copy link
Member

Choose a reason for hiding this comment

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

I think it does. It places an requirement on all implementers and offers guarantees to users.

Copy link
Contributor

Choose a reason for hiding this comment

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

Obviously, it's a soft requirement, since it can't be enforced, but I still think it's a good thing to document.

Copy link
Member

@bogdandrutu bogdandrutu left a comment

Choose a reason for hiding this comment

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

Blocked until #1946

@jkwatson
Copy link
Contributor

jkwatson commented Nov 1, 2020

After further thinking, I'd prefer SpanContext stay not as an interface, but as a final class (or AutoValue'd class). It's a core piece of data for the API, and since it's data-only, having it be non-interface is preferable to me.

@jkwatson jkwatson self-requested a review November 2, 2020 16:46
Copy link
Contributor

@jkwatson jkwatson left a comment

Choose a reason for hiding this comment

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

Thanks!

@trask
Copy link
Member

trask commented Nov 24, 2020

@bogdandrutu can you unblock this PR, or comment on #1946 which you blocked this on?

@jkwatson
Copy link
Contributor

After further thinking, I'd prefer SpanContext stay not as an interface, but as a final class (or AutoValue'd class). It's a core piece of data for the API, and since it's data-only, having it be non-interface is preferable to me.

Note: although I usually favor data-as-classes, I'm on board with this change.

Comment on lines +114 to 116
default boolean isValid() {
return TraceId.isValid(getTraceIdAsHexString()) && SpanId.isValid(getSpanIdAsHexString());
}
Copy link
Member

Choose a reason for hiding this comment

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

this will become more expensive after this change, we should calculate this only once since it is used couple of times per instance created.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, see above...this is still memoized by the implementation.

Comment on lines +86 to 88
default byte[] getSpanIdBytes() {
return SpanId.bytesFromHex(getSpanIdAsHexString(), 0);
}
Copy link
Member

Choose a reason for hiding this comment

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

Why removing the ability to memoized this call? It may get expensive. I would suggest to not default this and any method that was memoized before.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is still memoized by the autovalue implementation. See ImmutableSpanContext above.

@bogdandrutu
Copy link
Member

My concern still stays on a general level. If there was no auto-instrumentation project majority of the engineers have implemented this as a final class, so I am concerned that we do designed choices based on an external project need that may influence the overall usability and performance of the core product. This designed choices may affect us in the future in an unknown way.

I do understand the needs coming from auto-instrumentation, but you need to keep in mind that right now we need to be prepared to deal with cases where users will implement this in a "unexpected" way like having mutable objects inside the SpanContext, etc. this may cause problems for us, and we may have to deal with this.

@bogdandrutu bogdandrutu dismissed their stale review November 25, 2020 16:33

Discussed with @jkwatson, we will add a note about not supporting alternative implementations

@anuraaga
Copy link
Contributor Author

anuraaga commented Dec 1, 2020

Thanks! Added a warning

@jkwatson
Copy link
Contributor

jkwatson commented Dec 1, 2020

@marcingrzejszczak this is potentially a breaking change

@jkwatson jkwatson merged commit 0163a8c into open-telemetry:master Dec 1, 2020
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.

6 participants