Don't create continuations when async propagation is off
This commit is contained in:
parent
a0a11a51d0
commit
d594d6e8db
|
@ -33,21 +33,21 @@ class AkkaActors {
|
||||||
|
|
||||||
@Trace
|
@Trace
|
||||||
def basicTell() : Unit = {
|
def basicTell() : Unit = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
howdyGreeter ! WhoToGreet("Akka")
|
howdyGreeter ! WhoToGreet("Akka")
|
||||||
howdyGreeter ! Greet
|
howdyGreeter ! Greet
|
||||||
}
|
}
|
||||||
|
|
||||||
@Trace
|
@Trace
|
||||||
def basicAsk() : Unit = {
|
def basicAsk() : Unit = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
howdyGreeter ! WhoToGreet("Akka")
|
howdyGreeter ! WhoToGreet("Akka")
|
||||||
howdyGreeter ? Greet
|
howdyGreeter ? Greet
|
||||||
}
|
}
|
||||||
|
|
||||||
@Trace
|
@Trace
|
||||||
def basicForward() : Unit = {
|
def basicForward() : Unit = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
helloGreeter ! WhoToGreet("Akka")
|
helloGreeter ! WhoToGreet("Akka")
|
||||||
helloGreeter ? Greet
|
helloGreeter ? Greet
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ScalaConcurrentTests {
|
||||||
*/
|
*/
|
||||||
@Trace
|
@Trace
|
||||||
def traceWithFutureAndCallbacks() : Integer = {
|
def traceWithFutureAndCallbacks() : Integer = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
val goodFuture: Future[Integer] = Future {
|
val goodFuture: Future[Integer] = Future {
|
||||||
tracedChild("goodFuture")
|
tracedChild("goodFuture")
|
||||||
1
|
1
|
||||||
|
@ -34,7 +34,7 @@ class ScalaConcurrentTests {
|
||||||
|
|
||||||
@Trace
|
@Trace
|
||||||
def tracedAcrossThreadsWithNoTrace() :Integer = {
|
def tracedAcrossThreadsWithNoTrace() :Integer = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
val goodFuture: Future[Integer] = Future {
|
val goodFuture: Future[Integer] = Future {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ class ScalaConcurrentTests {
|
||||||
*/
|
*/
|
||||||
@Trace
|
@Trace
|
||||||
def traceWithPromises() : Integer = {
|
def traceWithPromises() : Integer = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
val keptPromise = Promise[Boolean]()
|
val keptPromise = Promise[Boolean]()
|
||||||
val brokenPromise = Promise[Boolean]()
|
val brokenPromise = Promise[Boolean]()
|
||||||
val afterPromise = keptPromise.future
|
val afterPromise = keptPromise.future
|
||||||
|
@ -87,7 +87,7 @@ class ScalaConcurrentTests {
|
||||||
*/
|
*/
|
||||||
@Trace
|
@Trace
|
||||||
def tracedWithFutureFirstCompletions() :Integer = {
|
def tracedWithFutureFirstCompletions() :Integer = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
val completedVal = Future.firstCompletedOf(
|
val completedVal = Future.firstCompletedOf(
|
||||||
List(
|
List(
|
||||||
Future {
|
Future {
|
||||||
|
@ -111,7 +111,7 @@ class ScalaConcurrentTests {
|
||||||
*/
|
*/
|
||||||
@Trace
|
@Trace
|
||||||
def tracedTimeout(): Integer = {
|
def tracedTimeout(): Integer = {
|
||||||
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncLinking(true)
|
GlobalTracer.get().scopeManager().active().asInstanceOf[TraceScope].setAsyncPropagation(true)
|
||||||
val f: Future[String] = Future {
|
val f: Future[String] = Future {
|
||||||
tracedChild("timeoutChild")
|
tracedChild("timeoutChild")
|
||||||
while(true) {
|
while(true) {
|
||||||
|
|
|
@ -141,7 +141,7 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable {
|
||||||
@Advice.Argument(value = 0, readOnly = false) Runnable task) {
|
@Advice.Argument(value = 0, readOnly = false) Runnable task) {
|
||||||
final Scope scope = GlobalTracer.get().scopeManager().active();
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
if (scope instanceof TraceScope
|
if (scope instanceof TraceScope
|
||||||
&& ((TraceScope) scope).isAsyncLinking()
|
&& ((TraceScope) scope).isAsyncPropagating()
|
||||||
&& task != null
|
&& task != null
|
||||||
&& !(task instanceof DatadogWrapper)) {
|
&& !(task instanceof DatadogWrapper)) {
|
||||||
task = new RunnableWrapper(task, (TraceScope) scope);
|
task = new RunnableWrapper(task, (TraceScope) scope);
|
||||||
|
@ -165,7 +165,7 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable {
|
||||||
@Advice.Argument(value = 0, readOnly = false) Callable task) {
|
@Advice.Argument(value = 0, readOnly = false) Callable task) {
|
||||||
final Scope scope = GlobalTracer.get().scopeManager().active();
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
if (scope instanceof TraceScope
|
if (scope instanceof TraceScope
|
||||||
&& ((TraceScope) scope).isAsyncLinking()
|
&& ((TraceScope) scope).isAsyncPropagating()
|
||||||
&& task != null
|
&& task != null
|
||||||
&& !(task instanceof DatadogWrapper)) {
|
&& !(task instanceof DatadogWrapper)) {
|
||||||
task = new CallableWrapper(task, (TraceScope) scope);
|
task = new CallableWrapper(task, (TraceScope) scope);
|
||||||
|
@ -188,7 +188,7 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable {
|
||||||
public static Collection<?> wrapJob(
|
public static Collection<?> wrapJob(
|
||||||
@Advice.Argument(value = 0, readOnly = false) Collection<? extends Callable<?>> tasks) {
|
@Advice.Argument(value = 0, readOnly = false) Collection<? extends Callable<?>> tasks) {
|
||||||
final Scope scope = GlobalTracer.get().scopeManager().active();
|
final Scope scope = GlobalTracer.get().scopeManager().active();
|
||||||
if (scope instanceof TraceScope && ((TraceScope) scope).isAsyncLinking()) {
|
if (scope instanceof TraceScope && ((TraceScope) scope).isAsyncPropagating()) {
|
||||||
Collection<Callable<?>> wrappedTasks = new ArrayList<>(tasks.size());
|
Collection<Callable<?>> wrappedTasks = new ArrayList<>(tasks.size());
|
||||||
for (Callable task : tasks) {
|
for (Callable task : tasks) {
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
|
@ -247,7 +247,7 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final TraceScope context = continuation.activate();
|
final TraceScope context = continuation.activate();
|
||||||
context.setAsyncLinking(true);
|
context.setAsyncPropagation(true);
|
||||||
try {
|
try {
|
||||||
delegatee.run();
|
delegatee.run();
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -268,7 +268,7 @@ public final class ExecutorInstrumentation extends Instrumenter.Configurable {
|
||||||
@Override
|
@Override
|
||||||
public T call() throws Exception {
|
public T call() throws Exception {
|
||||||
final TraceScope context = continuation.activate();
|
final TraceScope context = continuation.activate();
|
||||||
context.setAsyncLinking(true);
|
context.setAsyncPropagation(true);
|
||||||
try {
|
try {
|
||||||
return delegatee.call();
|
return delegatee.call();
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -50,7 +50,7 @@ class ExecutorInstrumentationTest extends AgentTestRunner {
|
||||||
@Override
|
@Override
|
||||||
@Trace(operationName = "parent")
|
@Trace(operationName = "parent")
|
||||||
void run() {
|
void run() {
|
||||||
((ContinuableScope) GlobalTracer.get().scopeManager().active()).setAsyncLinking(true)
|
((ContinuableScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(true)
|
||||||
// this child will have a span
|
// this child will have a span
|
||||||
m.invoke(pool, new AsyncChild())
|
m.invoke(pool, new AsyncChild())
|
||||||
// this child won't
|
// this child won't
|
||||||
|
@ -95,7 +95,7 @@ class ExecutorInstrumentationTest extends AgentTestRunner {
|
||||||
@Override
|
@Override
|
||||||
@Trace(operationName = "parent")
|
@Trace(operationName = "parent")
|
||||||
void run() {
|
void run() {
|
||||||
((ContinuableScope) GlobalTracer.get().scopeManager().active()).setAsyncLinking(true)
|
((ContinuableScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(true)
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < 20; ++ i) {
|
for (int i = 0; i < 20; ++ i) {
|
||||||
Future f = pool.submit((Callable)child)
|
Future f = pool.submit((Callable)child)
|
||||||
|
|
|
@ -99,7 +99,7 @@ public final class PlayInstrumentation extends Instrumenter.Configurable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
|
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
|
||||||
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncLinking(true);
|
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(true);
|
||||||
}
|
}
|
||||||
return scope;
|
return scope;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +175,7 @@ public final class PlayInstrumentation extends Instrumenter.Configurable {
|
||||||
public Object apply(Throwable t, boolean isCheck) throws Exception {
|
public Object apply(Throwable t, boolean isCheck) throws Exception {
|
||||||
try {
|
try {
|
||||||
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
|
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
|
||||||
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncLinking(false);
|
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(false);
|
||||||
}
|
}
|
||||||
onError(span, t);
|
onError(span, t);
|
||||||
} catch (Throwable t2) {
|
} catch (Throwable t2) {
|
||||||
|
@ -202,7 +202,7 @@ public final class PlayInstrumentation extends Instrumenter.Configurable {
|
||||||
|
|
||||||
public Result apply(Result result) {
|
public Result apply(Result result) {
|
||||||
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
|
if (GlobalTracer.get().scopeManager().active() instanceof TraceScope) {
|
||||||
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncLinking(false);
|
((TraceScope) GlobalTracer.get().scopeManager().active()).setAsyncPropagation(false);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Tags.HTTP_STATUS.set(span, result.header().status());
|
Tags.HTTP_STATUS.set(span, result.header().status());
|
||||||
|
|
|
@ -14,10 +14,14 @@ public interface TraceScope {
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
/** If true, this context will propagate across async boundaries. */
|
/** If true, this context will propagate across async boundaries. */
|
||||||
boolean isAsyncLinking();
|
boolean isAsyncPropagating();
|
||||||
|
|
||||||
/** Set context's async propagation value. */
|
/**
|
||||||
void setAsyncLinking(boolean value);
|
* Enable or disable async propagation. Async propagation is initially set to false.
|
||||||
|
*
|
||||||
|
* @param value The new propagation value. True == propagate. False == don't propagate.
|
||||||
|
*/
|
||||||
|
void setAsyncPropagation(boolean value);
|
||||||
|
|
||||||
/** Used to pass async context between workers. */
|
/** Used to pass async context between workers. */
|
||||||
interface Continuation {
|
interface Continuation {
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class ContinuableScope implements Scope, TraceScope {
|
||||||
/** Continuation that created this scope. May be null. */
|
/** Continuation that created this scope. May be null. */
|
||||||
private final Continuation continuation;
|
private final Continuation continuation;
|
||||||
/** Flag to propagate this scope across async boundaries. */
|
/** Flag to propagate this scope across async boundaries. */
|
||||||
private final AtomicBoolean isAsyncLinking = new AtomicBoolean(false);
|
private final AtomicBoolean isAsyncPropagating = new AtomicBoolean(false);
|
||||||
|
|
||||||
ContinuableScope(
|
ContinuableScope(
|
||||||
final ContextualScopeManager scopeManager,
|
final ContextualScopeManager scopeManager,
|
||||||
|
@ -73,23 +73,26 @@ public class ContinuableScope implements Scope, TraceScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAsyncLinking(boolean value) {
|
public boolean isAsyncPropagating() {
|
||||||
isAsyncLinking.set(value);
|
return isAsyncPropagating.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAsyncLinking() {
|
public void setAsyncPropagation(boolean value) {
|
||||||
return isAsyncLinking.get();
|
isAsyncPropagating.set(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The continuation returned should be closed after the associa
|
* The continuation returned must be closed or activated or the trace will not finish.
|
||||||
*
|
*
|
||||||
* @param finishOnClose
|
* @return The new continuation, or null if this scope is not async propagating.
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public Continuation capture() {
|
public Continuation capture() {
|
||||||
return new Continuation();
|
if (isAsyncPropagating()) {
|
||||||
|
return new Continuation();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Continuation implements Closeable, TraceScope.Continuation {
|
public class Continuation implements Closeable, TraceScope.Continuation {
|
||||||
|
|
|
@ -92,10 +92,30 @@ class ScopeManagerTest extends Specification {
|
||||||
finishSpan << [true, false]
|
finishSpan << [true, false]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def "ContinuableScope only creates continuations when propagation is set"() {
|
||||||
|
setup:
|
||||||
|
def builder = tracer.buildSpan("test")
|
||||||
|
def scope = (ContinuableScope) builder.startActive(true)
|
||||||
|
def continuation = scope.capture()
|
||||||
|
|
||||||
|
expect:
|
||||||
|
continuation == null
|
||||||
|
|
||||||
|
when:
|
||||||
|
scope.setAsyncPropagation(true)
|
||||||
|
continuation = scope.capture()
|
||||||
|
then:
|
||||||
|
continuation != null
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
continuation.close()
|
||||||
|
}
|
||||||
|
|
||||||
def "ContinuableScope doesn't close if non-zero"() {
|
def "ContinuableScope doesn't close if non-zero"() {
|
||||||
setup:
|
setup:
|
||||||
def builder = tracer.buildSpan("test")
|
def builder = tracer.buildSpan("test")
|
||||||
def scope = (ContinuableScope) builder.startActive(true)
|
def scope = (ContinuableScope) builder.startActive(true)
|
||||||
|
scope.setAsyncPropagation(true)
|
||||||
def continuation = scope.capture()
|
def continuation = scope.capture()
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
|
@ -149,6 +169,7 @@ class ScopeManagerTest extends Specification {
|
||||||
def builder = tracer.buildSpan("test")
|
def builder = tracer.buildSpan("test")
|
||||||
def scope = (ContinuableScope) builder.startActive(false)
|
def scope = (ContinuableScope) builder.startActive(false)
|
||||||
def span = scope.span()
|
def span = scope.span()
|
||||||
|
scope.setAsyncPropagation(true)
|
||||||
def continuation = scope.capture()
|
def continuation = scope.capture()
|
||||||
scope.close()
|
scope.close()
|
||||||
span.finish()
|
span.finish()
|
||||||
|
@ -186,6 +207,7 @@ class ScopeManagerTest extends Specification {
|
||||||
def parentScope = tracer.buildSpan("parent").startActive(true)
|
def parentScope = tracer.buildSpan("parent").startActive(true)
|
||||||
def parentSpan = parentScope.span()
|
def parentSpan = parentScope.span()
|
||||||
ContinuableScope childScope = (ContinuableScope) tracer.buildSpan("parent").startActive(true)
|
ContinuableScope childScope = (ContinuableScope) tracer.buildSpan("parent").startActive(true)
|
||||||
|
childScope.setAsyncPropagation(true)
|
||||||
def childSpan = childScope.span()
|
def childSpan = childScope.span()
|
||||||
|
|
||||||
def continuation = childScope.capture()
|
def continuation = childScope.capture()
|
||||||
|
@ -209,6 +231,7 @@ class ScopeManagerTest extends Specification {
|
||||||
|
|
||||||
when:
|
when:
|
||||||
def newScope = continuation.activate()
|
def newScope = continuation.activate()
|
||||||
|
newScope.setAsyncPropagation(true)
|
||||||
def newContinuation = newScope.capture()
|
def newContinuation = newScope.capture()
|
||||||
|
|
||||||
then:
|
then:
|
||||||
|
@ -236,6 +259,7 @@ class ScopeManagerTest extends Specification {
|
||||||
def builder = tracer.buildSpan("test")
|
def builder = tracer.buildSpan("test")
|
||||||
def scope = (ContinuableScope) builder.startActive(false)
|
def scope = (ContinuableScope) builder.startActive(false)
|
||||||
def span = scope.span()
|
def span = scope.span()
|
||||||
|
scope.setAsyncPropagation(true)
|
||||||
def continuation = scope.capture()
|
def continuation = scope.capture()
|
||||||
scope.close()
|
scope.close()
|
||||||
span.finish()
|
span.finish()
|
||||||
|
@ -313,6 +337,7 @@ class ScopeManagerTest extends Specification {
|
||||||
def "ContinuableScope put in threadLocal after continuation activation"() {
|
def "ContinuableScope put in threadLocal after continuation activation"() {
|
||||||
setup:
|
setup:
|
||||||
ContinuableScope scope = (ContinuableScope) tracer.buildSpan("parent").startActive(true)
|
ContinuableScope scope = (ContinuableScope) tracer.buildSpan("parent").startActive(true)
|
||||||
|
scope.setAsyncPropagation(true)
|
||||||
|
|
||||||
expect:
|
expect:
|
||||||
scopeManager.tlsScope.get() == scope
|
scopeManager.tlsScope.get() == scope
|
||||||
|
|
Loading…
Reference in New Issue