Remove finish span on close#301
Conversation
| * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a | ||
| * programming error to neglect to call {@link Scope#close()} on the returned instance. | ||
| */ | ||
| Scope activate(Span span); |
There was a problem hiding this comment.
I would add sample code like
Span span = tracer.startSpan...
try (Scope scope = tracer.activate(span)) {
} catch (Exception e) {
span.log(..)
} finally {
span.finish()
}
| * @see Scope | ||
| */ | ||
| Scope startActive(boolean finishSpanOnClose); | ||
| Scope startActive(); |
There was a problem hiding this comment.
Do we actually need this method? It seems to promote the exact same bad practice.
There was a problem hiding this comment.
The Scope and auto-finish were originally designed for use with try-with-resource, but that pattern does not allow for logging exceptions to the span since the scope is not visible in the catch clause. Thus the recommended pattern is what I showed in https://github.com/opentracing/opentracing-java/pull/301/files#r213032222, which requires access to the span reference and only using Scope as a way to move the spans on and off the thread-local stack.
Using startActive() essentially suffers from the same problem - you can use it with try-catch, but not in the catch clause.
So it's back to: what is ultimate goal of this PR? The existing API works, but has gotchas for people unfamiliar with it.
There was a problem hiding this comment.
Oh, that crossed my mind too. So I think that, if it stays, we would need to be clear about the implications of its usage - that is needs to be used with a standard try block, i.e.
Scope scope = tracer.buildSpan("foo").startActive();
try {
} catch (Exception e) {
Tags.ERROR.set(scope.span(), true);
} finally {
scope.span().finish();
scope.close();
}(That's why I used such usage in its updated inline documentation ;) )
I'd be up for keeping it (with the proper documentation), but definitely understand it's not a perfect thing, and I'm open to have it removed if deemed so (in such case I will update the PR).
There was a problem hiding this comment.
Good point Yuri. I think the fact that I fell for it again, suggesting to use try-with-resources + catch demonstrates that the API can easily misused. I also suggest removing it. Isn’t the intention of this PR to avoid potential misuse of the API? Also,startActive is just syntactic sugar (which turned out to be bittersweet ;).
There was a problem hiding this comment.
This is a strange method, please remove it.
There was a problem hiding this comment.
Seems we have found agreement on this point, so I will update this PR in the next days to have it removed ;)
| * The span will not be automatically finished when {@link Scope#close()} is called. | ||
| * | ||
| * <p> | ||
| * The returned {@link Scope} supports try-with-resources, but is usually |
There was a problem hiding this comment.
Why is it not usually used with try-with-resources?
There was a problem hiding this comment.
That's related to Yuri's comment about removing it - essentially, that, as opposed to using ScopeManager.activate(), here we need an usual try block to do the cleanup (that is, having a reference to the Span to finish it after any error has occurred).
try (Scope scope = tracer.buildSpan("foo").startActive()) {
} catch (Exception e) {
// scope and scope.span() are not reachable here nor in the finally section :/
}(I wish we could simply have something like try (scope) { ... but Java doesn't have support for that)
There was a problem hiding this comment.
If this method isn't deleted, I think it would be cleaner if done similar to census and brave's "scoped span" Instead of messing with scope, mess with span.finish(). In other words, return a Span, and do mention it is a programming error to not call span.finish on the same thread. Another way is to leave it out..
Here's the javadoc from brave's ScopedSpan:
/**
* Closes the {@link CurrentTraceContext#newScope(TraceContext) scope} associated with this span,
* then reports the span complete, assigning the most precise duration possible.
*/
public abstract void finish();| * scope = tracer.buildSpan("...").startActive(); | ||
| * // (Do work) | ||
| * scope.span().setTag( ... ); // etc, etc | ||
| * } finally { |
There was a problem hiding this comment.
Will add it 👍
codefromthecrypt
left a comment
There was a problem hiding this comment.
Thanks for this.. I'm not feeling great about startActive as it is defined right now. It can either be left out or refactored.
| public interface ScopeManager { | ||
|
|
||
| /** | ||
| * @deprecated use {@link #activate} instead. |
There was a problem hiding this comment.
nit move to the bottom and say when it will be removed (ideally next release as would the other deprecated methods added prior.. deprecation pre 1.0 is a strange thing but anyway)
There was a problem hiding this comment.
I don't think there's a date to remove this one (we should discuss this topic, but another time ;) ), but we could say "in the next releases" (and definitely before 1.0 ;) )
| Scope activate(Span span, boolean finishSpanOnClose); | ||
|
|
||
| /** | ||
| * Make a {@link Span} instance active. |
There was a problem hiding this comment.
add some description of what active means as the word isn't intuitive.
For example "Makes this span visible via commands like (XX) until the corresponding scope is close"
Also, note that it is a programming error to leave the scope unclosed or to attempt to close it on a different thread.
There was a problem hiding this comment.
Thanks, will add such explanation.
| SpanBuilder withStartTimestamp(long microseconds); | ||
|
|
||
| /** | ||
| * @deprecated use {@link #startActive} instead. |
| * @see Scope | ||
| */ | ||
| Scope startActive(boolean finishSpanOnClose); | ||
| Scope startActive(); |
There was a problem hiding this comment.
This is a strange method, please remove it.
| * The span will not be automatically finished when {@link Scope#close()} is called. | ||
| * | ||
| * <p> | ||
| * The returned {@link Scope} supports try-with-resources, but is usually |
There was a problem hiding this comment.
If this method isn't deleted, I think it would be cleaner if done similar to census and brave's "scoped span" Instead of messing with scope, mess with span.finish(). In other words, return a Span, and do mention it is a programming error to not call span.finish on the same thread. Another way is to leave it out..
Here's the javadoc from brave's ScopedSpan:
/**
* Closes the {@link CurrentTraceContext#newScope(TraceContext) scope} associated with this span,
* then reports the span complete, assigning the most precise duration possible.
*/
public abstract void finish();|
on the note about scope.. it is odd because scope in opentracing still has an accessor to the span. it makes it awkward and still encourages passing the scope around. I think this should be removed along with this change. When
Either way, please don't forget to remove your scope.span as it encourages people to leak scopes. |
|
Hey @adriancole Thanks for the feedback. So my personal take for your points is:
Span span = tracer.buildSpan("one").startActive();
try {
} catch (Exception e) {
...
span.finish();
} finally {
tracer.scopeManager.active().close();
}This being implicit kinda makes me wonder (but definitely thing to consider).
So the thing about removing Opinions? @felixbarny @yurishkuro @tedsuo |
|
are we shooting for this? Span span = tracer.buildSpan("nasty").start();
try (Scope scope = tracer.activate(span)) {
// do nasty stuff
} catch (Exception e) {
span.SetTag(...);
...
} finally {
span.finish();
}It makes the usage slightly more verbose than the current api, especially without try-with-resource (only if <=1.6, who cares), but avoids the misuse. |
|
I agree with @yurishkuro
*deprecate and eventually remove |
|
Hey, Was wondering, after the feedback, about this (small variation):
|
|
For additional information: some frameworks do not let us 'wrap' their entire operation, but provide hooks for In some cases, as mentioned in the main discussion, the user does not even have a place to store context information as part of the aforementioned Either way, we decide to go a) or b) (or even both), and improving greatly the documentation (mentioning what should never be done with |
|
Sounds fine to me |
| * try (Scope scope = tracer.buildSpan("...").startActive(true)) { | ||
| * Scope scope = null; | ||
| * try { | ||
| * scope = tracer.buildSpan("...").startActive(); |
There was a problem hiding this comment.
please inline this before the try. That removes the null checking later.
Also, as mentioned I think the scope having an accessor to the span is problematic.
2402d20 to
9607986
Compare
|
Hey all, This PR is updated to reflect the latest requested changes, namely:
|
opentracing-testbed/src/test/java/io/opentracing/testbed/activate_deactivate/README.md
Show resolved
Hide resolved
| * } catch (Exception e) { | ||
| * span.log(...); | ||
| * } finally { | ||
| * span.finish(); // Optionally finish the Span. |
There was a problem hiding this comment.
// Optionally finish the Span if the operation it represents is logically completed at this point.
| * Return the currently active {@link Span}. | ||
| * | ||
| * <p> | ||
| * If there is an {@link Span non-null active span}, it becomes an implicit parent |
There was a problem hiding this comment.
Is it necessary to have this mentioned here? It think this comment only belongs to the span builder methods. Scope Manager as an abstraction is not tied to the builder's behavior.
| * | ||
| * <p> | ||
| * Because both {@link #active()} and {@link #activeSpan()} reference the current | ||
| * the active state, they both will be either null or non-null. |
| * This is a shorthand for {@code Tracer.scopeManager().activate(span)}. | ||
| * | ||
| * @return a {@link Scope} instance to control the end of the active period for the {@link Span}. It is a | ||
| * programming error to neglect to call {@link Scope#close()} on the returned instance. |
There was a problem hiding this comment.
and may lead to memory leaks and the scope may remain in the thread-local stack.
| * // It's also possible to create Spans manually, bypassing the ScopeManager activation. | ||
| * Span http = tracer.buildSpan("HandleHTTPRequest") | ||
| * // Note: if there is a `tracer.activeSpan()` instance, it will be used as the target | ||
| * // of an implicit CHILD_OF Reference when `start()` is invoked. |
There was a problem hiding this comment.
unless another span reference is explicitly provided to the builder
|
@yurishkuro Thanks for the edit notes, appreciated. Please take a look whenever you can ;) |
|
Hey @felixbarny @adriancole Wondering if you are fine with this PR? If yes, I'd like to have it merged, and probably have a Release Candidate to test things out soon after. @yurishkuro Docs edits look good to you? ;) |
|
LGTM |
|
Thanks @felixbarny ! I will proceed to merge this PR tomorrow as if seems to have found a proper trade-off of features, unless there's any complain from anybody ;) |
|
Merged, thanks everybody for their feedback! Remember that this is not a final change, and it could be changed if/as needed (we will likely be doing a Release Candidate to test this and other changes out) ;) |
|
@carlosalberto I didn't participate in this PR as my opinion is already voiced by others, but I forgot to thank you for creating this! |
* Deprecate the StringTag.set() overload taking a StringTag. (#262) * Implement Trace Identifiers. (#280) * Bump JaCoCo to use a Java 10 friendly version (#306) * Remove finish span on close (#301) * Deprecate finishSpanOnClose on activation. * Add ScopeManager.activeSpan() and Tracer.activateSpan(). * Clarify the API changes and deprecations. * Add an error reporting sample to opentracing-testbed. * Simple layer on top of ByteBuffer for BINARY format. (#276) * Add generic typed setTag/withTag (#311) * Allow injecting into maps of type Map<String,Object> (#310) * Add simple registerIfAbsent to global tracer (#289) * Split Inject and Extract Builtin interfaces (#316) * Deprecate ScopeManager.active() (#326) * Make Tracer extends Closable. (#329) * Do not make isRegistered() synchronized. (#333) * Deprecate AutoFinishScopeManager (#335)
Addresses #291
SpanBuilder.startActive(Span, boolean)andScopeManager.activate(Span, bool)have been kept, but as deprecated methods.Updated the
opentracing-testbedcode to use this change, and added a new, small,error-reportingcase.cc @felixbarny @adriancole @yurishkuro @tedsuo @sjoerdtalsma