From fc21fc0e276a4385c8e41b64e46f21aca6c457bb Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 22 Jul 2026 14:18:38 +0100 Subject: [PATCH 1/3] Support W3C baggage propagation across various async instrumentation --- .../java/concurrent/AdviceUtils.java | 17 +++- .../java/concurrent/ConcurrentState.java | 28 +++--- .../ExecutorInstrumentationUtils.java | 25 +++-- .../java/concurrent/State.java | 15 +-- .../ListenableFutureInstrumentation.java | 13 +-- .../executor/JavaExecutorInstrumentation.java | 13 +-- .../runnable/ConsumerTaskInstrumentation.java | 11 ++- .../concurrent/CompletableFutureAdvice.java | 11 ++- .../CallbackRunnableInstrumentation.java | 4 +- .../FutureObjectInstrumentation.java | 2 +- .../PromiseObjectInstrumentation.java | 12 +-- .../DefaultPromiseInstrumentation.java | 11 ++- .../FutureObjectInstrumentation.java | 2 +- .../PromiseObjectInstrumentation.java | 11 ++- .../PromiseTransformationInstrumentation.java | 4 +- .../instrumentation/scala/PromiseHelper.java | 92 +++++++------------ .../springamqp/DeliveryInstrumentation.java | 11 ++- 17 files changed, 138 insertions(+), 144 deletions(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/AdviceUtils.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/AdviceUtils.java index 81d6a6abd1f..980ce54a998 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/AdviceUtils.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/AdviceUtils.java @@ -1,8 +1,8 @@ package datadog.trace.bootstrap.instrumentation.java.concurrent; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.isAsyncPropagationEnabled; +import datadog.context.Context; import datadog.context.ContextContinuation; import datadog.context.ContextScope; import datadog.trace.bootstrap.ContextStore; @@ -51,15 +51,24 @@ public static void cancelTask(ContextStore contextStore, final T t } } + public static boolean shouldCapture(Context context) { + if (context == Context.root()) { + return false; + } + AgentSpan span = AgentSpan.fromContext(context); + // propagate contexts with no span or a valid span, when flag is on + return (span == null || span.isValid()) && isAsyncPropagationEnabled(); + } + public static void capture(ContextStore contextStore, T task) { - AgentSpan span = activeSpan(); - if (span != null && span.isValid() && isAsyncPropagationEnabled()) { + Context context = Context.current(); + if (shouldCapture(context)) { State state = contextStore.get(task); if (null == state) { state = State.FACTORY.create(); contextStore.put(task, state); } - state.captureAndSetContinuation(span); + state.captureAndSetContinuation(context); } } } diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ConcurrentState.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ConcurrentState.java index 50113054443..7f426794b5f 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ConcurrentState.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ConcurrentState.java @@ -1,13 +1,12 @@ package datadog.trace.bootstrap.instrumentation.java.concurrent; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.captureSpan; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.isAsyncPropagationEnabled; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static datadog.trace.bootstrap.instrumentation.java.concurrent.ContinuationClaim.CLAIMED; +import datadog.context.Context; import datadog.context.ContextContinuation; import datadog.context.ContextScope; import datadog.trace.bootstrap.ContextStore; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,16 +32,19 @@ public final class ConcurrentState { private ConcurrentState() {} public static ConcurrentState captureContinuation( - ContextStore contextStore, K key, AgentSpan span) { - if (span == null || !span.isValid() || !isAsyncPropagationEnabled()) { + ContextStore contextStore, K key, Context context) { + if (shouldCapture(context)) { + final ConcurrentState state = contextStore.putIfAbsent(key, FACTORY); + if (!state.captureAndSetContinuation(context) && log.isDebugEnabled()) { + log.debug( + "continuation was already set for {} in context {}, no continuation captured.", + key, + context); + } + return state; + } else { return null; } - final ConcurrentState state = contextStore.putIfAbsent(key, FACTORY); - if (!state.captureAndSetContinuation(span) && log.isDebugEnabled()) { - log.debug( - "continuation was already set for {} in span {}, no continuation captured.", key, span); - } - return state; } public static ContextScope activateAndContinueContinuation( @@ -83,10 +85,10 @@ public static void cancelAndClearContinuation( state.cancelAndClearContinuation(); } - private boolean captureAndSetContinuation(final AgentSpan span) { + private boolean captureAndSetContinuation(final Context context) { if (CONTINUATION.compareAndSet(this, null, CLAIMED)) { // lazy write is guaranteed to be seen by getAndSet - CONTINUATION.lazySet(this, captureSpan(span).hold()); + CONTINUATION.lazySet(this, context.capture().hold()); return true; } return false; diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ExecutorInstrumentationUtils.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ExecutorInstrumentationUtils.java index e6fa74b1d70..43ca4fdf7bf 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ExecutorInstrumentationUtils.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/ExecutorInstrumentationUtils.java @@ -1,10 +1,10 @@ package datadog.trace.bootstrap.instrumentation.java.concurrent; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.isAsyncPropagationEnabled; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static datadog.trace.bootstrap.instrumentation.java.concurrent.ExcludeFilter.ExcludeType; +import datadog.context.Context; import datadog.trace.bootstrap.ContextStore; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,38 +17,37 @@ public final class ExecutorInstrumentationUtils { * Checks if given task should get state attached. * * @param task task object - * @param span active span + * @param context active context * @return true iff given task object should be wrapped */ - public static boolean shouldAttachStateToTask(final Object task, final AgentSpan span) { + public static boolean shouldAttachStateToTask(final Object task, final Context context) { if (task == null) { return false; } if (ExcludeFilter.exclude(ExcludeType.EXECUTOR, task)) { return false; } - return span != null && span.isValid() && isAsyncPropagationEnabled(); + return shouldCapture(context); } /** - * Create task state given current span. + * Create task state given current context. * * @param contextStore context storage * @param task task instance - * @param span current span + * @param context current context * @param task class type * @return new state */ public static State setupState( - final ContextStore contextStore, final T task, final AgentSpan span) { - + final ContextStore contextStore, final T task, final Context context) { final State state = contextStore.putIfAbsent(task, State.FACTORY); - - if (!state.captureAndSetContinuation(span)) { + if (!state.captureAndSetContinuation(context)) { log.debug( - "continuation was already set for {} in span {}, no continuation captured.", task, span); + "continuation was already set for {} in context {}, no continuation captured.", + task, + context); } - return state; } diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/State.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/State.java index 122c1f090e0..48cfe9078de 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/State.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/java/concurrent/State.java @@ -1,13 +1,13 @@ package datadog.trace.bootstrap.instrumentation.java.concurrent; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.captureSpan; import static datadog.trace.bootstrap.instrumentation.java.concurrent.ContinuationClaim.CLAIMED; +import datadog.context.Context; import datadog.context.ContextContinuation; import datadog.trace.api.profiling.Timing; import datadog.trace.bootstrap.ContextStore; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; +import javax.annotation.Nullable; public final class State { @@ -26,7 +26,7 @@ public final class State { private State() {} - public boolean captureAndSetContinuation(final AgentSpan span) { + public boolean captureAndSetContinuation(final Context context) { if (CONTINUATION.compareAndSet(this, null, CLAIMED)) { // it's a real pain to do this twice, and this can actually // happen systematically - WITHOUT RACES - because of broken @@ -34,7 +34,7 @@ public boolean captureAndSetContinuation(final AgentSpan span) { // "double instruments" calls to ScheduledExecutorService.submit/schedule // // lazy write is guaranteed to be seen by getAndSet - CONTINUATION.lazySet(this, captureSpan(span)); + CONTINUATION.lazySet(this, context.capture()); return true; } return false; @@ -58,14 +58,15 @@ public void closeContinuation() { } } - public AgentSpan getSpan() { + public Context getContext() { ContextContinuation continuation = CONTINUATION.get(this); if (null == continuation || CLAIMED == continuation) { - return null; + return Context.root(); } - return AgentSpan.fromContext(continuation.context()); + return continuation.context(); } + @Nullable public ContextContinuation getAndResetContinuation() { ContextContinuation continuation = CONTINUATION.get(this); if (null == continuation || CLAIMED == continuation) { diff --git a/dd-java-agent/instrumentation/guava-10.0/src/main/java/datadog/trace/instrumentation/guava10/ListenableFutureInstrumentation.java b/dd-java-agent/instrumentation/guava-10.0/src/main/java/datadog/trace/instrumentation/guava10/ListenableFutureInstrumentation.java index 875c5ba920c..c0fe8e71137 100644 --- a/dd-java-agent/instrumentation/guava-10.0/src/main/java/datadog/trace/instrumentation/guava10/ListenableFutureInstrumentation.java +++ b/dd-java-agent/instrumentation/guava-10.0/src/main/java/datadog/trace/instrumentation/guava10/ListenableFutureInstrumentation.java @@ -1,17 +1,18 @@ package datadog.trace.instrumentation.guava10; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.rootContext; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; import com.google.common.util.concurrent.AbstractFuture; +import datadog.context.Context; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.java.concurrent.ExecutorInstrumentationUtils; import datadog.trace.bootstrap.instrumentation.java.concurrent.RunnableWrapper; import datadog.trace.bootstrap.instrumentation.java.concurrent.State; @@ -55,16 +56,16 @@ public static class AddListenerAdvice { @Advice.OnMethodEnter(suppress = Throwable.class) public static State addListenerEnter( @Advice.Argument(value = 0, readOnly = false) Runnable task) { - final AgentSpan span = activeSpan(); - if (null != span) { + final Context context = currentContext(); + if (context != rootContext()) { final Runnable newTask = RunnableWrapper.wrapIfNeeded(task); // It is important to check potentially wrapped task if we can instrument task in this // executor. Some executors do not support wrapped tasks. - if (ExecutorInstrumentationUtils.shouldAttachStateToTask(newTask, span)) { + if (ExecutorInstrumentationUtils.shouldAttachStateToTask(newTask, context)) { task = newTask; final ContextStore contextStore = InstrumentationContext.get(Runnable.class, State.class); - return ExecutorInstrumentationUtils.setupState(contextStore, newTask, span); + return ExecutorInstrumentationUtils.setupState(contextStore, newTask, context); } } return null; diff --git a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/executor/JavaExecutorInstrumentation.java b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/executor/JavaExecutorInstrumentation.java index efdcda49641..a68277cb1be 100644 --- a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/executor/JavaExecutorInstrumentation.java +++ b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/executor/JavaExecutorInstrumentation.java @@ -1,13 +1,14 @@ package datadog.trace.instrumentation.java.concurrent.executor; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.rootContext; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; +import datadog.context.Context; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.java.concurrent.ExecutorInstrumentationUtils; import datadog.trace.bootstrap.instrumentation.java.concurrent.RunnableWrapper; import datadog.trace.bootstrap.instrumentation.java.concurrent.State; @@ -33,16 +34,16 @@ public static State enterJobSubmit( // there are cased like ScheduledExecutorService.submit (which we instrument) // which calls ScheduledExecutorService.schedule (which we also instrument) // where all of this could be dodged the second time - final AgentSpan span = activeSpan(); - if (null != span) { + final Context context = currentContext(); + if (context != rootContext()) { final Runnable newTask = RunnableWrapper.wrapIfNeeded(task); // It is important to check potentially wrapped task if we can instrument task in this // executor. Some executors do not support wrapped tasks. - if (ExecutorInstrumentationUtils.shouldAttachStateToTask(newTask, span)) { + if (ExecutorInstrumentationUtils.shouldAttachStateToTask(newTask, context)) { task = newTask; final ContextStore contextStore = InstrumentationContext.get(Runnable.class, State.class); - return ExecutorInstrumentationUtils.setupState(contextStore, newTask, span); + return ExecutorInstrumentationUtils.setupState(contextStore, newTask, context); } } return null; diff --git a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/runnable/ConsumerTaskInstrumentation.java b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/runnable/ConsumerTaskInstrumentation.java index f5df4d8923e..5e936a80849 100644 --- a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/runnable/ConsumerTaskInstrumentation.java +++ b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/datadog/trace/instrumentation/java/concurrent/runnable/ConsumerTaskInstrumentation.java @@ -1,19 +1,20 @@ package datadog.trace.instrumentation.java.concurrent.runnable; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.endTaskScope; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.startTaskScope; import static datadog.trace.instrumentation.java.concurrent.ConcurrentInstrumentationNames.EXECUTOR_INSTRUMENTATION_NAME; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import com.google.auto.service.AutoService; +import datadog.context.Context; import datadog.context.ContextScope; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.java.concurrent.State; import java.util.Map; import java.util.concurrent.ForkJoinTask; @@ -51,10 +52,10 @@ public void methodAdvice(MethodTransformer transformer) { public static class Construct { @Advice.OnMethodExit(suppress = Throwable.class) public static void construct(@Advice.This ForkJoinTask task) { - AgentSpan span = activeSpan(); - if (null != span) { + Context context = currentContext(); + if (shouldCapture(context)) { State state = State.FACTORY.create(); - state.captureAndSetContinuation(span); + state.captureAndSetContinuation(context); InstrumentationContext.get(ForkJoinTask.class, State.class).put(task, state); } } diff --git a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/java/util/concurrent/CompletableFutureAdvice.java b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/java/util/concurrent/CompletableFutureAdvice.java index cc1e0deecb5..2f1ef4bd5b2 100644 --- a/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/java/util/concurrent/CompletableFutureAdvice.java +++ b/dd-java-agent/instrumentation/java/java-concurrent/java-concurrent-1.8/src/main/java/java/util/concurrent/CompletableFutureAdvice.java @@ -1,12 +1,13 @@ package java.util.concurrent; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.rootContext; import static java.util.concurrent.CompletableFuture.ASYNC; +import datadog.context.Context; import datadog.context.ContextScope; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.java.concurrent.ConcurrentState; import java.util.concurrent.CompletableFuture.UniCompletion; import net.bytebuddy.asm.Advice; @@ -17,11 +18,11 @@ public final class CompletableFutureAdvice { public static final class UniConstructor { @Advice.OnMethodExit(suppress = Throwable.class) public static void afterInit(@Advice.This UniCompletion zis) { - AgentSpan span = activeSpan(); - if (zis.isLive() && span != null) { + Context context = currentContext(); + if (zis.isLive() && context != rootContext()) { ContextStore contextStore = InstrumentationContext.get(UniCompletion.class, ConcurrentState.class); - ConcurrentState.captureContinuation(contextStore, zis, span); + ConcurrentState.captureContinuation(contextStore, zis, context); } } diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/CallbackRunnableInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/CallbackRunnableInstrumentation.java index 177a5e65bbc..78038465abe 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/CallbackRunnableInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/CallbackRunnableInstrumentation.java @@ -44,7 +44,7 @@ public static void onConstruct(@Advice.This CallbackRunnable task) { public static final class Run { @Advice.OnMethodEnter public static ContextScope before(@Advice.This CallbackRunnable task) { - return PromiseHelper.runActivateSpan( + return PromiseHelper.runWithContext( InstrumentationContext.get(CallbackRunnable.class, State.class).get(task)); } @@ -64,7 +64,7 @@ public static void beforeExecute( State state = contextStore.get(task); if (PromiseHelper.completionPriority) { state = - PromiseHelper.executeCaptureSpan( + PromiseHelper.executeCaptureContext( InstrumentationContext.get(Try.class, Context.class), resolved, contextStore, diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/FutureObjectInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/FutureObjectInstrumentation.java index 81dfed4392a..97034cddac0 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/FutureObjectInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/FutureObjectInstrumentation.java @@ -44,7 +44,7 @@ public static void afterInit() { lookup.findVirtual(Future$.class, "unit", MethodType.methodType(Future.class)); Future unit = (Future) mh.invoke(Future$.MODULE$); Try result = unit.value().get(); - InstrumentationContext.get(Try.class, Context.class).put(result, null); + InstrumentationContext.get(Try.class, Context.class).remove(result); } catch (Throwable ignored) { } } diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/PromiseObjectInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/PromiseObjectInstrumentation.java index d29f7075db3..28cd365ad9e 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/PromiseObjectInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.10/src/main/java/datadog/trace/instrumentation/scala210/concurrent/PromiseObjectInstrumentation.java @@ -1,14 +1,14 @@ package datadog.trace.instrumentation.scala210.concurrent; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; -import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.spanFromContext; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import datadog.context.Context; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.scala.PromiseHelper; import net.bytebuddy.asm.Advice; import scala.concurrent.impl.CallbackRunnable; @@ -38,14 +38,14 @@ public void methodAdvice(MethodTransformer transformer) { public static final class ResolveTry { @Advice.OnMethodExit(suppress = Throwable.class) public static void afterResolve(@Advice.Return(readOnly = false) Try resolved) { - AgentSpan span = PromiseHelper.getSpan(); - if (null != span) { + Context context = currentContext(); + if (shouldCapture(context)) { ContextStore contextStore = InstrumentationContext.get(Try.class, Context.class); final Context existing = contextStore.get(resolved); - Try next = PromiseHelper.getTry(resolved, span, spanFromContext(existing)); + Try next = PromiseHelper.getTry(resolved, context, existing); if (next != resolved) { - contextStore.put(next, span); + contextStore.put(next, context); resolved = next; } } diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/DefaultPromiseInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/DefaultPromiseInstrumentation.java index 8f8b98bb6cc..4af9504adc5 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/DefaultPromiseInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/DefaultPromiseInstrumentation.java @@ -1,6 +1,8 @@ package datadog.trace.instrumentation.scala213.concurrent; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static scala.concurrent.impl.Promise.Transformation; @@ -8,7 +10,6 @@ import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.scala.PromiseHelper; import net.bytebuddy.asm.Advice; import scala.util.Try; @@ -42,15 +43,15 @@ public static void beforeTryComplete( if (state instanceof Try) { return; } - AgentSpan span = PromiseHelper.getSpan(); - if (null != span) { + Context context = currentContext(); + if (shouldCapture(context)) { ContextStore contextStore = InstrumentationContext.get(Try.class, Context.class); Context existing = contextStore.get(resolved); if (existing == null) { - Try next = PromiseHelper.getTry(resolved, span, null); + Try next = PromiseHelper.getTry(resolved, context, null); if (next != resolved) { - contextStore.put(next, span); + contextStore.put(next, context); resolved = next; } } diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/FutureObjectInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/FutureObjectInstrumentation.java index 7c33a738382..a0de0cc8890 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/FutureObjectInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/FutureObjectInstrumentation.java @@ -34,7 +34,7 @@ public static final class ClassInit { @Advice.OnMethodExit(suppress = Throwable.class) public static void afterInit() { Try result = Future$.MODULE$.unit().value().get(); - InstrumentationContext.get(Try.class, Context.class).put(result, null); + InstrumentationContext.get(Try.class, Context.class).remove(result); } /** Promise.Transformation was introduced in scala 2.13 */ diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseObjectInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseObjectInstrumentation.java index 84a4e6d0bdd..d8a17eb04dd 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseObjectInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseObjectInstrumentation.java @@ -1,6 +1,8 @@ package datadog.trace.instrumentation.scala213.concurrent; import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static scala.concurrent.impl.Promise.Transformation; @@ -8,7 +10,6 @@ import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.instrumentation.scala.PromiseHelper; import net.bytebuddy.asm.Advice; import scala.util.Try; @@ -37,14 +38,14 @@ public void methodAdvice(MethodTransformer transformer) { public static final class Resolve { @Advice.OnMethodExit(suppress = Throwable.class) public static void afterResolve(@Advice.Return(readOnly = false) Try resolved) { - AgentSpan span = PromiseHelper.getSpan(); - if (null != span) { + Context context = currentContext(); + if (shouldCapture(context)) { ContextStore contextStore = InstrumentationContext.get(Try.class, Context.class); Context existing = contextStore.get(resolved); - Try next = PromiseHelper.getTry(resolved, span, AgentSpan.fromContext(existing)); + Try next = PromiseHelper.getTry(resolved, context, existing); if (next != resolved) { - contextStore.put(next, span); + contextStore.put(next, context); resolved = next; } } diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseTransformationInstrumentation.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseTransformationInstrumentation.java index 1d45b284b25..e57eb714a05 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseTransformationInstrumentation.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-2.13/src/main/java/datadog/trace/instrumentation/scala213/concurrent/PromiseTransformationInstrumentation.java @@ -51,7 +51,7 @@ public static void onConstruct( public static final class Run { @Advice.OnMethodEnter public static ContextScope before(@Advice.This Transformation task) { - return PromiseHelper.runActivateSpan( + return PromiseHelper.runWithContext( InstrumentationContext.get(Transformation.class, State.class).get(task)); } @@ -81,7 +81,7 @@ public static void beforeExecute( State state = contextStore.get(task); if (PromiseHelper.completionPriority) { state = - PromiseHelper.executeCaptureSpan( + PromiseHelper.executeCaptureContext( InstrumentationContext.get(Try.class, Context.class), resolved, contextStore, diff --git a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-common/src/main/java/datadog/trace/instrumentation/scala/PromiseHelper.java b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-common/src/main/java/datadog/trace/instrumentation/scala/PromiseHelper.java index 690771cbd76..b3e6b27d7ac 100644 --- a/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-common/src/main/java/datadog/trace/instrumentation/scala/PromiseHelper.java +++ b/dd-java-agent/instrumentation/scala/scala-promise/scala-promise-common/src/main/java/datadog/trace/instrumentation/scala/PromiseHelper.java @@ -1,15 +1,10 @@ package datadog.trace.instrumentation.scala; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.captureSpan; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.isAsyncPropagationEnabled; - import datadog.context.Context; import datadog.context.ContextContinuation; import datadog.context.ContextScope; import datadog.trace.api.InstrumenterConfig; import datadog.trace.bootstrap.ContextStore; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils; import datadog.trace.bootstrap.instrumentation.java.concurrent.State; import java.util.Collections; @@ -24,36 +19,22 @@ public class PromiseHelper { Collections.singletonList("scala_promise_completion_priority"), false); /** - * Get the {@code Span} that should be associated with the {@code Try} completing this {@code - * Promise}. - * - * @return the Span or null - */ - public static AgentSpan getSpan() { - final AgentSpan span = activeSpan(); - if (null != span && span.isValid() && isAsyncPropagationEnabled()) { - return span; - } - return null; - } - - /** - * Get the {@code Try} that should be associated with the {@code Span}. Will create a new copy of - * the {@code Try} if the existing one already has a different {@code Span} associated. + * Get the {@code Try} that should be associated with the {@code Context}. Will create a new copy + * of the {@code Try} if the existing one already has a different {@code Context} associated. * * @param resolved the current Try - * @param span the current Span - * @param existing the currently stored Span for the Try - * @return the Try that should be associated with the Span + * @param context the current context + * @param existing the currently stored context for the Try + * @return the Try that should be associated with the context */ public static Try getTry( - final Try resolved, final AgentSpan span, final AgentSpan existing) { - // Check if the new Span is the same as the currently stored one - if (existing == span) { + final Try resolved, final Context context, final Context existing) { + // Check if the new context is the same as the currently stored one + if (existing == context) { return resolved; } - // Otherwise we need to create a new Try to associate the Span with + // Otherwise we need to create a new Try to associate the context with if (resolved instanceof Success) { Success success = (Success) resolved; return new Success<>(success.value()); @@ -71,25 +52,22 @@ public static Try getTry( * @param state the State related to the task becoming active. * @return the active ContextScope */ - public static ContextScope runActivateSpan(State state) { + public static ContextScope runWithContext(State state) { if (state == null) { return null; } - AgentSpan capturedSpan = state.getSpan(); - if (capturedSpan != null) { - AgentSpan activeSpan = activeSpan(); - if (capturedSpan != activeSpan) { - return AdviceUtils.startTaskScope(state); - } else { - state.closeContinuation(); - } + Context context = state.getContext(); + if (context != Context.root() && context != Context.current()) { + return AdviceUtils.startTaskScope(state); + } else { + state.closeContinuation(); } return null; } /** - * Transfer and capture the {@code Span} from the {@code Try} to the task, and store or swap out - * the existing {@code Continuation} if any. + * Transfer and capture the {@code Context} from the {@code Try} to the task, and store or swap + * out the existing {@code Continuation} if any. * * @param tryStore the ContextStore for the Try * @param resolved the Try in question @@ -98,30 +76,28 @@ public static ContextScope runActivateSpan(State state) { * @param state the current State associated with the task * @return the current or updated state */ - public static State executeCaptureSpan( + public static State executeCaptureContext( ContextStore tryStore, Try resolved, ContextStore taskStore, K task, State state) { - final AgentSpan span = AgentSpan.fromContext(tryStore.get(resolved)); - if (span != null) { - // Check if the new Span is the same as the currently stored one - if (null != state && state.getSpan() == span) { - return state; - } - ContextContinuation continuation = captureSpan(span); - ContextContinuation existing = null; - if (null != state) { - existing = state.getAndResetContinuation(); - } else { - state = State.FACTORY.create(); - taskStore.put(task, state); - } - state.setOrCancelContinuation(continuation); - if (null != existing) { - existing.release(); - } + final Context context = tryStore.get(resolved); + // Check if there's no new context, or it's the same as the stored one + if (null == context || (null != state && state.getContext() == context)) { + return state; + } + ContextContinuation continuation = context.capture(); + ContextContinuation existing = null; + if (null != state) { + existing = state.getAndResetContinuation(); + } else { + state = State.FACTORY.create(); + taskStore.put(task, state); + } + state.setOrCancelContinuation(continuation); + if (null != existing) { + existing.release(); } return state; } diff --git a/dd-java-agent/instrumentation/spring/spring-rabbit-1.5/src/main/java/datadog/trace/instrumentation/springamqp/DeliveryInstrumentation.java b/dd-java-agent/instrumentation/spring/spring-rabbit-1.5/src/main/java/datadog/trace/instrumentation/springamqp/DeliveryInstrumentation.java index 930ad52599e..3169c6dea4b 100644 --- a/dd-java-agent/instrumentation/spring/spring-rabbit-1.5/src/main/java/datadog/trace/instrumentation/springamqp/DeliveryInstrumentation.java +++ b/dd-java-agent/instrumentation/spring/spring-rabbit-1.5/src/main/java/datadog/trace/instrumentation/springamqp/DeliveryInstrumentation.java @@ -1,14 +1,15 @@ package datadog.trace.instrumentation.springamqp; -import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; +import static datadog.trace.bootstrap.instrumentation.api.Java8BytecodeBridge.currentContext; +import static datadog.trace.bootstrap.instrumentation.java.concurrent.AdviceUtils.shouldCapture; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; import com.google.auto.service.AutoService; +import datadog.context.Context; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; import datadog.trace.bootstrap.InstrumentationContext; -import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import datadog.trace.bootstrap.instrumentation.java.concurrent.State; import java.util.Map; import net.bytebuddy.asm.Advice; @@ -39,10 +40,10 @@ public Map contextStore() { public static class CaptureActiveScope { @Advice.OnMethodExit public static void captureActiveScope(@Advice.This Delivery delivery) { - AgentSpan span = activeSpan(); - if (span != null) { + Context context = currentContext(); + if (shouldCapture(context)) { State state = State.FACTORY.create(); - state.captureAndSetContinuation(span); + state.captureAndSetContinuation(context); InstrumentationContext.get(Delivery.class, State.class).put(delivery, state); } } From f26ec3327b7c735ab173d4cae40930054309a452 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 22 Jul 2026 17:00:25 +0100 Subject: [PATCH 2/3] Add regression test for W3C baggage over slick async --- .../scala/SlickBaggagePropagationTest.scala | 53 +++++++++++++++++++ .../slick-3.2/src/test/scala/SlickUtils.scala | 8 +++ 2 files changed, 61 insertions(+) create mode 100644 dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickBaggagePropagationTest.scala diff --git a/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickBaggagePropagationTest.scala b/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickBaggagePropagationTest.scala new file mode 100644 index 00000000000..ffeb51f0563 --- /dev/null +++ b/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickBaggagePropagationTest.scala @@ -0,0 +1,53 @@ +import datadog.context.Context +import datadog.trace.agent.test.AbstractInstrumentationTest +import datadog.trace.bootstrap.instrumentation.api.Baggage +import org.junit.jupiter.api.Assertions.{assertEquals, assertNotNull, assertTrue} +import org.junit.jupiter.api.Test + +import java.util.Collections +import java.util.concurrent.atomic.AtomicReference +import java.util.concurrent.{CountDownLatch, TimeUnit} + +/** Regression test for https://github.com/DataDog/dd-trace-java/issues/11758. + * + * SlickRunnableInstrumentation's Construct advice calls AdviceUtils.capture(), which reads only + * activeSpan() and bails out entirely when there is no active span - it never looks at the rest of + * the Context. So baggage attached without an active Datadog span (e.g. OTel baggage set + * independently of a local span) is silently dropped when the Runnable resumes on a Slick + * AsyncExecutor thread, instead of being carried across like the rest of the Context. + */ +class SlickBaggagePropagationTest extends AbstractInstrumentationTest { + + @Test + def baggagePropagatesAcrossAsyncExecutorHandoff(): Unit = { + val database = new SlickUtils(AbstractInstrumentationTest.writer) + + val baggage = Baggage.create(Collections.singletonMap("user.id", "abc123")) + val capturedBaggage = new AtomicReference[Baggage]() + val taskRan = new CountDownLatch(1) + + // Baggage attached with no active span - AdviceUtils.capture() bails out as soon as + // activeSpan() is null, so it never even looks at the rest of the Context. + val baggageScope = Context.current().`with`(baggage).attach() + try { + database.runOnAsyncExecutor(new Runnable { + override def run(): Unit = { + capturedBaggage.set(Baggage.fromContext(Context.current())) + taskRan.countDown() + } + }) + } finally { + baggageScope.close() + } + + assertTrue(taskRan.await(10, TimeUnit.SECONDS), "task did not run on the AsyncExecutor") + + val propagated = capturedBaggage.get() + assertNotNull( + propagated, + "baggage must survive the hand-off onto the Slick AsyncExecutor thread; null means" + + " SlickRunnableInstrumentation only captured the span, dropping the rest of the Context" + ) + assertEquals("abc123", propagated.asMap().get("user.id")) + } +} diff --git a/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickUtils.scala b/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickUtils.scala index c1f05aeef57..42febdf5bf5 100644 --- a/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickUtils.scala +++ b/dd-java-agent/instrumentation/slick-3.2/src/test/scala/SlickUtils.scala @@ -53,6 +53,14 @@ class SlickUtils(TEST_WRITER: ListWriter) { Await.result(future, Duration.Inf).head } + /** Runs the given task directly on the database's Slick {@code AsyncExecutor}, the same thread + * pool used to run query actions. This exercises {@code SlickRunnableInstrumentation} without + * requiring a full query round-trip. + */ + def runOnAsyncExecutor(task: Runnable): Unit = { + database.executor.executionContext.execute(task) + } + } object SlickUtils { From 12ef672694ec6f6a017754720d26c2c50d2220a1 Mon Sep 17 00:00:00 2001 From: Stuart McCulloch Date: Wed, 22 Jul 2026 15:42:33 +0100 Subject: [PATCH 3/3] Install appropriate context manager when building native images --- .../src/main/java/datadog/trace/bootstrap/Agent.java | 4 ++-- .../trace/agent/tooling/nativeimage/TracerActivation.java | 2 -- .../NativeImageGeneratorRunnerInstrumentation.java | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java index 555e027d498..110fc9afc57 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/Agent.java @@ -234,6 +234,8 @@ public static void start( createAgentClassloader(agentJarURL); + AgentTracer.maybeInstallLegacyContextManager(); + if (Platform.isNativeImageBuilder()) { // these default services are not used during native-image builds remoteConfigEnabled = false; @@ -338,8 +340,6 @@ public static void start( StaticEventLogger.end("crashtracking"); } - AgentTracer.maybeInstallLegacyContextManager(); - startDatadogAgent(initTelemetry, inst); final EnumSet libraries = detectLibraries(log); diff --git a/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/nativeimage/TracerActivation.java b/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/nativeimage/TracerActivation.java index 682ceb9115e..e6ff1031faa 100644 --- a/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/nativeimage/TracerActivation.java +++ b/dd-java-agent/agent-installer/src/main/java/datadog/trace/agent/tooling/nativeimage/TracerActivation.java @@ -8,7 +8,6 @@ import datadog.trace.agent.tooling.MeterInstaller; import datadog.trace.agent.tooling.ProfilerInstaller; import datadog.trace.agent.tooling.TracerInstaller; -import datadog.trace.bootstrap.instrumentation.api.AgentTracer; import datadog.trace.bootstrap.instrumentation.api.ProfilingContextIntegration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +18,6 @@ public final class TracerActivation { public static void activate() { try { - AgentTracer.maybeInstallLegacyContextManager(); // Initialize meter MeterInstaller.installMeter(); // Initialize tracer diff --git a/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java b/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java index 8ab84d9b8af..22376f649eb 100644 --- a/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java +++ b/dd-java-agent/instrumentation/graal/graal-native-image-20.0/src/main/java/datadog/trace/instrumentation/graal/nativeimage/NativeImageGeneratorRunnerInstrumentation.java @@ -69,6 +69,8 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "com.datadoghq.profiler.BufferWriter:run_time," + "com.datadoghq.profiler.BufferWriter8:run_time," + "com.datadoghq.profiler.BufferWriter9:run_time," + + "datadog.context.ContextKey:build_time," + + "datadog.context.ContextProviders$ProvidedManager:build_time," + "datadog.environment.JavaVirtualMachine:rerun," + "datadog.environment.OperatingSystem:rerun," + "datadog.environment.OperatingSystem$Architecture:rerun," @@ -134,6 +136,8 @@ public static void onEnter(@Advice.Argument(value = 0, readOnly = false) String[ + "datadog.trace.bootstrap.benchmark.StaticEventLogger:build_time," + "datadog.trace.bootstrap.blocking.BlockingExceptionHandler:build_time," + "datadog.trace.bootstrap.InstrumentationErrors:build_time," + + "datadog.trace.bootstrap.instrumentation.api.AgentTracer$LegacyContextManager:build_time," + + "datadog.trace.bootstrap.instrumentation.api.InternalContextKeys:build_time," + "datadog.trace.bootstrap.instrumentation.java.concurrent.AsyncResultExtensions$CompletableAsyncResultExtension:build_time," + "datadog.trace.bootstrap.instrumentation.java.concurrent.AsyncResultExtensions$1:build_time," + "datadog.trace.bootstrap.instrumentation.java.concurrent.AsyncResultExtensions:build_time,"