-
Notifications
You must be signed in to change notification settings - Fork 345
Add Span#unwrap #211
base: v0.31.0
Are you sure you want to change the base?
Add Span#unwrap #211
Conversation
* Returns an object that is an instance of the given class to allow access to non-standard methods. | ||
* | ||
* <p> Using this method is highly preferred to type casts, especially because there might be a hierarchy of wrapper | ||
* objects. </p> |
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.
based on the two implementations (Mock and Noop), not clear how this is different from cast - is the intention that wrappers will override this method?
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.
Yes, a wrapper's implementation might look like this:
public <T extends Span> T unwrap(Class<T> clazz) {
if (clazz.isInstance(this)) {
return clazz.cast(this);
} else {
return delegate.unwrap(clazz);
}
}
where delegate
is a Span
instance variable
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.
Or, if Java 8+ is the baseline, the interface can implement a basic unwrap
routine, freeing up implementations to have code that would be mostly duplicated.
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.
At first glance it looks as though we 'pollute' Span with a concern that may not be applicable to all spans.
Maybe define a SpanWrapper
interface for this that all wrappers can then implement? This keeps Span cleaner.
interface SpanWrapper extends Span {
<T extends Span> T unwrap(Class<T> spanType);
}
SpanWrapper could be part of |
That kind of defeats the whole purpose of the PR. Because then it is still not possible to unwrap a plain Span to a specific one without type casts. By the way, this is heavily inspired by JDBC wrappers: https://docs.oracle.com/javase/7/docs/api/java/sql/Wrapper.html |
I know. 😉 In my opinion unwrapping is not something that is of use for the general API; people have a static <T extends Span> T unwrap(Span span, Class<T> spanType) {
return span instanceof SpanWrapper ? ((SpanWrapper) span).unwrap(spanType) : null;
} The point of this PR should be (in my opinion) a standardized way to indicate that you can unwrap. For this the interface serves the purpose. For me not mixing concerns and having a clean api outweighs typechecks any day. Just my opinion of course. Curious what others think. |
But how can we enforce then that each tracer's |
You can't unfortunately. |
I don't think this adds significant value to the general API. If the wrap fails, then it just returns null. That seems like a worse place to be. Not to mention, this will just encourage people to write code that is specific to a tracer implementation, rather than the OT api. At that point, why pretend to use the OT api at all? Just work directly with the tracer's concrete types all the way through. |
I think this is a good improvement to the API. Other successful APIs, like JPA, have such methods and it's really handy to have them when you absolutely need to have access to an implementation-specific feature.
I don't think it will encourage. People are already doing casts to get the underlying trace IDs. |
Which points to the root cause: An omission of a general concept in the OpenTracing api: Trace ID's. I still say: Let people typecast at their on risk but not facilitate this. Needing typecasts is usually a sign that a needed concept is still missing in the core API. By the way: I agree that it would be hugely beneficial for the end user if there were a single place to go get an opaque trace ID, I just don't think that polluting the API with unwrapping is the way to go. |
Trace IDs was just one example of why people are doing that today.
It's very common for features to flow from implementations into the standard, like it has happened multiple times in the JPA world (from EclipseLink/Hibernate to JPA). People will cast to the concrete implementation when they need, no matter if we provide a |
I think it's useful, and especially if wrappers are used, otherwise there is no way to properly cast the object. |
Now that we are moving on Trace Identifiers, we should consider adding unwrap as part of the same release. A couple thoughts:
|
+1, it would help in MicroProfile-OpenTracing TCK and other use cases. The test deployment uses Unwrap would be also helpful in |
...which was specifically designed to provide only the API, so people are not tempted to work around it. I'm still 👎 on adding |
@sjoerdtalsma you might have missed microprofile-opentracing use case altogether... A reasonably well designed API shouldn't force you to do reflectio, like it is currently with globaltracer API. If a caller does dummy thins it's his issue. Look at other APIs e.g. JPA or hystrix plugins... |
@pavolloffay I'm genuinely willing to be convinced.
.. and the reference point 3 you mentioned:
Probably I'm missing something, but from the above I still don't get what the use-case for unwrap is here.. I think @tylerbenson explained better than me when he wrote
|
With
Span
wrappers becoming more and more popular (for example https://github.com/opentracing-contrib/java-api-extensions). There is a growing need to be able to get access to the underlyingSpan
implementation without type casts which fail if there is a hierarchy of span wrappers.