SafeHasSuperTypeMatcher: handle exceptions when getting class erasure
This commit is contained in:
parent
a7c63b9261
commit
36ec5d51e5
|
@ -1,7 +1,5 @@
|
||||||
package datadog.trace.agent.tooling;
|
package datadog.trace.agent.tooling;
|
||||||
|
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.erasure;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -32,7 +30,7 @@ public class ByteBuddyElementMatchers {
|
||||||
*/
|
*/
|
||||||
public static <T extends TypeDescription> ElementMatcher.Junction<T> safeHasSuperType(
|
public static <T extends TypeDescription> ElementMatcher.Junction<T> safeHasSuperType(
|
||||||
final ElementMatcher<? super TypeDescription> matcher) {
|
final ElementMatcher<? super TypeDescription> matcher) {
|
||||||
return safeHasGenericSuperType(erasure(matcher));
|
return safeHasGenericSuperType(new SafeErasureMatcher(matcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,6 +48,29 @@ public class ByteBuddyElementMatchers {
|
||||||
return new SafeHasSuperTypeMatcher<>(matcher);
|
return new SafeHasSuperTypeMatcher<>(matcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps another matcher to assure that an element is not matched in case that the matching causes
|
||||||
|
* an {@link Exception}. Logs exception if it happens.
|
||||||
|
*
|
||||||
|
* @param matcher The element matcher that potentially throws an exception.
|
||||||
|
* @param <T> The type of the matched object.
|
||||||
|
* @return A matcher that returns {@code false} in case that the given matcher throws an
|
||||||
|
* exception.
|
||||||
|
*/
|
||||||
|
public static <T> ElementMatcher.Junction<T> failSafe(
|
||||||
|
final ElementMatcher<? super T> matcher, final String description) {
|
||||||
|
return new SafeMatcher<>(matcher, false, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TypeDescription safeAsErasure(final TypeDefinition target) {
|
||||||
|
try {
|
||||||
|
return target.asErasure();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.debug("Exception trying to get interfaces:", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An element matcher that matches a super type. This is different from {@link
|
* An element matcher that matches a super type. This is different from {@link
|
||||||
* net.bytebuddy.matcher.HasSuperTypeMatcher} in the following way:
|
* net.bytebuddy.matcher.HasSuperTypeMatcher} in the following way:
|
||||||
|
@ -119,10 +140,13 @@ public class ByteBuddyElementMatchers {
|
||||||
private boolean hasInterface(
|
private boolean hasInterface(
|
||||||
final TypeDefinition typeDefinition, final Set<TypeDescription> checkedInterfaces) {
|
final TypeDefinition typeDefinition, final Set<TypeDescription> checkedInterfaces) {
|
||||||
for (final TypeDefinition interfaceType : safeGetInterfaces(typeDefinition)) {
|
for (final TypeDefinition interfaceType : safeGetInterfaces(typeDefinition)) {
|
||||||
if (checkedInterfaces.add(interfaceType.asErasure())
|
final TypeDescription erasure = safeAsErasure(interfaceType);
|
||||||
&& (matcher.matches(interfaceType.asGenericType())
|
if (erasure != null) {
|
||||||
|| hasInterface(interfaceType, checkedInterfaces))) {
|
if (checkedInterfaces.add(interfaceType.asErasure())
|
||||||
return true;
|
&& (matcher.matches(interfaceType.asGenericType())
|
||||||
|
|| hasInterface(interfaceType, checkedInterfaces))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -153,4 +177,98 @@ public class ByteBuddyElementMatchers {
|
||||||
return "safeHasSuperType(" + matcher + ")";
|
return "safeHasSuperType(" + matcher + ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An element matcher that matches its argument's {@link TypeDescription.Generic} raw type against
|
||||||
|
* the given matcher for a {@link TypeDescription}. As a wildcard does not define an erasure, a
|
||||||
|
* runtime exception is thrown when this matcher is applied to a wildcard.
|
||||||
|
*
|
||||||
|
* <p>Catches and logs exception if it was thrown when getting erasure, returning false.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the matched entity.
|
||||||
|
* @see net.bytebuddy.matcher.ErasureMatcher
|
||||||
|
*/
|
||||||
|
@HashCodeAndEqualsPlugin.Enhance
|
||||||
|
public static class SafeErasureMatcher<T extends TypeDefinition>
|
||||||
|
extends ElementMatcher.Junction.AbstractBase<T> {
|
||||||
|
|
||||||
|
/** The matcher to apply to the raw type of the matched element. */
|
||||||
|
private final ElementMatcher<? super TypeDescription> matcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new erasure matcher.
|
||||||
|
*
|
||||||
|
* @param matcher The matcher to apply to the raw type.
|
||||||
|
*/
|
||||||
|
public SafeErasureMatcher(final ElementMatcher<? super TypeDescription> matcher) {
|
||||||
|
this.matcher = matcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(final T target) {
|
||||||
|
final TypeDescription erasure = safeAsErasure(target);
|
||||||
|
if (erasure == null) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// We would like matcher exceptions to propagate
|
||||||
|
return matcher.matches(erasure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "safeErasure(" + matcher + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A fail-safe matcher catches exceptions that are thrown by a delegate matcher and returns an
|
||||||
|
* alternative value.
|
||||||
|
*
|
||||||
|
* <p>Logs exception if it was thrown.
|
||||||
|
*
|
||||||
|
* @param <T> The type of the matched entity.
|
||||||
|
* @see net.bytebuddy.matcher.FailSafeMatcher
|
||||||
|
*/
|
||||||
|
@HashCodeAndEqualsPlugin.Enhance
|
||||||
|
public static class SafeMatcher<T> extends ElementMatcher.Junction.AbstractBase<T> {
|
||||||
|
|
||||||
|
/** The delegate matcher that might throw an exception. */
|
||||||
|
private final ElementMatcher<? super T> matcher;
|
||||||
|
|
||||||
|
/** The fallback value in case of an exception. */
|
||||||
|
private final boolean fallback;
|
||||||
|
|
||||||
|
/** The text description to log if exception happens. */
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new fail-safe element matcher.
|
||||||
|
*
|
||||||
|
* @param matcher The delegate matcher that might throw an exception.
|
||||||
|
* @param fallback The fallback value in case of an exception.
|
||||||
|
* @param description Descriptive string to log along with exception.
|
||||||
|
*/
|
||||||
|
public SafeMatcher(
|
||||||
|
final ElementMatcher<? super T> matcher, final boolean fallback, final String description) {
|
||||||
|
this.matcher = matcher;
|
||||||
|
this.fallback = fallback;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(final T target) {
|
||||||
|
try {
|
||||||
|
return matcher.matches(target);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.debug(description, e);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "safeMatcher(try(" + matcher + ") or " + fallback + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package datadog.trace.agent.tooling;
|
package datadog.trace.agent.tooling;
|
||||||
|
|
||||||
|
import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.failSafe;
|
||||||
import static datadog.trace.agent.tooling.Utils.getConfigEnabled;
|
import static datadog.trace.agent.tooling.Utils.getConfigEnabled;
|
||||||
import static net.bytebuddy.matcher.ElementMatchers.any;
|
import static net.bytebuddy.matcher.ElementMatchers.any;
|
||||||
|
|
||||||
|
@ -80,7 +81,14 @@ public interface Instrumenter {
|
||||||
|
|
||||||
AgentBuilder.Identified.Extendable agentBuilder =
|
AgentBuilder.Identified.Extendable agentBuilder =
|
||||||
parentAgentBuilder
|
parentAgentBuilder
|
||||||
.type(safeTypeMatcher(typeMatcher()), classLoaderMatcher())
|
.type(
|
||||||
|
failSafe(
|
||||||
|
typeMatcher(),
|
||||||
|
"Instrumentation type matcher unexpected exception: " + getClass().getName()),
|
||||||
|
failSafe(
|
||||||
|
classLoaderMatcher(),
|
||||||
|
"Instrumentation class loader matcher unexpected exception: "
|
||||||
|
+ getClass().getName()))
|
||||||
.and(new MuzzleMatcher())
|
.and(new MuzzleMatcher())
|
||||||
.transform(DDTransformers.defaultTransformers());
|
.transform(DDTransformers.defaultTransformers());
|
||||||
agentBuilder = injectHelperClasses(agentBuilder);
|
agentBuilder = injectHelperClasses(agentBuilder);
|
||||||
|
@ -88,23 +96,6 @@ public interface Instrumenter {
|
||||||
return agentBuilder.asDecorator();
|
return agentBuilder.asDecorator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Wrap an ElementMatcher in a try-catch exception and log any exceptions. */
|
|
||||||
private ElementMatcher<? super TypeDescription> safeTypeMatcher(
|
|
||||||
final ElementMatcher<? super TypeDescription> instrumentationMatcher) {
|
|
||||||
return new ElementMatcher<TypeDescription>() {
|
|
||||||
@Override
|
|
||||||
public boolean matches(TypeDescription target) {
|
|
||||||
try {
|
|
||||||
return instrumentationMatcher.matches(target);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(
|
|
||||||
"Instrumentation matcher unexpected exception: " + instrumentationPrimaryName, e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private AgentBuilder.Identified.Extendable injectHelperClasses(
|
private AgentBuilder.Identified.Extendable injectHelperClasses(
|
||||||
AgentBuilder.Identified.Extendable agentBuilder) {
|
AgentBuilder.Identified.Extendable agentBuilder) {
|
||||||
final String[] helperClassNames = helperClassNames();
|
final String[] helperClassNames = helperClassNames();
|
||||||
|
@ -151,7 +142,7 @@ public interface Instrumenter {
|
||||||
instrumentationPrimaryName,
|
instrumentationPrimaryName,
|
||||||
getClass().getName(),
|
getClass().getName(),
|
||||||
classLoader);
|
classLoader);
|
||||||
for (Reference.Mismatch mismatch : mismatches) {
|
for (final Reference.Mismatch mismatch : mismatches) {
|
||||||
log.debug("-- {}", mismatch);
|
log.debug("-- {}", mismatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +150,7 @@ public interface Instrumenter {
|
||||||
log.debug(
|
log.debug(
|
||||||
"Applying instrumentation: {} -- {} on {}",
|
"Applying instrumentation: {} -- {} on {}",
|
||||||
instrumentationPrimaryName,
|
instrumentationPrimaryName,
|
||||||
this.getClass().getName(),
|
getClass().getName(),
|
||||||
classLoader);
|
classLoader);
|
||||||
}
|
}
|
||||||
return mismatches.size() == 0;
|
return mismatches.size() == 0;
|
||||||
|
|
Loading…
Reference in New Issue