Skip to content

Instantly share code, notes, and snippets.

@mabn
Last active August 3, 2017 23:15
Show Gist options
  • Save mabn/9246ebb03aa1534b33b98bd728158b11 to your computer and use it in GitHub Desktop.
Save mabn/9246ebb03aa1534b33b98bd728158b11 to your computer and use it in GitHub Desktop.
Making scope work?
import java.io.Closeable;
interface ActiveSpanSource {
// no changes
ActiveSpan makeActive(Span span);
}
interface Tracer extends ActiveSpanSource{
// no changes
SpanBuilder buildSpan(String operationName);
}
interface Span extends AutoCloseable {
Span setTag(String key, String value);
// Creates "an inactive ActiveSpan" which can be "activated" and turned into regular ActiveSpan. It
// has only a single purpose - to carry some contextual information to another thread. Using
// "capture" is not mandatory
Continuation capture();
/**
* By default deactivates the span (if it was active) and finishes the span. The behaviour
* is defined by the lifecycle used to create the span and another lifecycle can be provided
* at span creation.
*/
@Override
void close();
// yes! it's back!
void finish();
}
interface SpanBuilder {
// starts span and makes it active in the current thread
Span startActive();
// allows to alter span's lifecycle management - e.g. how Span.close() behaves
Span startActive(SpanLifecycle lifecycle);
// no changes, starts inactive span
Span startManual();
SpanBuilder childOf(Span span);
}
// represents the scope of span activity. provides access to the span that is active in this scope
// via span(). closed ActiveSpan is no longer valid - it's an error to call span() on it
interface ActiveSpan extends Closeable {
// the main change - it has no span method! instead - span get be obtained with span()
Span span();
/**
* By default deactivates current ActiveSpan (but does not finish the span!). The behaviour is
* defined by the lifecycle used to create the span and another lifecycle can be provided at
* span creation.
*/
@Override
void close();
}
interface Continuation {
ActiveSpan activate();
}
interface SpanLifecycle {
void onClose(Span span);
}
public class Test {
Tracer tracer = null;
ActiveSpanSource activeSpanSource = tracer;
void active_span_in_current_thread() {
tracer.buildSpan("a").startActive();
try (Span span = tracer.buildSpan("a").startActive()) {
doSomething();
} // at this point I'm done, no more interactions with the span. It should be deactivated
// and finished
}
void activate_span_in_other_thread() {
try (Span span = tracer.buildSpan("a").startActive()){
inOtherThread(() -> {
try (ActiveSpan active = activeSpanSource.makeActive(span)){
active.span().setTag("k","v");
} // here the ActiveSpan deactivates, but the span is not finished
});
} // at this point I'm done, no more interactions with the span. it should be deactivated
// and finished. This is the default behavior of startActive()
}
void automatic_finish_is_possible_but_optional() {
// this span has non-default lifecycle management:
try (Span span = tracer.buildSpan("a").startActive(new AutoFinisher())){
inOtherThread(() -> { // Assume that the child thread lives longer than the parent
try (ActiveSpan active = activeSpanSource.makeActive(span)){
active.span().setTag("k","v");
} // this finishes the span because AutoFinisher counts activations,
// deactivations and finishes the span after the Span and the last ActiveSpan are closed
});
} // this does not finish the span as it is still active in the child thread - that's the behaviour
// of AutoFinisher
}
void carry_thread_locals_to_child_thread() {
try (Span span = tracer.buildSpan("a").startActive()){
Continuation toActivate = span.capture();
inOtherThread(() -> {
try (ActiveSpan active = toActivate.activate()){
} // here the ActiveSpan deactivates, but the span is not finished
});
} // at this point I'm done, no more interactions with the span. it should be
// deactivated and finished (the child thread finishes before the parent)
}
void create_child_span_in_the_same_thread() {
try (Span parent = tracer.buildSpan("parent").startActive()){
try(Span child = tracer.buildSpan("child").childOf(parent).startActive()) {
doSomething();
}; // deactivates and finishes child
} // deactivates and finishes parent
}
void create_child_span_in_another_thread() {
try (Span parent = tracer.buildSpan("parent").startActive()){
inOtherThread(() -> {
try(Span child = tracer.buildSpan("child").childOf(parent).startActive()) {
doSomething();
}; // deactivates and finishes child
});
} // deactivates and finishes parent
}
// stuff to make this thing compile
void doSomething(){}
void inOtherThread(RunnableWithException c){}
interface RunnableWithException {
void run() throws Exception;
}
class AutoFinisher implements SpanLifecycle {
@Override
public void onClose(Span span) {
throw new UnsupportedOperationException();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment