Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package datadog.trace.agent.tooling;

/** Carries advice and target context for a failed advice transformation. */
final class AdviceTransformationException extends RuntimeException {
private final String instrumentationClass;
private final String adviceClass;
private final String targetClass;
private final String targetMethod;

AdviceTransformationException(
String instrumentationClass,
String adviceClass,
String targetClass,
String targetMethod,
Throwable cause) {
super("Advice transformation failed for " + targetClass + '.' + targetMethod, cause);
this.instrumentationClass = instrumentationClass;
this.adviceClass = adviceClass;
this.targetClass = targetClass;
this.targetMethod = targetMethod;
}

String getInstrumentationClass() {
return instrumentationClass;
}

String getAdviceClass() {
return adviceClass;
}

String getTargetClass() {
return targetClass;
}

String getTargetMethod() {
return targetMethod;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import datadog.trace.api.InstrumenterConfig;
import datadog.trace.api.Platform;
import datadog.trace.api.ProductActivation;
import datadog.trace.api.internal.VisibleForTesting;
import datadog.trace.api.telemetry.IntegrationsCollector;
import datadog.trace.bootstrap.FieldBackedContextAccessor;
import datadog.trace.bootstrap.instrumentation.java.concurrent.ExcludeFilter;
Expand Down Expand Up @@ -111,6 +112,17 @@ public static ClassFileTransformer installBytebuddyAgent(
final boolean skipAdditionalLibraryMatcher,
final Set<InstrumenterModule.TargetSystem> enabledSystems,
final AgentBuilder.Listener... listeners) {
return installBytebuddyAgent(
inst, skipAdditionalLibraryMatcher, enabledSystems, DEBUG, listeners);
}

@VisibleForTesting
public static ClassFileTransformer installBytebuddyAgent(
final Instrumentation inst,
final boolean skipAdditionalLibraryMatcher,
final Set<InstrumenterModule.TargetSystem> enabledSystems,
final boolean adviceTransformationDiagnosticsEnabled,
final AgentBuilder.Listener... listeners) {
Utils.setInstrumentation(inst);

TypePoolFacade.registerAsSupplier();
Expand Down Expand Up @@ -216,7 +228,11 @@ public static ClassFileTransformer installBytebuddyAgent(
}

CombiningTransformerBuilder transformerBuilder =
new CombiningTransformerBuilder(agentBuilder, instrumenterIndex, enabledSystems);
new CombiningTransformerBuilder(
agentBuilder,
instrumenterIndex,
enabledSystems,
adviceTransformationDiagnosticsEnabled);

int installedCount = 0;
for (InstrumenterModule module : instrumenterModules) {
Expand Down Expand Up @@ -429,11 +445,44 @@ public void onError(
final boolean loaded,
final Throwable throwable) {
if (DEBUG) {
log.debug(
"Transformation failed - instrumentation.target.class={} instrumentation.target.classloader={}",
typeName,
classLoader,
throwable);
if (throwable instanceof AdviceTransformationException) {
AdviceTransformationException failure = (AdviceTransformationException) throwable;
try {
InstrumenterFlare.recordTransformationError(
"instrumentation.class="
+ failure.getInstrumentationClass()
+ " advice.class="
+ failure.getAdviceClass()
+ " instrumentation.target.class="
+ failure.getTargetClass()
+ " instrumentation.target.method="
+ failure.getTargetMethod()
+ " instrumentation.target.loaded="
+ loaded
+ " instrumentation.target.classloader="
+ classLoader
+ " error="
+ failure.getCause());
} catch (RuntimeException ignored) {
// Flare collection must not interfere with transformation failure reporting.
}
log.debug(
"Advice transformation failed - instrumentation.class={} advice.class={} instrumentation.target.class={} instrumentation.target.method={} instrumentation.target.loaded={} instrumentation.target.classloader={}",
failure.getInstrumentationClass(),
failure.getAdviceClass(),
failure.getTargetClass(),
failure.getTargetMethod(),
loaded,
classLoader,
failure.getCause());
} else {
log.debug(
"Transformation failed - instrumentation.target.class={} instrumentation.target.loaded={} instrumentation.target.classloader={}",
typeName,
loaded,
classLoader,
throwable);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public final class CombiningTransformerBuilder
private final InstrumenterIndex instrumenterIndex;
private final int knownTransformationCount;
private final Set<InstrumenterModule.TargetSystem> enabledSystems;
private final boolean adviceTransformationDiagnosticsEnabled;

private final List<MatchRecorder> matchers = new ArrayList<>();
private final BitSet knownTypesMask;
Expand All @@ -81,14 +82,16 @@ public final class CombiningTransformerBuilder
private HelperTransformer helperTransformer;
private Advice.PostProcessor.Factory postProcessor;
private MuzzleCheck muzzle;
private String instrumentationClass;

// temporary buffer for collecting advice; reset for each instrumenter
private final List<AgentBuilder.Transformer> advice = new ArrayList<>();

public CombiningTransformerBuilder(
AgentBuilder agentBuilder,
InstrumenterIndex instrumenterIndex,
Set<InstrumenterModule.TargetSystem> enabledSystems) {
Set<InstrumenterModule.TargetSystem> enabledSystems,
boolean adviceTransformationDiagnosticsEnabled) {
this.agentBuilder = agentBuilder;
this.instrumenterIndex = instrumenterIndex;
int knownInstrumentationCount = instrumenterIndex.instrumentationCount();
Expand All @@ -98,6 +101,7 @@ public CombiningTransformerBuilder(
this.nextRuntimeInstrumentationId = knownInstrumentationCount;
this.nextRuntimeTransformationId = knownTransformationCount;
this.enabledSystems = enabledSystems;
this.adviceTransformationDiagnosticsEnabled = adviceTransformationDiagnosticsEnabled;
}

/** Builds matchers and transformers for an instrumentation module and its members. */
Expand Down Expand Up @@ -151,6 +155,9 @@ private void prepareInstrumentation(InstrumenterModule module, int instrumentati
/** Builds a type-specific transformer, controlled by one or more matchers. */
private void buildTypeInstrumentation(Instrumenter member) {

instrumentationClass =
adviceTransformationDiagnosticsEnabled ? member.getClass().getName() : null;

int transformationId = instrumenterIndex.transformationId(member);
if (transformationId < 0) {
// this is a non-indexed transformation configured at runtime, e.g. "dd.trace.methods"
Expand Down Expand Up @@ -273,7 +280,11 @@ private void addAdviceIfEnabled(
customMapping = customMapping.with(postProcessor);
}
AgentBuilder.Transformer.ForAdvice forAdvice =
new AgentBuilder.Transformer.ForAdvice(customMapping)
adviceTransformationDiagnosticsEnabled
? new DebuggingAdviceTransformer(customMapping, instrumentationClass, adviceClass)
: new AgentBuilder.Transformer.ForAdvice(customMapping);
forAdvice =
forAdvice
.withExceptionHandler(ExceptionHandlers.exceptionHandlerFor(adviceClass))
.include(Utils.getBootstrapProxy());
ClassLoader adviceLoader = Utils.getExtendedClassLoader();
Expand Down
Loading