diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 401d6036fd..e5ccd7b3f7 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,3 +2,6 @@ # https://help.github.com/en/articles/about-code-owners * @DataDog/apm-java + +dd-java-agent/agent-profiling/ @DataDog/profiling +dd-smoke-tests/profiling-integration-tests/ @DataDog/profiling diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cec83b9b54..d150a433ec 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -### Contributing +## Contributing Pull requests for bug fixes are welcome, but before submitting new features or changes to current functionality [open an issue](https://github.com/DataDog/dd-trace-java/issues/new) and discuss your ideas or propose the changes you wish to make. After a resolution is reached a PR can be submitted for review. @@ -15,7 +15,14 @@ Java files must be formatted using [google-java-format](https://github.com/googl Other source files (Groovy, Scala, etc) should ideally be formatted by Intellij Idea's default formatting, but are not enforced. -### Intellij Idea +### Intellij IDEA + +Compiler settings: +* OpenJDK 11 must be installed to build the entire project. Under `SDKs` it must have the name `11`. +* Under `Build, Execution, Deployment > Compiler > Java Compiler` disable `Use '--release' option for cross-compilation` + +Required plugins: +* [Lombok](https://plugins.jetbrains.com/plugin/6317-lombok-plugin) Suggested plugins and settings: @@ -25,6 +32,5 @@ Suggested plugins and settings: * With java use the following import layout (groovy should still use the default) to ensure consistency with google-java-format: ![import layout](https://user-images.githubusercontent.com/734411/43430811-28442636-94ae-11e8-86f1-f270ddcba023.png) * [Google Java Format](https://plugins.jetbrains.com/plugin/8527-google-java-format) -* [Lombok](https://plugins.jetbrains.com/plugin/6317-lombok-plugin) * [Save Actions](https://plugins.jetbrains.com/plugin/7642-save-actions) ![Recommended Settings](https://user-images.githubusercontent.com/734411/43430944-db84bf8a-94ae-11e8-8cec-0daa064937c4.png) diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/decorator/HttpServerDecorator.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/decorator/HttpServerDecorator.java index ff8e1f50dc..ef8956a60d 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/decorator/HttpServerDecorator.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/decorator/HttpServerDecorator.java @@ -23,8 +23,6 @@ public abstract class HttpServerDecorator extends protected abstract URI url(REQUEST request) throws URISyntaxException; - protected abstract String peerHostname(CONNECTION connection); - protected abstract String peerHostIP(CONNECTION connection); protected abstract Integer peerPort(CONNECTION connection); @@ -87,7 +85,6 @@ public abstract class HttpServerDecorator extends public AgentSpan onConnection(final AgentSpan span, final CONNECTION connection) { assert span != null; if (connection != null) { - span.setTag(Tags.PEER_HOSTNAME.getKey(), peerHostname(connection)); final String ip = peerHostIP(connection); if (ip != null) { if (VALID_IPV4_ADDRESS.matcher(ip).matches()) { diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java index 0f466e1a49..7bab610e0f 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentInstaller.java @@ -1,15 +1,13 @@ package datadog.trace.agent.tooling; import static datadog.trace.agent.tooling.ClassLoaderMatcher.skipClassLoader; +import static datadog.trace.agent.tooling.bytebuddy.GlobalIgnoresMatcher.globalIgnoresMatcher; import static net.bytebuddy.matcher.ElementMatchers.any; -import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; -import static net.bytebuddy.matcher.ElementMatchers.nameContains; -import static net.bytebuddy.matcher.ElementMatchers.nameMatches; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.none; -import static net.bytebuddy.matcher.ElementMatchers.not; +import datadog.trace.agent.tooling.context.FieldBackedProvider; import datadog.trace.api.Config; import java.lang.instrument.Instrumentation; import java.util.ArrayList; @@ -21,10 +19,10 @@ import java.util.ServiceLoader; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.agent.builder.ResettableClassFileTransformer; +import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.utility.JavaModule; @Slf4j @@ -54,91 +52,33 @@ public class AgentInstaller { final Instrumentation inst, final AgentBuilder.Listener... listeners) { INSTRUMENTATION = inst; + addByteBuddyRawSetting(); + + FieldBackedProvider.resetContextMatchers(); + AgentBuilder agentBuilder = new AgentBuilder.Default() .disableClassFormatChanges() .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) - .with(new RedefinitionLoggingListener()) .with(AgentBuilder.DescriptionStrategy.Default.POOL_ONLY) .with(AgentTooling.poolStrategy()) - .with(new TransformLoggingListener()) .with(new ClassLoadListener()) .with(AgentTooling.locationStrategy()) // FIXME: we cannot enable it yet due to BB/JVM bug, see // https://github.com/raphw/byte-buddy/issues/558 // .with(AgentBuilder.LambdaInstrumentationStrategy.ENABLED) .ignore(any(), skipClassLoader()) - // Unlikely to ever need to instrument an annotation: - .or(ElementMatchers.isAnnotation()) - // Unlikely to ever need to instrument an enum: - .or(ElementMatchers.isEnum()) - .or( - nameStartsWith("datadog.trace.") - // FIXME: We should remove this once - // https://github.com/raphw/byte-buddy/issues/558 is fixed - .and( - not( - named( - "datadog.trace.bootstrap.instrumentation.java.concurrent.RunnableWrapper") - .or( - named( - "datadog.trace.bootstrap.instrumentation.java.concurrent.CallableWrapper"))))) - .or(nameStartsWith("datadog.opentracing.")) - .or(nameStartsWith("datadog.slf4j.")) - .or(nameStartsWith("net.bytebuddy.")) - .or( - nameStartsWith("java.") - .and( - not( - named("java.net.URL") - .or(named("java.net.HttpURLConnection")) - .or(nameStartsWith("java.rmi.")) - .or(nameStartsWith("java.util.concurrent.")) - .or( - nameStartsWith("java.util.logging.") - // Concurrent instrumentation modifies the strucutre of - // Cleaner class incompaibly with java9+ modules. - // Working around until a long-term fix for modules can be - // put in place. - .and(not(named("java.util.logging.LogManager$Cleaner"))))))) - .or( - nameStartsWith("com.sun.") - .and( - not( - nameStartsWith("com.sun.messaging.") - .or(nameStartsWith("com.sun.jersey.api.client"))))) - .or( - nameStartsWith("sun.") - .and( - not( - nameStartsWith("sun.net.www.protocol.") - .or(nameStartsWith("sun.rmi.server")) - .or(nameStartsWith("sun.rmi.transport")) - .or(named("sun.net.www.http.HttpClient"))))) - .or(nameStartsWith("jdk.")) - .or(nameStartsWith("org.aspectj.")) - .or(nameStartsWith("org.groovy.")) - .or(nameStartsWith("org.codehaus.groovy.macro.")) - .or(nameStartsWith("com.intellij.rt.debugger.")) - .or(nameStartsWith("com.p6spy.")) - .or(nameStartsWith("com.newrelic.")) - .or(nameStartsWith("com.dynatrace.")) - .or(nameStartsWith("com.jloadtrace.")) - .or(nameStartsWith("com.appdynamics.")) - .or(nameStartsWith("com.singularity.")) - .or(nameStartsWith("com.jinspired.")) - .or(nameStartsWith("org.jinspired.")) - .or(nameStartsWith("org.apache.log4j.").and(not(named("org.apache.log4j.MDC")))) - .or(nameStartsWith("org.slf4j.").and(not(named("org.slf4j.MDC")))) - .or(nameContains("$JaxbAccessor")) - .or(nameContains("CGLIB$$")) - .or(nameContains("javassist")) - .or(nameContains(".asm.")) - .or(nameContains("$__sisu")) - .or(nameMatches("com\\.mchange\\.v2\\.c3p0\\..*Proxy")) - .or(isAnnotatedWith(named("javax.decorator.Decorator"))) + .or(globalIgnoresMatcher()) .or(matchesConfiguredExcludes()); + if (log.isDebugEnabled()) { + agentBuilder = + agentBuilder + .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) + .with(new RedefinitionLoggingListener()) + .with(new TransformLoggingListener()); + } + for (final AgentBuilder.Listener listener : listeners) { agentBuilder = agentBuilder.with(listener); } @@ -159,6 +99,23 @@ public class AgentInstaller { return agentBuilder.installOn(inst); } + private static void addByteBuddyRawSetting() { + final String savedPropertyValue = System.getProperty(TypeDefinition.RAW_TYPES_PROPERTY); + try { + System.setProperty(TypeDefinition.RAW_TYPES_PROPERTY, "true"); + final boolean rawTypes = TypeDescription.AbstractBase.RAW_TYPES; + if (!rawTypes) { + log.debug("Too late to enable {}", TypeDefinition.RAW_TYPES_PROPERTY); + } + } finally { + if (savedPropertyValue == null) { + System.clearProperty(TypeDefinition.RAW_TYPES_PROPERTY); + } else { + System.setProperty(TypeDefinition.RAW_TYPES_PROPERTY, savedPropertyValue); + } + } + } + private static ElementMatcher.Junction matchesConfiguredExcludes() { final List excludedClasses = Config.get().getExcludedClasses(); ElementMatcher.Junction matcher = none(); diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java index e6b302ae89..bd98181a71 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/AgentTooling.java @@ -1,5 +1,7 @@ package datadog.trace.agent.tooling; +import datadog.trace.agent.tooling.bytebuddy.DDCachingPoolStrategy; +import datadog.trace.agent.tooling.bytebuddy.DDLocationStrategy; import datadog.trace.bootstrap.WeakMap; /** diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ByteBuddyElementMatchers.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ByteBuddyElementMatchers.java deleted file mode 100644 index b94a19e4ab..0000000000 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ByteBuddyElementMatchers.java +++ /dev/null @@ -1,382 +0,0 @@ -package datadog.trace.agent.tooling; - -import static net.bytebuddy.matcher.ElementMatchers.hasSignature; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import lombok.extern.slf4j.Slf4j; -import net.bytebuddy.build.HashCodeAndEqualsPlugin; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.type.TypeDefinition; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.description.type.TypeList; -import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.matcher.ElementMatchers; - -/** - * This class provides some custom ByteBuddy element matchers to use when applying instrumentation - */ -@Slf4j -public class ByteBuddyElementMatchers { - - /** - * Matches any type description that declares a super type that matches the provided matcher. - * Exceptions during matching process are logged and ignored. - * - * @param matcher The type to be checked for being a super type of the matched type. - * @param The type of the matched object. - * @return A matcher that matches any type description that declares a super type that matches the - * provided matcher. - * @see ElementMatchers#hasSuperType(net.bytebuddy.matcher.ElementMatcher) - */ - public static ElementMatcher.Junction safeHasSuperType( - final ElementMatcher matcher) { - return safeHasGenericSuperType(new SafeErasureMatcher(matcher)); - } - - /** - * Matches any type description that declares a super type that matches the provided matcher. - * Exceptions during matching process are logged and ignored. - * - * @param matcher The type to be checked for being a super type of the matched type. - * @param The type of the matched object. - * @return A matcher that matches any type description that declares a super type that matches the - * provided matcher. - * @see ElementMatchers#hasGenericSuperType(net.bytebuddy.matcher.ElementMatcher) - */ - public static ElementMatcher.Junction safeHasGenericSuperType( - final ElementMatcher 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 The type of the matched object. - * @return A matcher that returns {@code false} in case that the given matcher throws an - * exception. - */ - public static ElementMatcher.Junction failSafe( - final ElementMatcher matcher, final String description) { - return new SafeMatcher<>(matcher, false, description); - } - - private static TypeDescription safeAsErasure(final TypeDefinition typeDefinition) { - try { - return typeDefinition.asErasure(); - } catch (final Exception e) { - log.debug( - "{} trying to get erasure for target {}: {}", - e.getClass().getSimpleName(), - safeTypeDefinitionName(typeDefinition), - e.getMessage()); - return null; - } - } - - /** - * An element matcher that matches a super type. This is different from {@link - * net.bytebuddy.matcher.HasSuperTypeMatcher} in the following way: - * - *
    - *
  • Exceptions are logged - *
  • When exception happens the rest of the inheritance subtree is discarded (since ByteBuddy - * cannot load/parse type information for it) but search in other subtrees continues - *
- * - *

This is useful because this allows us to see when matcher's check is not complete (i.e. part - * of it fails), at the same time it makes best effort instead of failing quickly (like {@code - * failSafe(hasSuperType(...))} does) which means the code is more resilient to classpath - * inconsistencies - * - * @param The type of the matched entity. - * @see net.bytebuddy.matcher.HasSuperTypeMatcher - */ - @HashCodeAndEqualsPlugin.Enhance - public static class SafeHasSuperTypeMatcher - extends ElementMatcher.Junction.AbstractBase { - - /** The matcher to apply to any super type of the matched type. */ - private final ElementMatcher matcher; - - /** - * Creates a new matcher for a super type. - * - * @param matcher The matcher to apply to any super type of the matched type. - */ - public SafeHasSuperTypeMatcher(final ElementMatcher matcher) { - this.matcher = matcher; - } - - @Override - public boolean matches(final T target) { - final Set checkedInterfaces = new HashSet<>(); - // We do not use foreach loop and iterator interface here because we need to catch exceptions - // in {@code getSuperClass} calls - TypeDefinition typeDefinition = target; - while (typeDefinition != null) { - if (matcher.matches(typeDefinition.asGenericType()) - || hasInterface(typeDefinition, checkedInterfaces)) { - return true; - } - typeDefinition = safeGetSuperClass(typeDefinition); - } - return false; - } - - private TypeDefinition safeGetSuperClass(final TypeDefinition typeDefinition) { - try { - return typeDefinition.getSuperClass(); - } catch (final Exception e) { - log.debug( - "{} trying to get super class for target {}: {}", - e.getClass().getSimpleName(), - safeTypeDefinitionName(typeDefinition), - e.getMessage()); - return null; - } - } - - /** - * Matches a type's interfaces against the provided matcher. - * - * @param typeDefinition The type for which to check all implemented interfaces. - * @param checkedInterfaces The interfaces that have already been checked. - * @return {@code true} if any interface matches the supplied matcher. - */ - private boolean hasInterface( - final TypeDefinition typeDefinition, final Set checkedInterfaces) { - for (final TypeDefinition interfaceType : safeGetInterfaces(typeDefinition)) { - final TypeDescription erasure = safeAsErasure(interfaceType); - if (erasure != null) { - if (checkedInterfaces.add(interfaceType.asErasure()) - && (matcher.matches(interfaceType.asGenericType()) - || hasInterface(interfaceType, checkedInterfaces))) { - return true; - } - } - } - return false; - } - - /** - * TypeDefinition#getInterfaces() produces an interator which may throw an exception during - * iteration if an interface is absent from the classpath. - * - *

This method exists to allow getting interfaces even if the lookup on one fails. - */ - private List safeGetInterfaces(final TypeDefinition typeDefinition) { - final List interfaceTypes = new ArrayList<>(); - try { - final Iterator interfaceIter = - typeDefinition.getInterfaces().iterator(); - while (interfaceIter.hasNext()) { - interfaceTypes.add(interfaceIter.next()); - } - } catch (final Exception e) { - log.debug( - "{} trying to get interfaces for target {}: {}", - e.getClass().getSimpleName(), - safeTypeDefinitionName(typeDefinition), - e.getMessage()); - } - return interfaceTypes; - } - - @Override - public String toString() { - 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. - * - *

Catches and logs exception if it was thrown when getting erasure, returning false. - * - * @param The type of the matched entity. - * @see net.bytebuddy.matcher.ErasureMatcher - */ - @HashCodeAndEqualsPlugin.Enhance - public static class SafeErasureMatcher - extends ElementMatcher.Junction.AbstractBase { - - /** The matcher to apply to the raw type of the matched element. */ - private final ElementMatcher matcher; - - /** - * Creates a new erasure matcher. - * - * @param matcher The matcher to apply to the raw type. - */ - public SafeErasureMatcher(final ElementMatcher 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. - * - *

Logs exception if it was thrown. - * - * @param The type of the matched entity. - * @see net.bytebuddy.matcher.FailSafeMatcher - */ - @HashCodeAndEqualsPlugin.Enhance - public static class SafeMatcher extends ElementMatcher.Junction.AbstractBase { - - /** The delegate matcher that might throw an exception. */ - private final ElementMatcher 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 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 + ")"; - } - } - - private static String safeTypeDefinitionName(final TypeDefinition td) { - try { - return td.getTypeName(); - } catch (final IllegalStateException ex) { - final String message = ex.getMessage(); - if (message.startsWith("Cannot resolve type description for ")) { - return message.replace("Cannot resolve type description for ", ""); - } else { - return "?"; - } - } - } - - // TODO: add javadoc - public static ElementMatcher.Junction hasSuperMethod( - final ElementMatcher matcher) { - return new HasSuperMethodMatcher<>(matcher); - } - - // TODO: add javadoc - @HashCodeAndEqualsPlugin.Enhance - public static class HasSuperMethodMatcher - extends ElementMatcher.Junction.AbstractBase { - - private final ElementMatcher matcher; - - public HasSuperMethodMatcher(final ElementMatcher matcher) { - this.matcher = matcher; - } - - @Override - public boolean matches(final MethodDescription target) { - if (target.isConstructor()) { - return false; - } - final Junction signatureMatcher = hasSignature(target.asSignatureToken()); - TypeDefinition declaringType = target.getDeclaringType(); - final Set checkedInterfaces = new HashSet<>(); - - while (declaringType != null) { - for (final MethodDescription methodDescription : declaringType.getDeclaredMethods()) { - if (signatureMatcher.matches(methodDescription) && matcher.matches(methodDescription)) { - return true; - } - } - if (matchesInterface(declaringType.getInterfaces(), signatureMatcher, checkedInterfaces)) { - return true; - } - declaringType = safeGetSuperClass(declaringType); - } - return false; - } - - private boolean matchesInterface( - final TypeList.Generic interfaces, - final Junction signatureMatcher, - final Set checkedInterfaces) { - for (final TypeDefinition type : interfaces) { - if (!checkedInterfaces.contains(type)) { - checkedInterfaces.add(type); - for (final MethodDescription methodDescription : type.getDeclaredMethods()) { - if (signatureMatcher.matches(methodDescription) && matcher.matches(methodDescription)) { - return true; - } - } - if (matchesInterface(type.getInterfaces(), signatureMatcher, checkedInterfaces)) { - return true; - } - } - } - return false; - } - - private TypeDefinition safeGetSuperClass(final TypeDefinition typeDefinition) { - try { - return typeDefinition.getSuperClass(); - } catch (final Exception e) { - log.debug( - "{} trying to get super class for target {}: {}", - e.getClass().getSimpleName(), - safeTypeDefinitionName(typeDefinition), - e.getMessage()); - return null; - } - } - - @Override - public String toString() { - return "hasSuperMethodMatcher(" + matcher + ")"; - } - } -} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java index ac776607c0..d19aad4117 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ClassLoaderMatcher.java @@ -1,20 +1,17 @@ package datadog.trace.agent.tooling; -import static datadog.trace.bootstrap.WeakMap.Provider.newWeakMap; - -import datadog.trace.bootstrap.DatadogClassLoader; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import datadog.trace.bootstrap.PatchLogger; -import datadog.trace.bootstrap.WeakMap; import io.opentracing.util.GlobalTracer; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.matcher.ElementMatcher; @Slf4j -public class ClassLoaderMatcher { +public final class ClassLoaderMatcher { public static final ClassLoader BOOTSTRAP_CLASSLOADER = null; + public static final int CACHE_CONCURRENCY = + Math.max(8, Runtime.getRuntime().availableProcessors()); /** A private constructor that must not be invoked. */ private ClassLoaderMatcher() { @@ -25,58 +22,49 @@ public class ClassLoaderMatcher { return SkipClassLoaderMatcher.INSTANCE; } - public static ElementMatcher.Junction.AbstractBase classLoaderHasClasses( - final String... names) { - return new ClassLoaderHasClassMatcher(names); + public static ElementMatcher.Junction.AbstractBase classLoaderHasNoResources( + final String... resources) { + return new ClassLoaderHasNoResourceMatcher(resources); } - private static class SkipClassLoaderMatcher - extends ElementMatcher.Junction.AbstractBase - implements WeakMap.ValueSupplier { + private static final class SkipClassLoaderMatcher + extends ElementMatcher.Junction.AbstractBase { public static final SkipClassLoaderMatcher INSTANCE = new SkipClassLoaderMatcher(); /* Cache of classloader-instance -> (true|false). True = skip instrumentation. False = safe to instrument. */ - private static final WeakMap SKIP_CACHE = newWeakMap(); - private static final Set CLASSLOADER_CLASSES_TO_SKIP; - - static { - final Set classesToSkip = new HashSet<>(); - classesToSkip.add("org.codehaus.groovy.runtime.callsite.CallSiteClassLoader"); - classesToSkip.add("sun.reflect.DelegatingClassLoader"); - classesToSkip.add("jdk.internal.reflect.DelegatingClassLoader"); - classesToSkip.add("clojure.lang.DynamicClassLoader"); - classesToSkip.add("org.apache.cxf.common.util.ASMHelper$TypeHelperClassLoader"); - classesToSkip.add(DatadogClassLoader.class.getName()); - CLASSLOADER_CLASSES_TO_SKIP = Collections.unmodifiableSet(classesToSkip); - } + private static final Cache skipCache = + CacheBuilder.newBuilder().weakKeys().concurrencyLevel(CACHE_CONCURRENCY).build(); + private static final String DATADOG_CLASSLOADER_NAME = + "datadog.trace.bootstrap.DatadogClassLoader"; private SkipClassLoaderMatcher() {} @Override - public boolean matches(final ClassLoader target) { - if (target == BOOTSTRAP_CLASSLOADER) { + public boolean matches(final ClassLoader cl) { + if (cl == BOOTSTRAP_CLASSLOADER) { // Don't skip bootstrap loader return false; } - return shouldSkipClass(target) || shouldSkipInstance(target); - } - - private boolean shouldSkipClass(final ClassLoader loader) { - return CLASSLOADER_CLASSES_TO_SKIP.contains(loader.getClass().getName()); - } - - private boolean shouldSkipInstance(final ClassLoader loader) { - return SKIP_CACHE.computeIfAbsent(loader, this); - } - - @Override - public Boolean get(final ClassLoader loader) { - final boolean skip = !delegatesToBootstrap(loader); - if (skip) { - log.debug( - "skipping classloader instance {} of type {}", loader, loader.getClass().getName()); + Boolean v = skipCache.getIfPresent(cl); + if (v != null) { + return v; } + v = shouldSkipClass(cl) || !delegatesToBootstrap(cl); + skipCache.put(cl, v); + return v; + } - return skip; + private static boolean shouldSkipClass(final ClassLoader loader) { + switch (loader.getClass().getName()) { + case "org.codehaus.groovy.runtime.callsite.CallSiteClassLoader": + case "sun.reflect.DelegatingClassLoader": + case "jdk.internal.reflect.DelegatingClassLoader": + case "clojure.lang.DynamicClassLoader": + case "org.apache.cxf.common.util.ASMHelper$TypeHelperClassLoader": + case "sun.misc.Launcher$ExtClassLoader": + case DATADOG_CLASSLOADER_NAME: + return true; + } + return false; } /** @@ -85,7 +73,7 @@ public class ClassLoaderMatcher { * class loading is issued from this check and {@code false} for 'real' class loads. We should * come up with some sort of hack to avoid this problem. */ - private boolean delegatesToBootstrap(final ClassLoader loader) { + private static boolean delegatesToBootstrap(final ClassLoader loader) { boolean delegates = true; if (!loadsExpectedClass(loader, GlobalTracer.class)) { log.debug("loader {} failed to delegate bootstrap opentracing class", loader); @@ -98,7 +86,8 @@ public class ClassLoaderMatcher { return delegates; } - private boolean loadsExpectedClass(final ClassLoader loader, final Class expectedClass) { + private static boolean loadsExpectedClass( + final ClassLoader loader, final Class expectedClass) { try { return loader.loadClass(expectedClass.getName()) == expectedClass; } catch (final ClassNotFoundException e) { @@ -107,36 +96,38 @@ public class ClassLoaderMatcher { } } - public static class ClassLoaderHasClassMatcher - extends ElementMatcher.Junction.AbstractBase - implements WeakMap.ValueSupplier { + private static class ClassLoaderHasNoResourceMatcher + extends ElementMatcher.Junction.AbstractBase { + private final Cache cache = + CacheBuilder.newBuilder().weakKeys().concurrencyLevel(CACHE_CONCURRENCY).build(); - private final WeakMap cache = newWeakMap(); + private final String[] resources; - private final String[] names; - - private ClassLoaderHasClassMatcher(final String... names) { - this.names = names; + private ClassLoaderHasNoResourceMatcher(final String... resources) { + this.resources = resources; } - @Override - public boolean matches(final ClassLoader target) { - if (target != null) { - return cache.computeIfAbsent(target, this); + private boolean hasNoResources(ClassLoader cl) { + for (final String resource : resources) { + if (cl.getResource(resource) == null) { + return true; + } } - return false; } @Override - public Boolean get(final ClassLoader target) { - for (final String name : names) { - if (target.getResource(Utils.getResourceName(name)) == null) { - return false; - } + public boolean matches(final ClassLoader cl) { + if (cl == null) { + return false; } - - return true; + Boolean v = cache.getIfPresent(cl); + if (v != null) { + return v; + } + v = hasNoResources(cl); + cache.put(cl, v); + return v; } } } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java index dca9fb6ccd..4b2bd2b4f3 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/Instrumenter.java @@ -1,10 +1,16 @@ package datadog.trace.agent.tooling; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.failSafe; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.failSafe; import static net.bytebuddy.matcher.ElementMatchers.any; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import datadog.trace.agent.tooling.bytebuddy.DDTransformers; +import datadog.trace.agent.tooling.bytebuddy.ExceptionHandlers; import datadog.trace.agent.tooling.context.FieldBackedProvider; import datadog.trace.agent.tooling.context.InstrumentationContextProvider; +import datadog.trace.agent.tooling.context.NoopContextProvider; import datadog.trace.agent.tooling.muzzle.Reference; import datadog.trace.agent.tooling.muzzle.ReferenceMatcher; import datadog.trace.api.Config; @@ -17,9 +23,11 @@ import java.util.SortedSet; import java.util.TreeSet; import lombok.extern.slf4j.Slf4j; import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.annotation.AnnotationSource; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatcher.Junction; import net.bytebuddy.utility.JavaModule; /** @@ -39,6 +47,12 @@ public interface Instrumenter { @Slf4j abstract class Default implements Instrumenter { + + // Added here instead of AgentInstaller's ignores because it's relatively + // expensive. https://github.com/DataDog/dd-trace-java/pull/1045 + public static final Junction NOT_DECORATOR_MATCHER = + not(isAnnotatedWith(named("javax.decorator.Decorator"))); + private final SortedSet instrumentationNames; private final String instrumentationPrimaryName; private final InstrumentationContextProvider contextProvider; @@ -53,7 +67,11 @@ public interface Instrumenter { instrumentationPrimaryName = instrumentationName; enabled = Config.get().isIntegrationEnabled(instrumentationNames, defaultEnabled()); - contextProvider = new FieldBackedProvider(this); + if (contextStore().size() > 0) { + contextProvider = new FieldBackedProvider(this); + } else { + contextProvider = NoopContextProvider.INSTANCE; + } } @Override @@ -73,6 +91,7 @@ public interface Instrumenter { classLoaderMatcher(), "Instrumentation class loader matcher unexpected exception: " + getClass().getName())) + .and(NOT_DECORATOR_MATCHER) .and(new MuzzleMatcher()) .and(new PostMatchHook()) .transform(DDTransformers.defaultTransformers()); @@ -120,10 +139,11 @@ public interface Instrumenter { */ final ReferenceMatcher muzzle = getInstrumentationMuzzle(); if (null != muzzle) { - final List mismatches = - muzzle.getMismatchedReferenceSources(classLoader); - if (mismatches.size() > 0) { + final boolean isMatch = muzzle.matches(classLoader); + if (!isMatch) { if (log.isDebugEnabled()) { + final List mismatches = + muzzle.getMismatchedReferenceSources(classLoader); log.debug( "Instrumentation muzzled: {} -- {} on {}", instrumentationNames, @@ -140,7 +160,7 @@ public interface Instrumenter { Instrumenter.Default.this.getClass().getName(), classLoader); } - return mismatches.size() == 0; + return isMatch; } return true; } @@ -204,11 +224,13 @@ public interface Instrumenter { public abstract Map, String> transformers(); /** - * A map of {class-name -> context-class-name}. Keys (and their subclasses) will be associated - * with a context of the value. + * Context stores to define for this instrumentation. + * + *

A map of {class-name -> context-class-name}. Keys (and their subclasses) will be + * associated with a context of the value. */ public Map contextStore() { - return Collections.EMPTY_MAP; + return Collections.emptyMap(); } protected boolean defaultEnabled() { diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java index 32a16a0b7c..f579210d33 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/WeakMapSuppliers.java @@ -39,7 +39,7 @@ class WeakMapSuppliers { @Override public WeakMap get() { - final WeakConcurrentMap map = new WeakConcurrentMap<>(false); + final WeakConcurrentMap map = new WeakConcurrentMap<>(false, true); cleaner.scheduleCleaning(map, MapCleaner.CLEANER, CLEAN_FREQUENCY_SECONDS, TimeUnit.SECONDS); return new Adapter<>(map); } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDCachingPoolStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java similarity index 63% rename from dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDCachingPoolStrategy.java rename to dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java index 1d4cccdb35..af41d33813 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDCachingPoolStrategy.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java @@ -1,4 +1,4 @@ -package datadog.trace.agent.tooling; +package datadog.trace.agent.tooling.bytebuddy; import static net.bytebuddy.agent.builder.AgentBuilder.PoolStrategy; @@ -6,7 +6,11 @@ import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import java.lang.ref.WeakReference; import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.description.annotation.AnnotationList; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.pool.TypePool; @@ -42,7 +46,7 @@ public class DDCachingPoolStrategy implements PoolStrategy { static final int LOADER_CAPACITY = 64; static final int TYPE_CAPACITY = 64; - static final int BOOTSTRAP_HASH = 0; + static final int BOOTSTRAP_HASH = 7236344; // Just a random number /** * Cache of recent ClassLoader WeakReferences; used to... @@ -89,16 +93,16 @@ public class DDCachingPoolStrategy implements PoolStrategy { loaderRefCache.put(classLoader, loaderRef); } - int loaderHash = classLoader.hashCode(); + final int loaderHash = classLoader.hashCode(); return createCachingTypePool(loaderHash, loaderRef, classFileLocator); } - private final TypePool.CacheProvider createCacheProvider( + private TypePool.CacheProvider createCacheProvider( final int loaderHash, final WeakReference loaderRef) { return new SharedResolutionCacheAdapter(loaderHash, loaderRef, sharedResolutionCache); } - private final TypePool createCachingTypePool( + private TypePool createCachingTypePool( final int loaderHash, final WeakReference loaderRef, final ClassFileLocator classFileLocator) { @@ -108,7 +112,7 @@ public class DDCachingPoolStrategy implements PoolStrategy { TypePool.Default.ReaderMode.FAST); } - private final TypePool createCachingTypePool( + private TypePool createCachingTypePool( final TypePool.CacheProvider cacheProvider, final ClassFileLocator classFileLocator) { return new TypePool.Default.WithLazyResolution( cacheProvider, classFileLocator, TypePool.Default.ReaderMode.FAST); @@ -140,7 +144,7 @@ public class DDCachingPoolStrategy implements PoolStrategy { this.loaderRef = loaderRef; this.className = className; - hashCode = (int) (31 * this.loaderHash) ^ className.hashCode(); + hashCode = 31 * this.loaderHash + className.hashCode(); } @Override @@ -150,18 +154,23 @@ public class DDCachingPoolStrategy implements PoolStrategy { @Override public boolean equals(final Object obj) { - if (!(obj instanceof TypeCacheKey)) return false; + if (!(obj instanceof TypeCacheKey)) { + return false; + } - TypeCacheKey that = (TypeCacheKey) obj; + final TypeCacheKey that = (TypeCacheKey) obj; - if (loaderHash != that.loaderHash) return false; + if (loaderHash != that.loaderHash) { + return false; + } + + if (className.equals(that.className)) { + // Fastpath loaderRef equivalence -- works because of WeakReference cache used + // Also covers the bootstrap null loaderRef case + if (loaderRef == that.loaderRef) { + return true; + } - // Fastpath loaderRef equivalence -- works because of WeakReference cache used - // Also covers the bootstrap null loaderRef case - if (loaderRef == that.loaderRef) { - // still need to check name - return className.equals(that.className); - } else if (className.equals(that.className)) { // need to perform a deeper loader check -- requires calling Reference.get // which can strengthen the Reference, so deliberately done last @@ -172,11 +181,15 @@ public class DDCachingPoolStrategy implements PoolStrategy { // In this case, it is fine because that means the ClassLoader is no // longer live, so the entries will never match anyway and will fall // out of the cache. - ClassLoader thisLoader = loaderRef.get(); - if (thisLoader == null) return false; + final ClassLoader thisLoader = loaderRef.get(); + if (thisLoader == null) { + return false; + } - ClassLoader thatLoader = that.loaderRef.get(); - if (thatLoader == null) return false; + final ClassLoader thatLoader = that.loaderRef.get(); + if (thatLoader == null) { + return false; + } return (thisLoader == thatLoader); } else { @@ -188,7 +201,7 @@ public class DDCachingPoolStrategy implements PoolStrategy { static final class SharedResolutionCacheAdapter implements TypePool.CacheProvider { private static final String OBJECT_NAME = "java.lang.Object"; private static final TypePool.Resolution OBJECT_RESOLUTION = - new TypePool.Resolution.Simple(TypeDescription.OBJECT); + new TypePool.Resolution.Simple(new CachingTypeDescription(TypeDescription.OBJECT)); private final int loaderHash; private final WeakReference loaderRef; @@ -205,9 +218,11 @@ public class DDCachingPoolStrategy implements PoolStrategy { @Override public TypePool.Resolution find(final String className) { - TypePool.Resolution existingResolution = + final TypePool.Resolution existingResolution = sharedResolutionCache.getIfPresent(new TypeCacheKey(loaderHash, loaderRef, className)); - if (existingResolution != null) return existingResolution; + if (existingResolution != null) { + return existingResolution; + } if (OBJECT_NAME.equals(className)) { return OBJECT_RESOLUTION; @@ -217,12 +232,13 @@ public class DDCachingPoolStrategy implements PoolStrategy { } @Override - public TypePool.Resolution register( - final String className, final TypePool.Resolution resolution) { + public TypePool.Resolution register(final String className, TypePool.Resolution resolution) { if (OBJECT_NAME.equals(className)) { return resolution; } + resolution = new CachingResolution(resolution); + sharedResolutionCache.put(new TypeCacheKey(loaderHash, loaderRef, className), resolution); return resolution; } @@ -232,4 +248,90 @@ public class DDCachingPoolStrategy implements PoolStrategy { // Allowing the high-level eviction policy make the clearing decisions } } + + private static class CachingResolution implements TypePool.Resolution { + private final TypePool.Resolution delegate; + private TypeDescription cachedResolution; + + public CachingResolution(final TypePool.Resolution delegate) { + + this.delegate = delegate; + } + + @Override + public boolean isResolved() { + return delegate.isResolved(); + } + + @Override + public TypeDescription resolve() { + // Intentionally not "thread safe". Duplicate work deemed an acceptable trade-off. + if (cachedResolution == null) { + cachedResolution = new CachingTypeDescription(delegate.resolve()); + } + return cachedResolution; + } + } + + /** + * TypeDescription implementation that delegates and caches the results for the expensive calls + * commonly used by our instrumentation. + */ + private static class CachingTypeDescription + extends TypeDescription.AbstractBase.OfSimpleType.WithDelegation { + private final TypeDescription delegate; + + // These fields are intentionally not "thread safe". + // Duplicate work deemed an acceptable trade-off. + private Generic superClass; + private TypeList.Generic interfaces; + private AnnotationList annotations; + private MethodList methods; + + public CachingTypeDescription(final TypeDescription delegate) { + this.delegate = delegate; + } + + @Override + protected TypeDescription delegate() { + return delegate; + } + + @Override + public Generic getSuperClass() { + if (superClass == null) { + superClass = delegate.getSuperClass(); + } + return superClass; + } + + @Override + public TypeList.Generic getInterfaces() { + if (interfaces == null) { + interfaces = delegate.getInterfaces(); + } + return interfaces; + } + + @Override + public AnnotationList getDeclaredAnnotations() { + if (annotations == null) { + annotations = delegate.getDeclaredAnnotations(); + } + return annotations; + } + + @Override + public MethodList getDeclaredMethods() { + if (methods == null) { + methods = delegate.getDeclaredMethods(); + } + return methods; + } + + @Override + public String getName() { + return delegate.getName(); + } + } } diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java similarity index 93% rename from dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java rename to dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java index 7a9ce42179..a3ec740f9d 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDLocationStrategy.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java @@ -1,5 +1,6 @@ -package datadog.trace.agent.tooling; +package datadog.trace.agent.tooling.bytebuddy; +import datadog.trace.agent.tooling.Utils; import java.util.ArrayList; import java.util.List; import net.bytebuddy.agent.builder.AgentBuilder; diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDTransformers.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDTransformers.java similarity index 72% rename from dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDTransformers.java rename to dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDTransformers.java index fe4bc25d32..371e286158 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/DDTransformers.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDTransformers.java @@ -1,4 +1,4 @@ -package datadog.trace.agent.tooling; +package datadog.trace.agent.tooling.bytebuddy; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.TypeConstantAdjustment; @@ -12,10 +12,10 @@ public class DDTransformers { new AgentBuilder.Transformer() { @Override public DynamicType.Builder transform( - DynamicType.Builder builder, - TypeDescription typeDescription, - ClassLoader classLoader, - JavaModule javaModule) { + final DynamicType.Builder builder, + final TypeDescription typeDescription, + final ClassLoader classLoader, + final JavaModule javaModule) { return builder.visit(TypeConstantAdjustment.INSTANCE); } }; diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ExceptionHandlers.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/ExceptionHandlers.java similarity index 98% rename from dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ExceptionHandlers.java rename to dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/ExceptionHandlers.java index 49db4f099f..09a275113f 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/ExceptionHandlers.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/ExceptionHandlers.java @@ -1,4 +1,4 @@ -package datadog.trace.agent.tooling; +package datadog.trace.agent.tooling.bytebuddy; import datadog.trace.bootstrap.ExceptionLogger; import net.bytebuddy.ClassFileVersion; diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/GlobalIgnoresMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/GlobalIgnoresMatcher.java new file mode 100644 index 0000000000..e809151f61 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/GlobalIgnoresMatcher.java @@ -0,0 +1,162 @@ +package datadog.trace.agent.tooling.bytebuddy; + +import java.util.regex.Pattern; +import net.bytebuddy.build.HashCodeAndEqualsPlugin; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@HashCodeAndEqualsPlugin.Enhance +public class GlobalIgnoresMatcher + extends ElementMatcher.Junction.AbstractBase { + + private static final Pattern COM_MCHANGE_PROXY = + Pattern.compile("com\\.mchange\\.v2\\.c3p0\\..*Proxy"); + + public static ElementMatcher.Junction globalIgnoresMatcher() { + return new GlobalIgnoresMatcher<>(); + } + + /** + * Be very careful about the types of matchers used in this section as they are called on every + * class load, so they must be fast. Generally speaking try to only use name matchers as they + * don't have to load additional info. + */ + @Override + public boolean matches(final T target) { + final String name = target.getActualName(); + + if (name.startsWith("datadog.opentracing.") + || name.startsWith("datadog.slf4j.") + || name.startsWith("net.bytebuddy.") + || name.startsWith("jdk.") + || name.startsWith("org.aspectj.") + || name.startsWith("org.groovy.") + || name.startsWith("org.codehaus.groovy.macro.") + || name.startsWith("com.intellij.rt.debugger.") + || name.startsWith("com.p6spy.") + || name.startsWith("com.newrelic.") + || name.startsWith("com.dynatrace.") + || name.startsWith("com.jloadtrace.") + || name.startsWith("com.appdynamics.") + || name.startsWith("com.singularity.") + || name.startsWith("com.jinspired.") + || name.startsWith("org.jinspired.") + || name.startsWith("org.springframework.cglib.") + || name.startsWith("org.springframework.aop.") + || name.startsWith("org.springframework.beans.factory.annotation.") + || name.startsWith("org.springframework.beans.factory.config.") + || name.startsWith("org.springframework.beans.factory.parsing.") + || name.startsWith("org.springframework.beans.factory.xml.") + || name.startsWith("org.springframework.beans.propertyeditors.") + || name.startsWith("org.springframework.boot.autoconfigure.cache.") + || name.startsWith("org.springframework.boot.autoconfigure.condition.") + || name.startsWith("org.springframework.boot.autoconfigure.http.") + || name.startsWith("org.springframework.boot.autoconfigure.jackson.") + || name.startsWith("org.springframework.boot.autoconfigure.web.") + || name.startsWith("org.springframework.boot.context.") + || name.startsWith("org.springframework.boot.convert.") + || name.startsWith("org.springframework.boot.diagnostics.") + || name.startsWith("org.springframework.boot.web.server.") + || name.startsWith("org.springframework.boot.web.servlet.") + || name.startsWith("org.springframework.context.annotation.") + || name.startsWith("org.springframework.context.event.") + || name.startsWith("org.springframework.context.expression.") + || name.startsWith("org.springframework.core.annotation.") + || name.startsWith("org.springframework.core.convert.") + || name.startsWith("org.springframework.core.env.") + || name.startsWith("org.springframework.core.io.") + || name.startsWith("org.springframework.core.type.") + || name.startsWith("org.springframework.expression.") + || name.startsWith("org.springframework.format.") + || name.startsWith("org.springframework.http.") + || name.startsWith("org.springframework.ui.") + || name.startsWith("org.springframework.validation.") + || name.startsWith("org.springframework.web.context.") + || name.startsWith("org.springframework.web.filter.") + || name.startsWith("org.springframework.web.method.") + || name.startsWith("org.springframework.web.multipart.") + || name.startsWith("org.springframework.web.util.")) { + + return true; + } + + if (name.startsWith("datadog.trace.")) { + // FIXME: We should remove this once + // https://github.com/raphw/byte-buddy/issues/558 is fixed + if (name.equals("datadog.trace.bootstrap.instrumentation.java.concurrent.RunnableWrapper") + || name.equals( + "datadog.trace.bootstrap.instrumentation.java.concurrent.CallableWrapper")) { + return false; + } + return true; + } + + if (name.startsWith("java.")) { + if (name.equals("java.net.URL") || name.equals("java.net.HttpURLConnection")) { + return false; + } + if (name.startsWith("java.rmi.") || name.startsWith("java.util.concurrent.")) { + return false; + } + // Concurrent instrumentation modifies the structure of + // Cleaner class incompatibly with java9+ modules. + // Working around until a long-term fix for modules can be + // put in place. + if (name.startsWith("java.util.logging.") + && !name.equals("java.util.logging.LogManager$Cleaner")) { + return false; + } + + return true; + } + + if (name.startsWith("com.sun.")) { + if (name.startsWith("com.sun.messaging.") || name.startsWith("com.sun.jersey.api.client")) { + return false; + } + + return true; + } + + if (name.startsWith("sun.")) { + if (name.startsWith("sun.net.www.protocol.") + || name.startsWith("sun.rmi.server") + || name.startsWith("sun.rmi.transport") + || name.equals("sun.net.www.http.HttpClient")) { + return false; + } + + return true; + } + + if (name.startsWith("org.apache.log4j.")) { + if (name.equals("org.apache.log4j.MDC")) { + return false; + } + + return true; + } + + if (name.startsWith("org.slf4j.")) { + if (name.equals("org.slf4j.MDC")) { + return false; + } + + return true; + } + + if (name.contains("$JaxbAccessor") + || name.contains("CGLIB$$") + || name.contains("javassist") + || name.contains(".asm.") + || name.contains("$__sisu")) { + return true; + } + + if (COM_MCHANGE_PROXY.matcher(name).matches()) { + return true; + } + + return false; + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/DDElementMatchers.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/DDElementMatchers.java new file mode 100644 index 0000000000..08987b8663 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/DDElementMatchers.java @@ -0,0 +1,72 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher; + +import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static net.bytebuddy.matcher.ElementMatchers.not; + +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * This class provides some custom ByteBuddy element matchers to use when applying instrumentation + */ +@Slf4j +public class DDElementMatchers { + + public static ElementMatcher.Junction extendsClass( + final ElementMatcher matcher) { + return not(isInterface()).and(new SafeExtendsClassMatcher<>(new SafeErasureMatcher<>(matcher))); + } + + public static ElementMatcher.Junction implementsInterface( + final ElementMatcher matcher) { + return not(isInterface()) + .and(new SafeHasSuperTypeMatcher<>(new SafeErasureMatcher<>(matcher), true)); + } + + public static ElementMatcher.Junction hasInterface( + final ElementMatcher matcher) { + return new SafeHasSuperTypeMatcher<>(new SafeErasureMatcher<>(matcher), true); + } + + public static ElementMatcher.Junction safeHasSuperType( + final ElementMatcher matcher) { + return not(isInterface()) + .and(new SafeHasSuperTypeMatcher<>(new SafeErasureMatcher<>(matcher), false)); + } + + // TODO: add javadoc + public static ElementMatcher.Junction hasSuperMethod( + final ElementMatcher matcher) { + return new HasSuperMethodMatcher<>(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 The type of the matched object. + * @return A matcher that returns {@code false} in case that the given matcher throws an + * exception. + */ + public static ElementMatcher.Junction failSafe( + final ElementMatcher matcher, final String description) { + return new LoggingFailSafeMatcher<>(matcher, false, description); + } + + static String safeTypeDefinitionName(final TypeDefinition td) { + try { + return td.getTypeName(); + } catch (final IllegalStateException ex) { + final String message = ex.getMessage(); + if (message.startsWith("Cannot resolve type description for ")) { + return message.replace("Cannot resolve type description for ", ""); + } else { + return "?"; + } + } + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/HasSuperMethodMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/HasSuperMethodMatcher.java new file mode 100644 index 0000000000..e0dd0ae66a --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/HasSuperMethodMatcher.java @@ -0,0 +1,72 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.SafeHasSuperTypeMatcher.safeGetSuperClass; +import static net.bytebuddy.matcher.ElementMatchers.hasSignature; + +import java.util.HashSet; +import java.util.Set; +import net.bytebuddy.build.HashCodeAndEqualsPlugin; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeList; +import net.bytebuddy.matcher.ElementMatcher; + +// TODO: add javadoc +@HashCodeAndEqualsPlugin.Enhance +class HasSuperMethodMatcher + extends ElementMatcher.Junction.AbstractBase { + + private final ElementMatcher matcher; + + public HasSuperMethodMatcher(final ElementMatcher matcher) { + this.matcher = matcher; + } + + @Override + public boolean matches(final MethodDescription target) { + if (target.isConstructor()) { + return false; + } + final Junction signatureMatcher = hasSignature(target.asSignatureToken()); + TypeDefinition declaringType = target.getDeclaringType(); + final Set checkedInterfaces = new HashSet<>(); + + while (declaringType != null) { + for (final MethodDescription methodDescription : declaringType.getDeclaredMethods()) { + if (signatureMatcher.matches(methodDescription) && matcher.matches(methodDescription)) { + return true; + } + } + if (matchesInterface(declaringType.getInterfaces(), signatureMatcher, checkedInterfaces)) { + return true; + } + declaringType = safeGetSuperClass(declaringType); + } + return false; + } + + private boolean matchesInterface( + final TypeList.Generic interfaces, + final Junction signatureMatcher, + final Set checkedInterfaces) { + for (final TypeDefinition type : interfaces) { + if (!checkedInterfaces.contains(type)) { + checkedInterfaces.add(type); + for (final MethodDescription methodDescription : type.getDeclaredMethods()) { + if (signatureMatcher.matches(methodDescription) && matcher.matches(methodDescription)) { + return true; + } + } + if (matchesInterface(type.getInterfaces(), signatureMatcher, checkedInterfaces)) { + return true; + } + } + } + return false; + } + + @Override + public String toString() { + return "hasSuperMethodMatcher(" + matcher + ")"; + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/LoggingFailSafeMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/LoggingFailSafeMatcher.java new file mode 100644 index 0000000000..3d7552dff3 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/LoggingFailSafeMatcher.java @@ -0,0 +1,57 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher; + +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.build.HashCodeAndEqualsPlugin; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * A fail-safe matcher catches exceptions that are thrown by a delegate matcher and returns an + * alternative value. + * + *

Logs exception if it was thrown. + * + * @param The type of the matched entity. + * @see net.bytebuddy.matcher.FailSafeMatcher + */ +@Slf4j +@HashCodeAndEqualsPlugin.Enhance +class LoggingFailSafeMatcher extends ElementMatcher.Junction.AbstractBase { + + /** The delegate matcher that might throw an exception. */ + private final ElementMatcher 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 LoggingFailSafeMatcher( + final ElementMatcher 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 + ")"; + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeErasureMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeErasureMatcher.java new file mode 100644 index 0000000000..29430da3ed --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeErasureMatcher.java @@ -0,0 +1,65 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeTypeDefinitionName; + +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.build.HashCodeAndEqualsPlugin; +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * 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. + * + *

Catches and logs exception if it was thrown when getting erasure, returning false. + * + * @param The type of the matched entity. + * @see net.bytebuddy.matcher.ErasureMatcher + */ +@Slf4j +@HashCodeAndEqualsPlugin.Enhance +class SafeErasureMatcher extends ElementMatcher.Junction.AbstractBase { + + /** The matcher to apply to the raw type of the matched element. */ + private final ElementMatcher matcher; + + /** + * Creates a new erasure matcher. + * + * @param matcher The matcher to apply to the raw type. + */ + public SafeErasureMatcher(final ElementMatcher 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 + ")"; + } + + static TypeDescription safeAsErasure(final TypeDefinition typeDefinition) { + try { + return typeDefinition.asErasure(); + } catch (final Exception e) { + log.debug( + "{} trying to get erasure for target {}: {}", + e.getClass().getSimpleName(), + safeTypeDefinitionName(typeDefinition), + e.getMessage()); + return null; + } + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeExtendsClassMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeExtendsClassMatcher.java new file mode 100644 index 0000000000..ddce190fd6 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeExtendsClassMatcher.java @@ -0,0 +1,36 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.SafeHasSuperTypeMatcher.safeGetSuperClass; + +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +class SafeExtendsClassMatcher + extends ElementMatcher.Junction.AbstractBase { + + private final ElementMatcher matcher; + + public SafeExtendsClassMatcher(final ElementMatcher matcher) { + this.matcher = matcher; + } + + @Override + public boolean matches(final T target) { + // We do not use foreach loop and iterator interface here because we need to catch exceptions + // in {@code getSuperClass} calls + TypeDefinition typeDefinition = target; + while (typeDefinition != null) { + if (matcher.matches(typeDefinition.asGenericType())) { + return true; + } + typeDefinition = safeGetSuperClass(typeDefinition); + } + return false; + } + + @Override + public String toString() { + return "safeExtendsClass(" + matcher + ")"; + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcher.java new file mode 100644 index 0000000000..c3a0d74f66 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcher.java @@ -0,0 +1,135 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeTypeDefinitionName; +import static datadog.trace.agent.tooling.bytebuddy.matcher.SafeErasureMatcher.safeAsErasure; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import lombok.extern.slf4j.Slf4j; +import net.bytebuddy.build.HashCodeAndEqualsPlugin; +import net.bytebuddy.description.type.TypeDefinition; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/** + * An element matcher that matches a super type. This is different from {@link + * net.bytebuddy.matcher.HasSuperTypeMatcher} in the following way: + * + *

    + *
  • Exceptions are logged + *
  • When exception happens the rest of the inheritance subtree is discarded (since ByteBuddy + * cannot load/parse type information for it) but search in other subtrees continues + *
+ * + *

This is useful because this allows us to see when matcher's check is not complete (i.e. part + * of it fails), at the same time it makes best effort instead of failing quickly (like {@code + * failSafe(hasSuperType(...))} does) which means the code is more resilient to classpath + * inconsistencies + * + * @param The type of the matched entity. + * @see net.bytebuddy.matcher.HasSuperTypeMatcher + */ +@Slf4j +@HashCodeAndEqualsPlugin.Enhance +class SafeHasSuperTypeMatcher + extends ElementMatcher.Junction.AbstractBase { + + /** The matcher to apply to any super type of the matched type. */ + private final ElementMatcher matcher; + + private final boolean interfacesOnly; + /** + * Creates a new matcher for a super type. + * + * @param matcher The matcher to apply to any super type of the matched type. + */ + public SafeHasSuperTypeMatcher( + final ElementMatcher matcher, final boolean interfacesOnly) { + this.matcher = matcher; + this.interfacesOnly = interfacesOnly; + } + + @Override + public boolean matches(final T target) { + final Set checkedInterfaces = new HashSet<>(); + // We do not use foreach loop and iterator interface here because we need to catch exceptions + // in {@code getSuperClass} calls + TypeDefinition typeDefinition = target; + while (typeDefinition != null) { + if (((!interfacesOnly || typeDefinition.isInterface()) + && matcher.matches(typeDefinition.asGenericType())) + || hasInterface(typeDefinition, checkedInterfaces)) { + return true; + } + typeDefinition = safeGetSuperClass(typeDefinition); + } + return false; + } + + /** + * Matches a type's interfaces against the provided matcher. + * + * @param typeDefinition The type for which to check all implemented interfaces. + * @param checkedInterfaces The interfaces that have already been checked. + * @return {@code true} if any interface matches the supplied matcher. + */ + private boolean hasInterface( + final TypeDefinition typeDefinition, final Set checkedInterfaces) { + for (final TypeDefinition interfaceType : safeGetInterfaces(typeDefinition)) { + final TypeDescription erasure = safeAsErasure(interfaceType); + if (erasure != null) { + if (checkedInterfaces.add(interfaceType.asErasure()) + && (matcher.matches(interfaceType.asGenericType()) + || hasInterface(interfaceType, checkedInterfaces))) { + return true; + } + } + } + return false; + } + + /** + * TypeDefinition#getInterfaces() produces an interator which may throw an exception during + * iteration if an interface is absent from the classpath. + * + *

This method exists to allow getting interfaces even if the lookup on one fails. + */ + private List safeGetInterfaces(final TypeDefinition typeDefinition) { + final List interfaceTypes = new ArrayList<>(); + try { + final Iterator interfaceIter = + typeDefinition.getInterfaces().iterator(); + while (interfaceIter.hasNext()) { + interfaceTypes.add(interfaceIter.next()); + } + } catch (final Exception e) { + log.debug( + "{} trying to get interfaces for target {}: {}", + e.getClass().getSimpleName(), + safeTypeDefinitionName(typeDefinition), + e.getMessage()); + } + return interfaceTypes; + } + + static TypeDefinition safeGetSuperClass(final TypeDefinition typeDefinition) { + try { + return typeDefinition.getSuperClass(); + } catch (final Exception e) { + log.debug( + "{} trying to get super class for target {}: {}", + e.getClass().getSimpleName(), + safeTypeDefinitionName(typeDefinition), + e.getMessage()); + return null; + } + } + + @Override + public String toString() { + return "safeHasSuperType(" + matcher + ")"; + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedProvider.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedProvider.java index 3c77fb422e..9c083bb29f 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedProvider.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/FieldBackedProvider.java @@ -1,13 +1,12 @@ package datadog.trace.agent.tooling.context; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; import static datadog.trace.agent.tooling.ClassLoaderMatcher.BOOTSTRAP_CLASSLOADER; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import datadog.trace.agent.tooling.HelperInjector; import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.Instrumenter.Default; import datadog.trace.agent.tooling.Utils; import datadog.trace.api.Config; import datadog.trace.bootstrap.ContextStore; @@ -20,6 +19,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -126,8 +126,8 @@ public class FieldBackedProvider implements InstrumentationContextProvider { @Override public AgentBuilder.Identified.Extendable instrumentationTransformer( AgentBuilder.Identified.Extendable builder) { - if (instrumenter.contextStore().size() > 0) { - /** + if (!instrumenter.contextStore().isEmpty()) { + /* * Install transformer that rewrites accesses to context store with specialized bytecode that * invokes appropriate storage implementation. */ @@ -303,14 +303,14 @@ public class FieldBackedProvider implements InstrumentationContextProvider { private AgentBuilder.Identified.Extendable injectHelpersIntoBootstrapClassloader( AgentBuilder.Identified.Extendable builder) { - /** + /* * We inject into bootstrap classloader because field accessor interfaces are needed by context * store implementations. Unfortunately this forces us to remove stored type checking because * actual classes may not be available at this point. */ builder = builder.transform(fieldAccessorInterfacesInjector); - /** + /* * We inject context store implementation into bootstrap classloader because same implementation * may be used by different instrumentations and it has to use same static map in case of * fallback to map-backed storage. @@ -341,35 +341,69 @@ public class FieldBackedProvider implements InstrumentationContextProvider { }; } + /* + Set of pairs (context holder, context class) for which we have matchers installed. + We use this to make sure we do not install matchers repeatedly for cases when same + context class is used by multiple instrumentations. + */ + private static final Set> INSTALLED_CONTEXT_MATCHERS = new HashSet<>(); + + /** Clear set that prevents multiple matchers for same context class */ + public static void resetContextMatchers() { + synchronized (INSTALLED_CONTEXT_MATCHERS) { + INSTALLED_CONTEXT_MATCHERS.clear(); + } + } + @Override public AgentBuilder.Identified.Extendable additionalInstrumentation( AgentBuilder.Identified.Extendable builder) { if (fieldInjectionEnabled) { for (final Map.Entry entry : instrumenter.contextStore().entrySet()) { - /** + /* * For each context store defined in a current instrumentation we create an agent builder * that injects necessary fields. + * Note: this synchronization should not have any impact on performance + * since this is done when agent builder is being made, it doesn't affect actual + * class transformation. */ - builder = - builder - .type( - safeHasSuperType(named(entry.getKey())).and(not(isInterface())), - instrumenter.classLoaderMatcher()) - .and(safeToInjectFieldsMatcher()) - .transform(AgentBuilder.Transformer.NoOp.INSTANCE); + synchronized (INSTALLED_CONTEXT_MATCHERS) { + // FIXME: This makes an assumption that class loader matchers for instrumenters that use + // same context classes should be the same - which seems reasonable, but is not checked. + // Addressing this properly requires some notion of 'compound intrumenters' which we + // currently do not have. + if (INSTALLED_CONTEXT_MATCHERS.contains(entry)) { + log.debug("Skipping builder for {} {}", instrumenter.getClass().getName(), entry); + continue; + } - /** - * We inject helpers here as well as when instrumentation is applied to ensure that helpers - * are present even if instrumented classes are not loaded, but classes with state fields - * added are loaded (e.g. sun.net.www.protocol.https.HttpsURLConnectionImpl). - */ - builder = injectHelpersIntoBootstrapClassloader(builder); + log.debug("Making builder for {} {}", instrumenter.getClass().getName(), entry); + INSTALLED_CONTEXT_MATCHERS.add(entry); - builder = - builder.transform( - getTransformerForASMVisitor( - getFieldInjectionVisitor(entry.getKey(), entry.getValue()))); + /* + * For each context store defined in a current instrumentation we create an agent builder + * that injects necessary fields. + */ + builder = + builder + .type(safeHasSuperType(named(entry.getKey())), instrumenter.classLoaderMatcher()) + .and(safeToInjectFieldsMatcher()) + .and(Default.NOT_DECORATOR_MATCHER) + .transform(AgentBuilder.Transformer.NoOp.INSTANCE); + + /* + * We inject helpers here as well as when instrumentation is applied to ensure that + * helpers are present even if instrumented classes are not loaded, but classes with state + * fields added are loaded (e.g. sun.net.www.protocol.https.HttpsURLConnectionImpl). + */ + builder = injectHelpersIntoBootstrapClassloader(builder); + + builder = + builder.transform( + getTransformerForASMVisitor( + getFieldInjectionVisitor(entry.getKey(), entry.getValue()))); + } } } return builder; @@ -384,7 +418,7 @@ public class FieldBackedProvider implements InstrumentationContextProvider { final JavaModule module, final Class classBeingRedefined, final ProtectionDomain protectionDomain) { - /** + /* * The idea here is that we can add fields if class is just being loaded * (classBeingRedefined == null) and we have to add same fields again if class we added * fields before is being transformed again. Note: here we assume that Class#getInterfaces() diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/NoopContextProvider.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/NoopContextProvider.java new file mode 100644 index 0000000000..dd1c36c3b5 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/context/NoopContextProvider.java @@ -0,0 +1,20 @@ +package datadog.trace.agent.tooling.context; + +import net.bytebuddy.agent.builder.AgentBuilder.Identified.Extendable; + +public class NoopContextProvider implements InstrumentationContextProvider { + + public static NoopContextProvider INSTANCE = new NoopContextProvider(); + + private NoopContextProvider() {} + + @Override + public Extendable instrumentationTransformer(final Extendable builder) { + return builder; + } + + @Override + public Extendable additionalInstrumentation(final Extendable builder) { + return builder; + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java index c669646024..d16556c9f6 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/muzzle/ReferenceMatcher.java @@ -22,9 +22,8 @@ import net.bytebuddy.pool.TypePool; /** Matches a set of references against a classloader. */ @Slf4j -public class ReferenceMatcher - implements WeakMap.ValueSupplier> { - private final WeakMap> mismatchCache = newWeakMap(); +public final class ReferenceMatcher implements WeakMap.ValueSupplier { + private final WeakMap mismatchCache = newWeakMap(); private final Reference[] references; private final Set helperClassNames; @@ -42,18 +41,12 @@ public class ReferenceMatcher } /** + * Matcher used by ByteBuddy. Fails fast and only caches empty results, or complete results + * * @param loader Classloader to validate against (or null for bootstrap) * @return true if all references match the classpath of loader */ - public boolean matches(final ClassLoader loader) { - return getMismatchedReferenceSources(loader).isEmpty(); - } - - /** - * @param loader Classloader to validate against (or null for bootstrap) - * @return A list of all mismatches between this ReferenceMatcher and loader's classpath. - */ - public List getMismatchedReferenceSources(ClassLoader loader) { + public boolean matches(ClassLoader loader) { if (loader == BOOTSTRAP_LOADER) { loader = Utils.getBootstrapProxy(); } @@ -62,8 +55,32 @@ public class ReferenceMatcher } @Override - public List get(final ClassLoader loader) { - final List mismatches = new ArrayList<>(0); + public Boolean get(final ClassLoader loader) { + for (final Reference reference : references) { + // Don't reference-check helper classes. + // They will be injected by the instrumentation's HelperInjector. + if (!helperClassNames.contains(reference.getClassName())) { + if (!checkMatch(reference, loader).isEmpty()) { + return false; + } + } + } + + return true; + } + + /** + * Loads the full list of mismatches. Used in debug contexts only + * + * @param loader Classloader to validate against (or null for bootstrap) + * @return A list of all mismatches between this ReferenceMatcher and loader's classpath. + */ + public List getMismatchedReferenceSources(ClassLoader loader) { + if (loader == BOOTSTRAP_LOADER) { + loader = Utils.getBootstrapProxy(); + } + + final List mismatches = new ArrayList<>(); for (final Reference reference : references) { // Don't reference-check helper classes. @@ -82,11 +99,12 @@ public class ReferenceMatcher * @param loader * @return A list of mismatched sources. A list of size 0 means the reference matches the class. */ - public static List checkMatch(Reference reference, ClassLoader loader) { + private static List checkMatch( + final Reference reference, final ClassLoader loader) { final TypePool typePool = AgentTooling.poolStrategy() .typePool(AgentTooling.locationStrategy().classFileLocator(loader), loader); - final List mismatches = new ArrayList<>(0); + final List mismatches = new ArrayList<>(); try { final TypePool.Resolution resolution = typePool.describe(Utils.getClassName(reference.getClassName())); @@ -96,7 +114,7 @@ public class ReferenceMatcher reference.getSources().toArray(new Source[0]), reference.getClassName())); } return checkMatch(reference, resolution.resolve()); - } catch (Exception e) { + } catch (final Exception e) { if (e.getMessage().startsWith("Cannot resolve type description for ")) { // bytebuddy throws an illegal state exception with this message if it cannot resolve types // TODO: handle missing type resolutions without catching bytebuddy's exceptions @@ -112,10 +130,10 @@ public class ReferenceMatcher } public static List checkMatch( - Reference reference, TypeDescription typeOnClasspath) { - final List mismatches = new ArrayList<>(0); + final Reference reference, final TypeDescription typeOnClasspath) { + final List mismatches = new ArrayList<>(); - for (Reference.Flag flag : reference.getFlags()) { + for (final Reference.Flag flag : reference.getFlags()) { if (!flag.matches(typeOnClasspath.getModifiers())) { final String desc = reference.getClassName(); mismatches.add( @@ -127,8 +145,8 @@ public class ReferenceMatcher } } - for (Reference.Field fieldRef : reference.getFields()) { - FieldDescription.InDefinedShape fieldDescription = findField(fieldRef, typeOnClasspath); + for (final Reference.Field fieldRef : reference.getFields()) { + final FieldDescription.InDefinedShape fieldDescription = findField(fieldRef, typeOnClasspath); if (fieldDescription == null) { mismatches.add( new Reference.Mismatch.MissingField( @@ -137,7 +155,7 @@ public class ReferenceMatcher fieldRef.getName(), fieldRef.getType().getInternalName())); } else { - for (Reference.Flag flag : fieldRef.getFlags()) { + for (final Reference.Flag flag : fieldRef.getFlags()) { if (!flag.matches(fieldDescription.getModifiers())) { final String desc = reference.getClassName() @@ -155,7 +173,7 @@ public class ReferenceMatcher } } - for (Reference.Method methodRef : reference.getMethods()) { + for (final Reference.Method methodRef : reference.getMethods()) { final MethodDescription.InDefinedShape methodDescription = findMethod(methodRef, typeOnClasspath); if (methodDescription == null) { @@ -165,7 +183,7 @@ public class ReferenceMatcher methodRef.getName(), methodRef.getDescriptor())); } else { - for (Reference.Flag flag : methodRef.getFlags()) { + for (final Reference.Flag flag : methodRef.getFlags()) { if (!flag.matches(methodDescription.getModifiers())) { final String desc = reference.getClassName() + "#" + methodRef.getName() + methodRef.getDescriptor(); @@ -184,8 +202,8 @@ public class ReferenceMatcher } private static FieldDescription.InDefinedShape findField( - Reference.Field fieldRef, TypeDescription typeOnClasspath) { - for (FieldDescription.InDefinedShape fieldType : typeOnClasspath.getDeclaredFields()) { + final Reference.Field fieldRef, final TypeDescription typeOnClasspath) { + for (final FieldDescription.InDefinedShape fieldType : typeOnClasspath.getDeclaredFields()) { if (fieldType.getName().equals(fieldRef.getName()) && fieldType .getType() @@ -196,14 +214,14 @@ public class ReferenceMatcher } } if (typeOnClasspath.getSuperClass() != null) { - FieldDescription.InDefinedShape fieldOnSupertype = + final FieldDescription.InDefinedShape fieldOnSupertype = findField(fieldRef, typeOnClasspath.getSuperClass().asErasure()); if (fieldOnSupertype != null) { return fieldOnSupertype; } } - for (TypeDescription.Generic interfaceType : typeOnClasspath.getInterfaces()) { - FieldDescription.InDefinedShape fieldOnSupertype = + for (final TypeDescription.Generic interfaceType : typeOnClasspath.getInterfaces()) { + final FieldDescription.InDefinedShape fieldOnSupertype = findField(fieldRef, interfaceType.asErasure()); if (fieldOnSupertype != null) { return fieldOnSupertype; @@ -213,8 +231,8 @@ public class ReferenceMatcher } private static MethodDescription.InDefinedShape findMethod( - Reference.Method methodRef, TypeDescription typeOnClasspath) { - for (MethodDescription.InDefinedShape methodDescription : + final Reference.Method methodRef, final TypeDescription typeOnClasspath) { + for (final MethodDescription.InDefinedShape methodDescription : typeOnClasspath.getDeclaredMethods()) { if (methodDescription.getInternalName().equals(methodRef.getName()) && methodDescription.getDescriptor().equals(methodRef.getDescriptor())) { @@ -222,14 +240,14 @@ public class ReferenceMatcher } } if (typeOnClasspath.getSuperClass() != null) { - MethodDescription.InDefinedShape methodOnSupertype = + final MethodDescription.InDefinedShape methodOnSupertype = findMethod(methodRef, typeOnClasspath.getSuperClass().asErasure()); if (methodOnSupertype != null) { return methodOnSupertype; } } - for (TypeDescription.Generic interfaceType : typeOnClasspath.getInterfaces()) { - MethodDescription.InDefinedShape methodOnSupertype = + for (final TypeDescription.Generic interfaceType : typeOnClasspath.getInterfaces()) { + final MethodDescription.InDefinedShape methodOnSupertype = findMethod(methodRef, interfaceType.asErasure()); if (methodOnSupertype != null) { return methodOnSupertype; diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/HttpServerDecoratorTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/HttpServerDecoratorTest.groovy index 163ded8240..4b431f662b 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/HttpServerDecoratorTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/decorator/HttpServerDecoratorTest.groovy @@ -83,7 +83,6 @@ class HttpServerDecoratorTest extends ServerDecoratorTest { then: if (conn) { - 1 * span.setTag(Tags.PEER_HOSTNAME.key, "test-host") 1 * span.setTag(Tags.PEER_PORT.key, 555) if (ipv4) { 1 * span.setTag(Tags.PEER_HOST_IPV4.key, "10.0.0.1") @@ -96,9 +95,9 @@ class HttpServerDecoratorTest extends ServerDecoratorTest { where: ipv4 | conn null | null - null | [host: "test-host", ip: null, port: 555] - true | [host: "test-host", ip: "10.0.0.1", port: 555] - false | [host: "test-host", ip: "3ffe:1900:4545:3:200:f8ff:fe21:67cf", port: 555] + null | [ip: null, port: 555] + true | [ip: "10.0.0.1", port: 555] + false | [ip: "3ffe:1900:4545:3:200:f8ff:fe21:67cf", port: 555] } def "test onResponse"() { @@ -173,11 +172,6 @@ class HttpServerDecoratorTest extends ServerDecoratorTest { return m.url } - @Override - protected String peerHostname(Map m) { - return m.host - } - @Override protected String peerHostIP(Map m) { return m.ip diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy index 892efbb78a..96c0fafb24 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ClassLoaderMatcherTest.groovy @@ -33,6 +33,11 @@ class ClassLoaderMatcherTest extends DDSpecification { !ClassLoaderMatcher.skipClassLoader().matches(null) } + def "DatadogClassLoader class name is hardcoded in ClassLoaderMatcher"() { + expect: + DatadogClassLoader.name == "datadog.trace.bootstrap.DatadogClassLoader" + } + /* * A URLClassloader which only delegates java.* classes */ diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ExceptionHandlerTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ExceptionHandlerTest.groovy index cedafaea29..ab440408c5 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ExceptionHandlerTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ExceptionHandlerTest.groovy @@ -3,7 +3,7 @@ package datadog.trace.agent.test import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger import ch.qos.logback.core.read.ListAppender -import datadog.trace.agent.tooling.ExceptionHandlers +import datadog.trace.agent.tooling.bytebuddy.ExceptionHandlers import datadog.trace.bootstrap.ExceptionLogger import datadog.trace.util.test.DDSpecification import net.bytebuddy.agent.ByteBuddyAgent diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy index 6b4a33c9d2..ff95afd609 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/test/ResourceLocatingTest.groovy @@ -1,6 +1,6 @@ package datadog.trace.agent.test -import datadog.trace.agent.tooling.DDLocationStrategy +import datadog.trace.agent.tooling.bytebuddy.DDLocationStrategy import datadog.trace.util.test.DDSpecification import net.bytebuddy.agent.builder.AgentBuilder import spock.lang.Shared diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/CacheProviderTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/CacheProviderTest.groovy index 73d0a1fe19..204c1538b5 100644 --- a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/CacheProviderTest.groovy +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/CacheProviderTest.groovy @@ -1,5 +1,6 @@ package datadog.trace.agent.tooling +import datadog.trace.agent.tooling.bytebuddy.DDCachingPoolStrategy import datadog.trace.util.test.DDSpecification import net.bytebuddy.description.type.TypeDescription import net.bytebuddy.dynamic.ClassFileLocator @@ -204,7 +205,7 @@ class CacheProviderTest extends DDSpecification { } static newClassLoader() { - return new URLClassLoader([] as URL[], (ClassLoader)null) + return new URLClassLoader([] as URL[], (ClassLoader) null) } static newLocator() { @@ -215,7 +216,8 @@ class CacheProviderTest extends DDSpecification { } @Override - void close() throws IOException {} + void close() throws IOException { + } } } } diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.groovy new file mode 100644 index 0000000000..fff3572044 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.groovy @@ -0,0 +1,52 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher + +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.A +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.B +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.F +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.G +import datadog.trace.util.test.DDSpecification +import net.bytebuddy.description.type.TypeDescription +import net.bytebuddy.jar.asm.Opcodes + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass +import static net.bytebuddy.matcher.ElementMatchers.named + +class ExtendsClassMatcherTest extends DDSpecification { + + def "test matcher #matcherClass.simpleName -> #type.simpleName"() { + expect: + extendsClass(matcher).matches(argument) == result + + where: + matcherClass | type | result + A | B | false + A | F | false + G | F | false + F | F | true + F | G | true + + matcher = named(matcherClass.name) + argument = TypeDescription.ForLoadedType.of(type) + } + + def "test traversal exceptions"() { + setup: + def type = Mock(TypeDescription) + def typeGeneric = Mock(TypeDescription.Generic) + def matcher = extendsClass(named(Object.name)) + + when: + def result = matcher.matches(type) + + then: + !result // default to false + noExceptionThrown() + 1 * type.getModifiers() >> Opcodes.ACC_ABSTRACT + 1 * type.asGenericType() >> typeGeneric + 1 * type.getTypeName() >> "type-name" + 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } + 1 * typeGeneric.getTypeName() >> "typeGeneric-name" + 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } + 0 * _ + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.groovy new file mode 100644 index 0000000000..6825085adc --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.groovy @@ -0,0 +1,60 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher + +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.A +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.B +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.E +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.F +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.G +import datadog.trace.util.test.DDSpecification +import net.bytebuddy.description.type.TypeDescription +import net.bytebuddy.jar.asm.Opcodes + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface +import static net.bytebuddy.matcher.ElementMatchers.named + +class HasInterfaceMatcherTest extends DDSpecification { + + def "test matcher #matcherClass.simpleName -> #type.simpleName"() { + expect: + hasInterface(matcher).matches(argument) == result + + where: + matcherClass | type | result + A | A | true + A | B | true + B | A | false + A | E | true + A | F | true + A | G | true + F | A | false + F | F | false + F | G | false + + matcher = named(matcherClass.name) + argument = TypeDescription.ForLoadedType.of(type) + } + + def "test traversal exceptions"() { + setup: + def type = Mock(TypeDescription) + def typeGeneric = Mock(TypeDescription.Generic) + def matcher = implementsInterface(named(Object.name)) + + when: + def result = matcher.matches(type) + + then: + !result // default to false + noExceptionThrown() + 1 * type.getModifiers() >> Opcodes.ACC_ABSTRACT + 1 * type.isInterface() >> true + 1 * type.asGenericType() >> typeGeneric + 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } + 1 * typeGeneric.getTypeName() >> "typeGeneric-name" + 1 * type.getInterfaces() >> { throw new Exception("getInterfaces exception") } + 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } + 2 * type.getTypeName() >> "type-name" + 0 * _ + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.groovy new file mode 100644 index 0000000000..5d2ebcdf81 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.groovy @@ -0,0 +1,68 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher + +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.A +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.B +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.C +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.F +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.G +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.TracedClass +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.UntracedClass +import datadog.trace.api.Trace +import datadog.trace.util.test.DDSpecification +import net.bytebuddy.description.method.MethodDescription + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasSuperMethod +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith +import static net.bytebuddy.matcher.ElementMatchers.none + +class HasSuperMethodMatcherTest extends DDSpecification { + + def "test matcher #type.simpleName #method"() { + expect: + hasSuperMethod(isAnnotatedWith(Trace)).matches(argument) == result + + where: + type | method | result + A | "a" | false + B | "b" | true + C | "c" | false + F | "f" | true + G | "g" | false + TracedClass | "a" | true + UntracedClass | "a" | false + UntracedClass | "b" | true + + argument = new MethodDescription.ForLoadedMethod(type.getDeclaredMethod(method)) + } + + def "test constructor never matches"() { + setup: + def method = Mock(MethodDescription) + def matcher = hasSuperMethod(none()) + + when: + def result = matcher.matches(method) + + then: + !result + 1 * method.isConstructor() >> true + 0 * _ + } + + def "test traversal exceptions"() { + setup: + def method = Mock(MethodDescription) + def matcher = hasSuperMethod(none()) + def sigToken = new MethodDescription.ForLoadedMethod(A.getDeclaredMethod("a")).asSignatureToken() + + when: + def result = matcher.matches(method) + + then: + !result // default to false + 1 * method.isConstructor() >> false + 1 * method.asSignatureToken() >> sigToken + 1 * method.getDeclaringType() >> null + 0 * _ + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.groovy new file mode 100644 index 0000000000..2decb1114e --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.groovy @@ -0,0 +1,59 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher + +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.A +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.B +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.E +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.F +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.G +import datadog.trace.util.test.DDSpecification +import net.bytebuddy.description.type.TypeDescription +import net.bytebuddy.jar.asm.Opcodes + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface +import static net.bytebuddy.matcher.ElementMatchers.named + +class ImplementsInterfaceMatcherTest extends DDSpecification { + + def "test matcher #matcherClass.simpleName -> #type.simpleName"() { + expect: + implementsInterface(matcher).matches(argument) == result + + where: + matcherClass | type | result + A | A | false + A | B | false + B | A | false + A | E | false + A | F | true + A | G | true + F | A | false + F | F | false + F | G | false + + matcher = named(matcherClass.name) + argument = TypeDescription.ForLoadedType.of(type) + } + + def "test traversal exceptions"() { + setup: + def type = Mock(TypeDescription) + def typeGeneric = Mock(TypeDescription.Generic) + def matcher = implementsInterface(named(Object.name)) + + when: + def result = matcher.matches(type) + + then: + !result // default to false + noExceptionThrown() + 1 * type.getModifiers() >> Opcodes.ACC_ABSTRACT + 1 * type.isInterface() >> true + 1 * type.asGenericType() >> typeGeneric + 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } + 1 * typeGeneric.getTypeName() >> "typeGeneric-name" + 1 * type.getInterfaces() >> { throw new Exception("getInterfaces exception") } + 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } + 2 * type.getTypeName() >> "type-name" + 0 * _ + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.groovy new file mode 100644 index 0000000000..d64af5b951 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.groovy @@ -0,0 +1,58 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher + +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.A +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.B +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.E +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.F +import datadog.trace.agent.tooling.bytebuddy.matcher.testclasses.G +import datadog.trace.util.test.DDSpecification +import net.bytebuddy.description.type.TypeDescription +import net.bytebuddy.jar.asm.Opcodes + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType +import static net.bytebuddy.matcher.ElementMatchers.named + +class SafeHasSuperTypeMatcherTest extends DDSpecification { + + def "test matcher #matcherClass.simpleName -> #type.simpleName"() { + expect: + safeHasSuperType(matcher).matches(argument) == result + + where: + matcherClass | type | result + A | A | false + A | B | false + B | A | false + A | E | false + A | F | true + B | G | true + F | A | false + F | F | true + F | G | true + + matcher = named(matcherClass.name) + argument = TypeDescription.ForLoadedType.of(type) + } + + def "test traversal exceptions"() { + setup: + def type = Mock(TypeDescription) + def typeGeneric = Mock(TypeDescription.Generic) + def matcher = safeHasSuperType(named(Object.name)) + + when: + def result = matcher.matches(type) + + then: + !result // default to false + noExceptionThrown() + 1 * type.getModifiers() >> Opcodes.ACC_ABSTRACT + 1 * type.asGenericType() >> typeGeneric + 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } + 1 * typeGeneric.getTypeName() >> "typeGeneric-name" + 1 * type.getInterfaces() >> { throw new Exception("getInterfaces exception") } + 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } + 2 * type.getTypeName() >> "type-name" + 0 * _ + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/SafeMatcherTest.groovy b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/SafeMatcherTest.groovy new file mode 100644 index 0000000000..c290502fe7 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/SafeMatcherTest.groovy @@ -0,0 +1,40 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher + +import datadog.trace.util.test.DDSpecification +import net.bytebuddy.matcher.ElementMatcher + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.failSafe + +class SafeMatcherTest extends DDSpecification { + + def mockMatcher = Mock(ElementMatcher) + + def "test matcher"() { + setup: + def matcher = failSafe(mockMatcher, "test") + + when: + def result = matcher.matches(new Object()) + + then: + 1 * mockMatcher.matches(_) >> match + result == match + + where: + match << [true, false] + } + + def "test matcher exception"() { + setup: + def matcher = failSafe(mockMatcher, "test") + + when: + def result = matcher.matches(new Object()) + + then: + 1 * mockMatcher.matches(_) >> { throw new Exception("matcher exception") } + 0 * _ + noExceptionThrown() + !result // default to false + } +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/A.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/A.java new file mode 100644 index 0000000000..43f723cb49 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/A.java @@ -0,0 +1,5 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +public interface A { + void a(); +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/B.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/B.java new file mode 100644 index 0000000000..d956115c2e --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/B.java @@ -0,0 +1,8 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +import datadog.trace.api.Trace; + +public interface B extends A { + @Trace + void b(); +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/C.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/C.java new file mode 100644 index 0000000000..4643231c7c --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/C.java @@ -0,0 +1,5 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +public interface C extends A, B { + void c(); +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/D.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/D.java new file mode 100644 index 0000000000..d5ae42e5fd --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/D.java @@ -0,0 +1,8 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +import datadog.trace.api.Trace; + +public interface D extends A, B, C { + @Trace + void d(); +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/E.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/E.java new file mode 100644 index 0000000000..859429ccb3 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/E.java @@ -0,0 +1,5 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +public interface E extends B, C, D { + void e(); +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/F.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/F.java new file mode 100644 index 0000000000..0c6e562897 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/F.java @@ -0,0 +1,8 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +import datadog.trace.api.Trace; + +public abstract class F implements E { + @Trace + public abstract void f(); +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/G.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/G.java new file mode 100644 index 0000000000..62e2ce4aa8 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/G.java @@ -0,0 +1,5 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +public abstract class G extends F { + public void g() {} +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/TracedClass.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/TracedClass.java new file mode 100644 index 0000000000..31a96b24a5 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/TracedClass.java @@ -0,0 +1,33 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +import datadog.trace.api.Trace; + +public class TracedClass extends UntracedClass { + @Trace + @Override + public void g() {} + + @Trace + @Override + public void f() {} + + @Trace + @Override + public void e() {} + + @Trace + @Override + public void d() {} + + @Trace + @Override + public void c() {} + + @Trace + @Override + public void b() {} + + @Trace + @Override + public void a() {} +} diff --git a/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/UntracedClass.java b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/UntracedClass.java new file mode 100644 index 0000000000..2ae032e561 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/test/groovy/datadog/trace/agent/tooling/bytebuddy/matcher/testclasses/UntracedClass.java @@ -0,0 +1,24 @@ +package datadog.trace.agent.tooling.bytebuddy.matcher.testclasses; + +public class UntracedClass extends G { + @Override + public void g() {} + + @Override + public void f() {} + + @Override + public void e() {} + + @Override + public void d() {} + + @Override + public void c() {} + + @Override + public void b() {} + + @Override + public void a() {} +} diff --git a/dd-java-agent/benchmark/benchmark.gradle b/dd-java-agent/benchmark/benchmark.gradle index 8d0205b087..4c2c066ced 100644 --- a/dd-java-agent/benchmark/benchmark.gradle +++ b/dd-java-agent/benchmark/benchmark.gradle @@ -6,68 +6,44 @@ apply from: "${rootDir}/gradle/java.gradle" dependencies { jmh project(':dd-trace-api') - jmh group: 'net.bytebuddy', name: 'byte-buddy-agent', version: '1.7.6' - - // Add a bunch of dependencies so instrumentation is not disabled. - jmh group: 'javax.jms', name: 'javax.jms-api', version: '2.0.1' - jmh group: 'javax.servlet', name: 'javax.servlet-api', version: '3.0.1' - jmh group: 'org.mongodb', name: 'mongo-java-driver', version: '3.4.2' - jmh group: 'org.mongodb', name: 'mongodb-driver-async', version: '3.4.2' - jmh(group: 'com.amazonaws', name: 'aws-java-sdk', version: '1.11.119') { - exclude(module: 'httpclient') - exclude(module: 'jackson-databind') - exclude(module: 'jackson-dataformat-cbor') - } - jmh group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0' - jmh group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3' - jmh(group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.2.0') + jmh deps.bytebuddyagent } -configurations.testRuntimeClasspath.dependencies.clear() - - jmh { - timeUnit = 'us' // Output time unit. Available time units are: [m, s, ms, us, ns]. - benchmarkMode = ['thrpt', 'avgt'] -// timeOnIteration = '5s' - iterations = 5 // Number of measurement iterations to do. + timeUnit = 'ms' // Output time unit. Available time units are: [m, s, ms, us, ns]. + benchmarkMode = ['avgt'] + timeOnIteration = '20s' + iterations = 1 // Number of measurement iterations to do. fork = 1 // How many times to forks a single benchmark. Use 0 to disable forking altogether -// jvmArgs = ["-Dasdf=123"] -// jvmArgs = ["-javaagent:${project(':dd-java-agent').shadowJar.archivePath}"] + jvmArgs = ["-Ddd.jmxfetch.enabled=false", "-Ddd.writer.type=LoggingWriter"] +// jvmArgs += ["-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints", "-XX:StartFlightRecording=delay=5s,dumponexit=true,name=jmh-benchmark,filename=${rootDir}/dd-java-agent/benchmark/build/reports/jmh/jmh-benchmark.jfr"] +// jvmArgs += ["-agentpath:${rootDir}/dd-java-agent/benchmark/src/jmh/resources/libasyncProfiler.so=start,collapsed,file=${rootDir}/dd-java-agent/benchmark/build/reports/jmh/profiler.txt".toString()] failOnError = true // Should JMH fail immediately if any benchmark had experienced the unrecoverable error? -// warmup = '2s' // Time to spend at each warmup iteration. -// warmupIterations = 2 // Number of warmup iterations to do. -// warmupForks = 0 // How many warmup forks to make for a single benchmark. 0 to disable warmup forks. + warmup = '5s' // Time to spend at each warmup iteration. +// warmupBatchSize = 10 // Warmup batch size: number of benchmark method calls per operation. + warmupForks = 0 // How many warmup forks to make for a single benchmark. 0 to disable warmup forks. + warmupIterations = 1 // Number of warmup iterations to do. -// profilers = ['stack'] +// profilers = ['stack:lines=5;detailLine=true;period=5;excludePackages=true'] // Use profilers to collect additional data. Supported profilers: [cl, comp, gc, stack, perf, perfnorm, perfasm, xperf, xperfasm, hs_cl, hs_comp, hs_gc, hs_rt, hs_thr] // humanOutputFile = project.file("${project.buildDir}/reports/jmh/human.txt") // human-readable output file // operationsPerInvocation = 10 // Operations per invocation. // synchronizeIterations = false // Synchronize iterations? - timeout = '1s' // Timeout for benchmark iteration. - includeTests = false + timeout = '5s' // Timeout for benchmark iteration. +// includeTests = false // Allows to include test sources into generate JMH jar, i.e. use it when benchmarks depend on the test classes. - duplicateClassesStrategy = 'fail' - jmhVersion = '1.20' // Specifies JMH version + duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE + jmhVersion = '1.23' // Specifies JMH version } -// configured as a separate task since the 'jmh' task did not like adding a javaagent argument. -tasks.register("jmhAgent", JavaExec) { - classpath = files(project.jmhCompileGeneratedClasses.destinationDir) - classpath += sourceSets.jmh.runtimeClasspath - main = "org.openjdk.jmh.Main" - args += ["-tu", "us"] - args += ["-bm", "avgt"] -// args += ["-prof", "stack:lines=5;detailLine=true;period=5;excludePackages=true"] - args += ["-f", "1"] - args += ["-foe", "true"] +tasks.jmh.dependsOn project(':dd-java-agent').shadowJar -// args += ["-wi", "2"] -// args += ["-i", "5"] - dependsOn project.tasks.jmhCompileGeneratedClasses -} - -tasks.jmhAgent.dependsOn project(':dd-java-agent').shadowJar +/* +If using libasyncProfiler, use the following to generate nice svg flamegraphs. +sed '/unknown/d' dd-java-agent/benchmark/build/reports/jmh/profiler.txt | sed '/^thread_start/d' | sed '/not_walkable/d' > dd-java-agent/benchmark/build/reports/jmh/profiler-cleaned.txt +(using https://github.com/brendangregg/FlameGraph) +./flamegraph.pl --color=java dd-java-agent/benchmark/build/reports/jmh/profiler-cleaned.txt > dd-java-agent/benchmark/build/reports/jmh/jmh-master.svg + */ diff --git a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/ClassRetransformingBenchmark.java b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/ClassRetransformingBenchmark.java index baec44ec36..e8c8986a45 100644 --- a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/ClassRetransformingBenchmark.java +++ b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/ClassRetransformingBenchmark.java @@ -4,49 +4,17 @@ import datadog.benchmark.classes.TracedClass; import datadog.benchmark.classes.UntracedClass; import java.lang.instrument.Instrumentation; import java.lang.instrument.UnmodifiableClassException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.nio.file.Paths; import net.bytebuddy.agent.ByteBuddyAgent; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.TearDown; public class ClassRetransformingBenchmark { - public static final String BENCHMARK_HOME = - Paths.get(".").toAbsolutePath().normalize().toString(); - - static { - if (!BENCHMARK_HOME.endsWith("benchmark")) { - throw new IllegalArgumentException("Invalid Home directory: " + BENCHMARK_HOME); - } - } @State(Scope.Benchmark) public static class BenchmarkState { private final Instrumentation inst = ByteBuddyAgent.install(); - - @Setup - public void initializeInstrumentation() { - // loading TracedClass will initialize helper injection - TracedClass.class.getName(); - } - - @TearDown - public void stopAgent() { - try { - final Class gt = Class.forName("io.opentracing.util.GlobalTracer"); - final Field tracerField = gt.getDeclaredField("tracer"); - tracerField.setAccessible(true); - final Object tracer = tracerField.get(null); - final Method close = tracer.getClass().getMethod("close"); - close.invoke(tracer); - } catch (final Exception e) { - } - } } @Benchmark @@ -60,54 +28,11 @@ public class ClassRetransformingBenchmark { state.inst.retransformClasses(TracedClass.class); } - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.2.jar") - public static class WithAgent022 extends ClassRetransformingBenchmark {} + @Fork(jvmArgsAppend = "-javaagent:/path/to/dd-java-agent-master.jar") + public static class WithAgentMaster extends ClassRetransformingBenchmark {} - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.4.jar") - public static class WithAgent024 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.6.jar") - public static class WithAgent026 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.7.jar") - public static class WithAgent027 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.8.jar") - public static class WithAgent028 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.9.jar") - public static class WithAgent029 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.10.jar") - public static class WithAgent0210 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.11.jar") - public static class WithAgent0211 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.2.12.jar") - public static class WithAgent0212 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.3.0.jar") - public static class WithAgent030 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.3.1.jar") - public static class WithAgent031 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.3.2.jar") - public static class WithAgent032 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.3.3.jar") - public static class WithAgent033 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.4.0.jar") - public static class WithAgent040 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.4.1.jar") - public static class WithAgent041 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:releases/dd-java-agent-0.5.0.jar") - public static class WithAgent050 extends ClassRetransformingBenchmark {} - - @Fork(jvmArgsAppend = "-javaagent:../build/libs/dd-java-agent.jar") + @Fork( + jvmArgsAppend = + "-javaagent:/path/to/dd-trace-java/dd-java-agent/build/libs/dd-java-agent.jar") public static class WithAgent extends ClassRetransformingBenchmark {} } diff --git a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/C.java b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/C.java index d124f05c42..b7a256697c 100644 --- a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/C.java +++ b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/C.java @@ -1,5 +1,5 @@ package datadog.benchmark.classes; -public interface C extends B { +public interface C extends A, B { void c(); } diff --git a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/D.java b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/D.java index ea8ffba11a..a52a49aa62 100644 --- a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/D.java +++ b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/D.java @@ -1,5 +1,5 @@ package datadog.benchmark.classes; -public interface D extends C { +public interface D extends A, B, C { void d(); } diff --git a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/E.java b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/E.java index 3ac6694578..9846b8802c 100644 --- a/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/E.java +++ b/dd-java-agent/benchmark/src/jmh/java/datadog/benchmark/classes/E.java @@ -1,5 +1,5 @@ package datadog.benchmark.classes; -public interface E extends D { +public interface E extends B, C, D { void e(); } diff --git a/dd-java-agent/benchmark/src/jmh/resources/dd-trace.yaml b/dd-java-agent/benchmark/src/jmh/resources/dd-trace.yaml deleted file mode 100644 index 22d9698b6f..0000000000 --- a/dd-java-agent/benchmark/src/jmh/resources/dd-trace.yaml +++ /dev/null @@ -1 +0,0 @@ -enableCustomAnnotationTracingOver: ["datadog.benchmark"] diff --git a/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerDecorator.java b/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerDecorator.java index 5d243d5f03..8d5ca93908 100644 --- a/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/akka-http-10.0/src/main/java/datadog/trace/instrumentation/akkahttp/AkkaHttpServerDecorator.java @@ -30,11 +30,6 @@ public class AkkaHttpServerDecorator return new URI(httpRequest.uri().toString()); } - @Override - protected String peerHostname(final HttpRequest httpRequest) { - return null; - } - @Override protected String peerHostIP(final HttpRequest httpRequest) { return null; diff --git a/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java b/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java index e1c57b4ea0..895ae79312 100644 --- a/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java +++ b/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpAsyncClientInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.apachehttpasyncclient; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; @@ -40,7 +40,7 @@ public class ApacheHttpAsyncClientInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("org.apache.http.nio.client.HttpAsyncClient")); + return implementsInterface(named("org.apache.http.nio.client.HttpAsyncClient")); } @Override diff --git a/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpClientRedirectInstrumentation.java b/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpClientRedirectInstrumentation.java index e61ff4a7a3..80590495f6 100644 --- a/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpClientRedirectInstrumentation.java +++ b/dd-java-agent/instrumentation/apache-httpasyncclient-4/src/main/java/datadog/trace/instrumentation/apachehttpasyncclient/ApacheHttpClientRedirectInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.apachehttpasyncclient; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -31,7 +31,7 @@ public class ApacheHttpClientRedirectInstrumentation extends Instrumenter.Defaul @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("org.apache.http.client.RedirectStrategy")); + return implementsInterface(named("org.apache.http.client.RedirectStrategy")); } @Override diff --git a/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java b/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java index d5fe205521..a31f2de4b7 100644 --- a/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java +++ b/dd-java-agent/instrumentation/apache-httpclient-4/src/main/java/datadog/trace/instrumentation/apachehttpclient/ApacheHttpClientInstrumentation.java @@ -1,13 +1,12 @@ package datadog.trace.instrumentation.apachehttpclient; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.apachehttpclient.ApacheHttpClientDecorator.DECORATE; import static datadog.trace.instrumentation.apachehttpclient.HttpHeadersInjectAdapter.SETTER; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; @@ -44,7 +43,7 @@ public class ApacheHttpClientInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.apache.http.client.HttpClient"))); + return implementsInterface(named("org.apache.http.client.HttpClient")); } @Override diff --git a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java index f276b16b20..e7ef390923 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-1.11.0/src/main/java/datadog/trace/instrumentation/aws/v0/AwsSdkClientDecorator.java @@ -9,7 +9,6 @@ import datadog.trace.api.DDTags; import datadog.trace.bootstrap.ContextStore; import datadog.trace.bootstrap.instrumentation.api.AgentSpan; import java.net.URI; -import java.net.URISyntaxException; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -102,8 +101,8 @@ public class AwsSdkClientDecorator extends HttpClientDecorator typeMatcher() { - return safeHasSuperType(named("com.amazonaws.AmazonWebServiceRequest")); + return nameStartsWith("com.amazonaws.") + .and(extendsClass(named("com.amazonaws.AmazonWebServiceRequest"))); } @Override diff --git a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsClientInstrumentation.java b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsClientInstrumentation.java index 1c4f2abfda..77a1c6ec15 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsClientInstrumentation.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsClientInstrumentation.java @@ -1,12 +1,11 @@ package datadog.trace.instrumentation.aws.v2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -23,8 +22,10 @@ public final class AwsClientInstrumentation extends AbstractAwsClientInstrumenta @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("software.amazon.awssdk.core.client.builder.SdkClientBuilder")) - .and(not(isInterface())); + return nameStartsWith("software.amazon.awssdk.") + .and( + implementsInterface( + named("software.amazon.awssdk.core.client.builder.SdkClientBuilder"))); } @Override diff --git a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsHttpClientInstrumentation.java b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsHttpClientInstrumentation.java index a2a2ca7682..873e2cf877 100644 --- a/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsHttpClientInstrumentation.java +++ b/dd-java-agent/instrumentation/aws-java-sdk-2.2/src/main/java/datadog/trace/instrumentation/aws/v2/AwsHttpClientInstrumentation.java @@ -1,12 +1,11 @@ package datadog.trace.instrumentation.aws.v2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -28,12 +27,14 @@ public final class AwsHttpClientInstrumentation extends AbstractAwsClientInstrum @Override public ElementMatcher typeMatcher() { - return safeHasSuperType( - named("software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage") - .or( - named( - "software.amazon.awssdk.core.internal.http.pipeline.stages.MakeAsyncHttpRequestStage"))) - .and(not(isInterface())); + return nameStartsWith("software.amazon.awssdk.") + .and( + extendsClass( + named( + "software.amazon.awssdk.core.internal.http.pipeline.stages.MakeHttpRequestStage") + .or( + named( + "software.amazon.awssdk.core.internal.http.pipeline.stages.MakeAsyncHttpRequestStage")))); } @Override diff --git a/dd-java-agent/instrumentation/cdi-1.2/src/test/groovy/CDIContainerTest.groovy b/dd-java-agent/instrumentation/cdi-1.2/src/test/groovy/CDIContainerTest.groovy index 6acb386213..f7878bd704 100644 --- a/dd-java-agent/instrumentation/cdi-1.2/src/test/groovy/CDIContainerTest.groovy +++ b/dd-java-agent/instrumentation/cdi-1.2/src/test/groovy/CDIContainerTest.groovy @@ -1,5 +1,4 @@ import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.instrumentation.TestBean import org.jboss.weld.environment.se.Weld import org.jboss.weld.environment.se.WeldContainer import org.jboss.weld.environment.se.threading.RunnableDecorator diff --git a/dd-java-agent/instrumentation/cdi-1.2/src/test/java/datadog/trace/instrumentation/TestBean.java b/dd-java-agent/instrumentation/cdi-1.2/src/test/java/TestBean.java similarity index 83% rename from dd-java-agent/instrumentation/cdi-1.2/src/test/java/datadog/trace/instrumentation/TestBean.java rename to dd-java-agent/instrumentation/cdi-1.2/src/test/java/TestBean.java index 3a7699aaa6..c68ad16a12 100644 --- a/dd-java-agent/instrumentation/cdi-1.2/src/test/java/datadog/trace/instrumentation/TestBean.java +++ b/dd-java-agent/instrumentation/cdi-1.2/src/test/java/TestBean.java @@ -1,5 +1,3 @@ -package datadog.trace.instrumentation; - public class TestBean { private String someField; diff --git a/dd-java-agent/instrumentation/classloading/classloading.gradle b/dd-java-agent/instrumentation/classloading/classloading.gradle new file mode 100644 index 0000000000..ff6901ae6f --- /dev/null +++ b/dd-java-agent/instrumentation/classloading/classloading.gradle @@ -0,0 +1 @@ +apply from: "${rootDir}/gradle/java.gradle" diff --git a/dd-java-agent/instrumentation/jboss-classloading/jboss-classloading.gradle b/dd-java-agent/instrumentation/classloading/jboss-testing/jboss-testing.gradle similarity index 68% rename from dd-java-agent/instrumentation/jboss-classloading/jboss-classloading.gradle rename to dd-java-agent/instrumentation/classloading/jboss-testing/jboss-testing.gradle index a1b94dd789..d5d8e92c0e 100644 --- a/dd-java-agent/instrumentation/jboss-classloading/jboss-classloading.gradle +++ b/dd-java-agent/instrumentation/classloading/jboss-testing/jboss-testing.gradle @@ -1,5 +1,7 @@ apply from: "${rootDir}/gradle/java.gradle" dependencies { + testCompile project(':dd-java-agent:instrumentation:classloading') + testCompile group: 'org.jboss.modules', name: 'jboss-modules', version: '1.3.10.Final' } diff --git a/dd-java-agent/instrumentation/classloading/jboss-testing/src/test/groovy/JBossClassloadingTest.groovy b/dd-java-agent/instrumentation/classloading/jboss-testing/src/test/groovy/JBossClassloadingTest.groovy new file mode 100644 index 0000000000..29f7b4de90 --- /dev/null +++ b/dd-java-agent/instrumentation/classloading/jboss-testing/src/test/groovy/JBossClassloadingTest.groovy @@ -0,0 +1,34 @@ +import datadog.trace.agent.test.AgentTestRunner +import org.jboss.modules.ModuleFinder +import org.jboss.modules.ModuleIdentifier +import org.jboss.modules.ModuleLoadException +import org.jboss.modules.ModuleLoader +import org.jboss.modules.ModuleSpec + +class JBossClassloadingTest extends AgentTestRunner { + def "delegates to bootstrap class loader for agent classes"() { + setup: + def moduleFinders = new ModuleFinder[1] + moduleFinders[0] = new ModuleFinder() { + @Override + ModuleSpec findModule(ModuleIdentifier identifier, ModuleLoader delegateLoader) throws ModuleLoadException { + return ModuleSpec.build(identifier).create() + } + } + def moduleLoader = new ModuleLoader(moduleFinders) + def moduleId = ModuleIdentifier.fromString("test") + def testModule = moduleLoader.loadModule(moduleId) + def classLoader = testModule.getClassLoader() + + when: + Class clazz + try { + clazz = Class.forName("datadog.trace.api.GlobalTracer", false, classLoader) + } catch (ClassNotFoundException e) { + } + + then: + assert clazz != null + assert clazz.getClassLoader() == null + } +} diff --git a/dd-java-agent/instrumentation/osgi-classloading/osgi-classloading.gradle b/dd-java-agent/instrumentation/classloading/osgi-testing/osgi-testing.gradle similarity index 88% rename from dd-java-agent/instrumentation/osgi-classloading/osgi-classloading.gradle rename to dd-java-agent/instrumentation/classloading/osgi-testing/osgi-testing.gradle index 29121dabb1..84e8719195 100644 --- a/dd-java-agent/instrumentation/osgi-classloading/osgi-classloading.gradle +++ b/dd-java-agent/instrumentation/classloading/osgi-testing/osgi-testing.gradle @@ -1,6 +1,7 @@ apply from: "${rootDir}/gradle/java.gradle" dependencies { + testCompile project(':dd-java-agent:instrumentation:classloading') // TODO: we should separate core and Eclipse tests at some point, // but right now core-specific tests are quite dump and are run with diff --git a/dd-java-agent/instrumentation/classloading/osgi-testing/src/test/groovy/OSGIClassloadingTest.groovy b/dd-java-agent/instrumentation/classloading/osgi-testing/src/test/groovy/OSGIClassloadingTest.groovy new file mode 100644 index 0000000000..6613655c04 --- /dev/null +++ b/dd-java-agent/instrumentation/classloading/osgi-testing/src/test/groovy/OSGIClassloadingTest.groovy @@ -0,0 +1,68 @@ +import datadog.trace.agent.test.AgentTestRunner +import org.apache.felix.framework.BundleWiringImpl +import org.eclipse.osgi.internal.debug.Debug +import org.eclipse.osgi.internal.framework.EquinoxConfiguration +import org.eclipse.osgi.internal.loader.BundleLoader +import org.eclipse.osgi.internal.loader.ModuleClassLoader +import org.eclipse.osgi.internal.loader.classpath.ClasspathManager +import org.eclipse.osgi.storage.BundleInfo + +class OSGIClassloadingTest extends AgentTestRunner { + def "OSGI delegates to bootstrap class loader for agent classes"() { + when: + def clazz + if (args == 1) { + clazz = loader.loadClass("datadog.trace.api.GlobalTracer") + } else { + clazz = loader.loadClass("datadog.trace.api.GlobalTracer", false) + } + + then: + assert clazz != null + assert clazz.getClassLoader() == null + + where: + loader | args + new TestClassLoader() | 1 + new TestClassLoader() | 2 + new BundleWiringImpl.BundleClassLoader(null, null, null) | 1 + new BundleWiringImpl.BundleClassLoader(null, null, null) | 2 + } + + static class TestClassLoader extends ModuleClassLoader { + + TestClassLoader() { + super(null) + } + + @Override + protected BundleInfo.Generation getGeneration() { + return null + } + + @Override + protected Debug getDebug() { + return null + } + + @Override + ClasspathManager getClasspathManager() { + return null + } + + @Override + protected EquinoxConfiguration getConfiguration() { + return null + } + + @Override + BundleLoader getBundleLoader() { + return null + } + + @Override + boolean isRegisteredAsParallel() { + return false + } + } +} diff --git a/dd-java-agent/instrumentation/classloading/src/main/java/datadog/trace/instrumentation/classloading/ClassloadingInstrumentation.java b/dd-java-agent/instrumentation/classloading/src/main/java/datadog/trace/instrumentation/classloading/ClassloadingInstrumentation.java new file mode 100644 index 0000000000..0078c2bd2e --- /dev/null +++ b/dd-java-agent/instrumentation/classloading/src/main/java/datadog/trace/instrumentation/classloading/ClassloadingInstrumentation.java @@ -0,0 +1,105 @@ +package datadog.trace.instrumentation.classloading; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isProtected; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.isStatic; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.not; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Constants; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.bootstrap.CallDepthThreadLocalMap; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +/* + * Some class loaders do not delegate to their parent, so classes in those class loaders + * will not be able to see classes in the bootstrap class loader. + * + * In particular, instrumentation on classes in those class loaders will not be able to see + * the shaded OpenTelemetry API classes in the bootstrap class loader. + * + * This instrumentation forces all class loaders to delegate to the bootstrap class loader + * for the classes that we have put in the bootstrap class loader. + */ +@AutoService(Instrumenter.class) +public final class ClassloadingInstrumentation extends Instrumenter.Default { + public ClassloadingInstrumentation() { + super("classloading"); + } + + @Override + public ElementMatcher typeMatcher() { + // just an optimization to exclude common class loaders that are known to delegate to the + // bootstrap loader (or happen to _be_ the bootstrap loader) + return not(named("java.lang.ClassLoader")) + .and(not(named("com.ibm.oti.vm.BootstrapClassLoader"))) + .and(not(named("datadog.trace.bootstrap.AgentClassLoader"))) + .and(extendsClass(named("java.lang.ClassLoader"))); + } + + @Override + public String[] helperClassNames() { + return new String[] {Constants.class.getName()}; + } + + @Override + public Map, String> transformers() { + return singletonMap( + isMethod() + .and(named("loadClass")) + .and( + takesArguments(1) + .and(takesArgument(0, named("java.lang.String"))) + .or( + takesArguments(2) + .and(takesArgument(0, named("java.lang.String"))) + .and(takesArgument(1, named("boolean"))))) + .and(isPublic().or(isProtected())) + .and(not(isStatic())), + ClassloadingInstrumentation.class.getName() + "$LoadClassAdvice"); + } + + public static class LoadClassAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class) + public static Class onEnter( + @Advice.Argument(0) final String name, @Advice.Local("_callDepth") int callDepth) { + callDepth = CallDepthThreadLocalMap.incrementCallDepth(ClassLoader.class); + if (callDepth > 0) { + return null; + } + for (final String prefix : Constants.BOOTSTRAP_PACKAGE_PREFIXES) { + if (name.startsWith(prefix)) { + try { + return Class.forName(name, false, null); + } catch (final ClassNotFoundException e) { + } + } + } + return null; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class) + public static void onExit( + @Advice.Local("_callDepth") final int callDepth, + @Advice.Return(readOnly = false) Class result, + @Advice.Enter final Class resultFromBootstrapLoader) { + if (callDepth > 0) { + return; + } + CallDepthThreadLocalMap.reset(ClassLoader.class); + if (resultFromBootstrapLoader != null) { + result = resultFromBootstrapLoader; + } + } + } +} diff --git a/dd-java-agent/instrumentation/classloading/src/test/groovy/ClassloadingTest.groovy b/dd-java-agent/instrumentation/classloading/src/test/groovy/ClassloadingTest.groovy new file mode 100644 index 0000000000..c35e49c1c2 --- /dev/null +++ b/dd-java-agent/instrumentation/classloading/src/test/groovy/ClassloadingTest.groovy @@ -0,0 +1,39 @@ +import datadog.trace.agent.test.AgentTestRunner + +class ClassloadingTest extends AgentTestRunner { + def "delegates to bootstrap class loader for agent classes"() { + setup: + def classLoader = new NonDelegatingURLClassLoader() + + when: + Class clazz + try { + clazz = Class.forName("datadog.trace.api.GlobalTracer", false, classLoader) + } catch (ClassNotFoundException e) { + } + + then: + assert clazz != null + assert clazz.getClassLoader() == null + } + + static class NonDelegatingURLClassLoader extends URLClassLoader { + + NonDelegatingURLClassLoader() { + super(new URL[0]) + } + + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + synchronized (getClassLoadingLock(name)) { + Class clazz = findLoadedClass(name) + if (clazz == null) { + clazz = findClass(name) + } + if (resolve) { + resolveClass(clazz) + } + return clazz + } + } + } +} diff --git a/dd-java-agent/instrumentation/tomcat-classloading/src/test/groovy/TomcatClassloadingTest.groovy b/dd-java-agent/instrumentation/classloading/tomcat-testing/src/test/groovy/TomcatClassloadingTest.groovy similarity index 100% rename from dd-java-agent/instrumentation/tomcat-classloading/src/test/groovy/TomcatClassloadingTest.groovy rename to dd-java-agent/instrumentation/classloading/tomcat-testing/src/test/groovy/TomcatClassloadingTest.groovy diff --git a/dd-java-agent/instrumentation/tomcat-classloading/tomcat-classloading.gradle b/dd-java-agent/instrumentation/classloading/tomcat-testing/tomcat-testing.gradle similarity index 90% rename from dd-java-agent/instrumentation/tomcat-classloading/tomcat-classloading.gradle rename to dd-java-agent/instrumentation/classloading/tomcat-testing/tomcat-testing.gradle index 026ee1bf3f..2c325ca118 100644 --- a/dd-java-agent/instrumentation/tomcat-classloading/tomcat-classloading.gradle +++ b/dd-java-agent/instrumentation/classloading/tomcat-testing/tomcat-testing.gradle @@ -18,6 +18,8 @@ testSets { } dependencies { + testCompile project(':dd-java-agent:instrumentation:classloading') + //This seems to be the earliest version that has org.apache.catalina.loader.WebappClassLoaderBase //Older versions would require slightly different instrumentation. testCompile group: 'org.apache.tomcat', name: 'tomcat-catalina', version: '8.0.14' diff --git a/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseBucketInstrumentation.java b/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseBucketInstrumentation.java index 4a805b6aef..7590cc66af 100644 --- a/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseBucketInstrumentation.java +++ b/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseBucketInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.couchbase.client; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import com.couchbase.client.java.CouchbaseCluster; @@ -29,10 +27,8 @@ public class CouchbaseBucketInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and( - named("com.couchbase.client.java.bucket.DefaultAsyncBucketManager") - .or(named("com.couchbase.client.java.CouchbaseAsyncBucket"))); + return named("com.couchbase.client.java.bucket.DefaultAsyncBucketManager") + .or(named("com.couchbase.client.java.CouchbaseAsyncBucket")); } @Override @@ -64,7 +60,7 @@ public class CouchbaseBucketInstrumentation extends Instrumenter.Default { return CallDepthThreadLocalMap.incrementCallDepth(CouchbaseCluster.class); } - @Advice.OnMethodExit + @Advice.OnMethodExit(onThrowable = Throwable.class) public static void subscribeResult( @Advice.Enter final int callDepth, @Advice.Origin final Method method, diff --git a/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClusterInstrumentation.java b/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClusterInstrumentation.java index 0af4109ec6..ae4ed86473 100644 --- a/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClusterInstrumentation.java +++ b/dd-java-agent/instrumentation/couchbase-2.0/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseClusterInstrumentation.java @@ -1,7 +1,6 @@ package datadog.trace.instrumentation.couchbase.client; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -29,10 +28,8 @@ public class CouchbaseClusterInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and( - named("com.couchbase.client.java.cluster.DefaultAsyncClusterManager") - .or(named("com.couchbase.client.java.CouchbaseAsyncCluster"))); + return named("com.couchbase.client.java.cluster.DefaultAsyncClusterManager") + .or(named("com.couchbase.client.java.CouchbaseAsyncCluster")); } @Override @@ -64,7 +61,7 @@ public class CouchbaseClusterInstrumentation extends Instrumenter.Default { return CallDepthThreadLocalMap.incrementCallDepth(CouchbaseCluster.class); } - @Advice.OnMethodExit + @Advice.OnMethodExit(onThrowable = Throwable.class) public static void subscribeResult( @Advice.Enter final int callDepth, @Advice.Origin final Method method, diff --git a/dd-java-agent/instrumentation/couchbase-2.6/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseNetworkInstrumentation.java b/dd-java-agent/instrumentation/couchbase-2.6/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseNetworkInstrumentation.java index 926b8b1931..09b9b1f3ae 100644 --- a/dd-java-agent/instrumentation/couchbase-2.6/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseNetworkInstrumentation.java +++ b/dd-java-agent/instrumentation/couchbase-2.6/src/main/java/datadog/trace/instrumentation/couchbase/client/CouchbaseNetworkInstrumentation.java @@ -1,8 +1,9 @@ package datadog.trace.instrumentation.couchbase.client; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -31,7 +32,9 @@ public class CouchbaseNetworkInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { // Exact class because private fields are used - return safeHasSuperType(named("com.couchbase.client.core.endpoint.AbstractGenericHandler")); + return nameStartsWith("com.couchbase.client.") + .and( + extendsClass(named("com.couchbase.client.core.endpoint.AbstractGenericHandler"))); } @Override diff --git a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java index 8482b92f3d..23e5411397 100644 --- a/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java +++ b/dd-java-agent/instrumentation/dropwizard/dropwizard-views/src/main/java/datadog/trace/instrumentation/dropwizard/view/DropwizardViewInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.dropwizard.view; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -34,7 +32,7 @@ public final class DropwizardViewInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("io.dropwizard.views.ViewRenderer"))); + return implementsInterface(named("io.dropwizard.views.ViewRenderer")); } @Override diff --git a/dd-java-agent/instrumentation/dropwizard/src/test/groovy/DropwizardTest.groovy b/dd-java-agent/instrumentation/dropwizard/src/test/groovy/DropwizardTest.groovy index afd65a0870..6354ba45e0 100644 --- a/dd-java-agent/instrumentation/dropwizard/src/test/groovy/DropwizardTest.groovy +++ b/dd-java-agent/instrumentation/dropwizard/src/test/groovy/DropwizardTest.groovy @@ -113,7 +113,6 @@ class DropwizardTest extends HttpServerTest typeMatcher() { - return not(isInterface()).and(named("org.elasticsearch.client.RestClient")); + return named("org.elasticsearch.client.RestClient"); } @Override diff --git a/dd-java-agent/instrumentation/elasticsearch/rest-6.4/src/main/java/datadog/trace/instrumentation/elasticsearch6_4/Elasticsearch6RestClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch/rest-6.4/src/main/java/datadog/trace/instrumentation/elasticsearch6_4/Elasticsearch6RestClientInstrumentation.java index d5060fdb08..268f3d90cd 100644 --- a/dd-java-agent/instrumentation/elasticsearch/rest-6.4/src/main/java/datadog/trace/instrumentation/elasticsearch6_4/Elasticsearch6RestClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch/rest-6.4/src/main/java/datadog/trace/instrumentation/elasticsearch6_4/Elasticsearch6RestClientInstrumentation.java @@ -4,10 +4,8 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSp import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.elasticsearch.ElasticsearchRestClientDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -43,7 +41,7 @@ public class Elasticsearch6RestClientInstrumentation extends Instrumenter.Defaul @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(named("org.elasticsearch.client.RestClient")); + return named("org.elasticsearch.client.RestClient"); } @Override diff --git a/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java index 8e18ae6157..1751e6f90b 100644 --- a/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/Elasticsearch2TransportClientInstrumentation.java @@ -4,10 +4,8 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSp import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.elasticsearch.ElasticsearchTransportClientDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,7 +33,7 @@ public class Elasticsearch2TransportClientInstrumentation extends Instrumenter.D public ElementMatcher typeMatcher() { // If we want to be more generic, we could instrument the interface instead: // .and(safeHasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + return named("org.elasticsearch.client.support.AbstractClient"); } @Override diff --git a/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/TransportActionListener.java b/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/TransportActionListener.java index fc2cc0b23d..063db70a66 100644 --- a/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/TransportActionListener.java +++ b/dd-java-agent/instrumentation/elasticsearch/transport-2/src/main/java/datadog/trace/instrumentation/elasticsearch2/TransportActionListener.java @@ -76,7 +76,7 @@ public class TransportActionListener implements Action if (response instanceof BaseNodesResponse) { final BaseNodesResponse resp = (BaseNodesResponse) response; - if (resp.failures().length > 0) { + if (resp.failures() != null && resp.failures().length > 0) { span.setTag("elasticsearch.node.failures", resp.failures().length); } span.setTag("elasticsearch.node.cluster.name", resp.getClusterName().value()); diff --git a/dd-java-agent/instrumentation/elasticsearch/transport-2/src/test/groovy/Elasticsearch2TransportClientTest.groovy b/dd-java-agent/instrumentation/elasticsearch/transport-2/src/test/groovy/Elasticsearch2TransportClientTest.groovy index fa661385a6..68e415e212 100644 --- a/dd-java-agent/instrumentation/elasticsearch/transport-2/src/test/groovy/Elasticsearch2TransportClientTest.groovy +++ b/dd-java-agent/instrumentation/elasticsearch/transport-2/src/test/groovy/Elasticsearch2TransportClientTest.groovy @@ -4,6 +4,7 @@ import datadog.trace.agent.test.utils.PortUtils import datadog.trace.api.DDSpanTypes import datadog.trace.bootstrap.instrumentation.api.Tags import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest +import org.elasticsearch.action.admin.cluster.stats.ClusterStatsRequest import org.elasticsearch.client.transport.TransportClient import org.elasticsearch.common.io.FileSystemUtils import org.elasticsearch.common.settings.Settings @@ -104,6 +105,41 @@ class Elasticsearch2TransportClientTest extends AgentTestRunner { } } + def "test elasticsearch stats"() { + setup: + def result = client.admin().cluster().clusterStats(new ClusterStatsRequest(new String[0])) + + def status = result.get().status + def failures = result.get().failures() + + expect: + status.name() == "GREEN" + failures == null + + assertTraces(1) { + trace(0, 1) { + span(0) { + serviceName "elasticsearch" + resourceName "ClusterStatsAction" + operationName "elasticsearch.query" + spanType DDSpanTypes.ELASTICSEARCH + tags { + "$Tags.COMPONENT" "elasticsearch-java" + "$Tags.SPAN_KIND" Tags.SPAN_KIND_CLIENT + "$Tags.PEER_HOSTNAME" "127.0.0.1" + "$Tags.PEER_HOST_IPV4" "127.0.0.1" + "$Tags.PEER_PORT" tcpPort + "$Tags.DB_TYPE" "elasticsearch" + "elasticsearch.action" "ClusterStatsAction" + "elasticsearch.request" "ClusterStatsRequest" + "elasticsearch.node.cluster.name" "test-cluster" + defaultTags() + } + } + } + } + } + def "test elasticsearch error"() { when: client.prepareGet(indexName, indexType, id).get() diff --git a/dd-java-agent/instrumentation/elasticsearch/transport-5.3/src/main/java/datadog/trace/instrumentation/elasticsearch5_3/Elasticsearch53TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch/transport-5.3/src/main/java/datadog/trace/instrumentation/elasticsearch5_3/Elasticsearch53TransportClientInstrumentation.java index a4715a6388..08df25f90d 100644 --- a/dd-java-agent/instrumentation/elasticsearch/transport-5.3/src/main/java/datadog/trace/instrumentation/elasticsearch5_3/Elasticsearch53TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch/transport-5.3/src/main/java/datadog/trace/instrumentation/elasticsearch5_3/Elasticsearch53TransportClientInstrumentation.java @@ -4,10 +4,8 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSp import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.elasticsearch.ElasticsearchTransportClientDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -36,7 +34,7 @@ public class Elasticsearch53TransportClientInstrumentation extends Instrumenter. public ElementMatcher typeMatcher() { // If we want to be more generic, we could instrument the interface instead: // .and(safeHasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + return named("org.elasticsearch.client.support.AbstractClient"); } @Override diff --git a/dd-java-agent/instrumentation/elasticsearch/transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch/transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java index 69165b71bf..f72087d5b9 100644 --- a/dd-java-agent/instrumentation/elasticsearch/transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch/transport-5/src/main/java/datadog/trace/instrumentation/elasticsearch5/Elasticsearch5TransportClientInstrumentation.java @@ -4,10 +4,8 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSp import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.elasticsearch.ElasticsearchTransportClientDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,7 +33,7 @@ public class Elasticsearch5TransportClientInstrumentation extends Instrumenter.D public ElementMatcher typeMatcher() { // If we want to be more generic, we could instrument the interface instead: // .and(safeHasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + return named("org.elasticsearch.client.support.AbstractClient"); } @Override diff --git a/dd-java-agent/instrumentation/elasticsearch/transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java b/dd-java-agent/instrumentation/elasticsearch/transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java index 399629348e..39ff74cf6f 100644 --- a/dd-java-agent/instrumentation/elasticsearch/transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java +++ b/dd-java-agent/instrumentation/elasticsearch/transport-6/src/main/java/datadog/trace/instrumentation/elasticsearch6/Elasticsearch6TransportClientInstrumentation.java @@ -4,10 +4,8 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSp import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.elasticsearch.ElasticsearchTransportClientDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -39,7 +37,7 @@ public class Elasticsearch6TransportClientInstrumentation extends Instrumenter.D public ElementMatcher typeMatcher() { // If we want to be more generic, we could instrument the interface instead: // .and(safeHasSuperType(named("org.elasticsearch.client.ElasticsearchClient")))) - return not(isInterface()).and(named("org.elasticsearch.client.support.AbstractClient")); + return named("org.elasticsearch.client.support.AbstractClient"); } @Override diff --git a/dd-java-agent/instrumentation/finatra-2.9/src/main/java/datadog/trace/instrumentation/finatra/FinatraDecorator.java b/dd-java-agent/instrumentation/finatra-2.9/src/main/java/datadog/trace/instrumentation/finatra/FinatraDecorator.java index 3d8cd1d1df..7b2c4a3ec0 100644 --- a/dd-java-agent/instrumentation/finatra-2.9/src/main/java/datadog/trace/instrumentation/finatra/FinatraDecorator.java +++ b/dd-java-agent/instrumentation/finatra-2.9/src/main/java/datadog/trace/instrumentation/finatra/FinatraDecorator.java @@ -24,11 +24,6 @@ public class FinatraDecorator extends HttpServerDecorator typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("com.twitter.finatra.http.internal.routing.Route"))); + return nameStartsWith("com.twitter.finatra.") + .and( + extendsClass(named("com.twitter.finatra.http.internal.routing.Route"))); } @Override diff --git a/dd-java-agent/instrumentation/glassfish/src/test/groovy/GlassFishServerTest.groovy b/dd-java-agent/instrumentation/glassfish/src/test/groovy/GlassFishServerTest.groovy index 278a491951..9f3dfcd6a8 100644 --- a/dd-java-agent/instrumentation/glassfish/src/test/groovy/GlassFishServerTest.groovy +++ b/dd-java-agent/instrumentation/glassfish/src/test/groovy/GlassFishServerTest.groovy @@ -103,7 +103,6 @@ class GlassFishServerTest extends HttpServerTest { tags { "$Tags.COMPONENT" serverDecorator.component() "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" { it == "localhost" || it == "127.0.0.1" } "$Tags.PEER_HOST_IPV4" { it == null || it == "127.0.0.1" } // Optional "$Tags.PEER_PORT" Integer "$Tags.HTTP_STATUS" endpoint.status diff --git a/dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java b/dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java index e5f6cca8dd..06435196cf 100644 --- a/dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java +++ b/dd-java-agent/instrumentation/grizzly-2/src/main/java/datadog/trace/instrumentation/grizzly/GrizzlyDecorator.java @@ -26,11 +26,6 @@ public class GrizzlyDecorator extends HttpServerDecorator typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.Criteria"))); + return implementsInterface(named("org.hibernate.Criteria")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/QueryInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/QueryInstrumentation.java index e1709299a7..5341ef6f9d 100644 --- a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/QueryInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/QueryInstrumentation.java @@ -1,12 +1,10 @@ package datadog.trace.instrumentation.hibernate.core.v3_3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.instrumentation.hibernate.HibernateDecorator.DECORATOR; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -33,7 +31,7 @@ public class QueryInstrumentation extends AbstractHibernateInstrumentation { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.Query"))); + return implementsInterface(named("org.hibernate.Query")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionFactoryInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionFactoryInstrumentation.java index 372c535ad3..de73a83749 100644 --- a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionFactoryInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionFactoryInstrumentation.java @@ -1,13 +1,12 @@ package datadog.trace.instrumentation.hibernate.core.v3_3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.hibernate.HibernateDecorator.DECORATOR; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -40,7 +39,7 @@ public class SessionFactoryInstrumentation extends AbstractHibernateInstrumentat @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.SessionFactory"))); + return implementsInterface(named("org.hibernate.SessionFactory")); } @Override @@ -53,7 +52,7 @@ public class SessionFactoryInstrumentation extends AbstractHibernateInstrumentat returns( named("org.hibernate.Session") .or(named("org.hibernate.StatelessSession")) - .or(safeHasSuperType(named("org.hibernate.Session"))))), + .or(hasInterface(named("org.hibernate.Session"))))), SessionFactoryInstrumentation.class.getName() + "$SessionFactoryAdvice"); } diff --git a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionInstrumentation.java index 81dc036813..1605ec86f0 100644 --- a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/SessionInstrumentation.java @@ -1,12 +1,11 @@ package datadog.trace.instrumentation.hibernate.core.v3_3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.instrumentation.hibernate.HibernateDecorator.DECORATOR; import static datadog.trace.instrumentation.hibernate.SessionMethodUtils.SCOPE_ONLY_METHODS; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -48,10 +47,8 @@ public class SessionInstrumentation extends AbstractHibernateInstrumentation { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and( - safeHasSuperType( - named("org.hibernate.Session").or(named("org.hibernate.StatelessSession")))); + return implementsInterface( + named("org.hibernate.Session").or(named("org.hibernate.StatelessSession"))); } @Override @@ -99,11 +96,11 @@ public class SessionInstrumentation extends AbstractHibernateInstrumentation { SessionInstrumentation.class.getName() + "$GetTransactionAdvice"); transformers.put( - isMethod().and(returns(safeHasSuperType(named("org.hibernate.Query")))), + isMethod().and(returns(hasInterface(named("org.hibernate.Query")))), SessionInstrumentation.class.getName() + "$GetQueryAdvice"); transformers.put( - isMethod().and(returns(safeHasSuperType(named("org.hibernate.Criteria")))), + isMethod().and(returns(hasInterface(named("org.hibernate.Criteria")))), SessionInstrumentation.class.getName() + "$GetCriteriaAdvice"); return transformers; diff --git a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/TransactionInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/TransactionInstrumentation.java index d6ab703337..a0740d004f 100644 --- a/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/TransactionInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-3.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v3_3/TransactionInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.hibernate.core.v3_3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; @@ -31,7 +29,7 @@ public class TransactionInstrumentation extends AbstractHibernateInstrumentation @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.Transaction"))); + return implementsInterface(named("org.hibernate.Transaction")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/CriteriaInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/CriteriaInstrumentation.java index d1d2b00c23..b2502bfab0 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/CriteriaInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/CriteriaInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.hibernate.core.v4_0; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -31,7 +29,7 @@ public class CriteriaInstrumentation extends AbstractHibernateInstrumentation { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.Criteria"))); + return implementsInterface(named("org.hibernate.Criteria")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/QueryInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/QueryInstrumentation.java index 9e2087a530..9d1192ccd5 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/QueryInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/QueryInstrumentation.java @@ -1,12 +1,10 @@ package datadog.trace.instrumentation.hibernate.core.v4_0; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.instrumentation.hibernate.HibernateDecorator.DECORATOR; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -33,7 +31,7 @@ public class QueryInstrumentation extends AbstractHibernateInstrumentation { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.Query"))); + return implementsInterface(named("org.hibernate.Query")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionFactoryInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionFactoryInstrumentation.java index be6c4cb8a0..fc35d6cdaa 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionFactoryInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionFactoryInstrumentation.java @@ -1,13 +1,11 @@ package datadog.trace.instrumentation.hibernate.core.v4_0; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.hibernate.HibernateDecorator.DECORATOR; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -34,7 +32,7 @@ public class SessionFactoryInstrumentation extends AbstractHibernateInstrumentat @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.SessionFactory"))); + return implementsInterface(named("org.hibernate.SessionFactory")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionInstrumentation.java index 2fb7cee33c..f1d615d19a 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/SessionInstrumentation.java @@ -1,12 +1,11 @@ package datadog.trace.instrumentation.hibernate.core.v4_0; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.instrumentation.hibernate.HibernateDecorator.DECORATOR; import static datadog.trace.instrumentation.hibernate.SessionMethodUtils.SCOPE_ONLY_METHODS; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -46,7 +45,7 @@ public class SessionInstrumentation extends AbstractHibernateInstrumentation { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.SharedSessionContract"))); + return implementsInterface(named("org.hibernate.SharedSessionContract")); } @Override @@ -93,11 +92,11 @@ public class SessionInstrumentation extends AbstractHibernateInstrumentation { SessionInstrumentation.class.getName() + "$GetTransactionAdvice"); transformers.put( - isMethod().and(returns(safeHasSuperType(named("org.hibernate.Query")))), + isMethod().and(returns(hasInterface(named("org.hibernate.Query")))), SessionInstrumentation.class.getName() + "$GetQueryAdvice"); transformers.put( - isMethod().and(returns(safeHasSuperType(named("org.hibernate.Criteria")))), + isMethod().and(returns(hasInterface(named("org.hibernate.Criteria")))), SessionInstrumentation.class.getName() + "$GetCriteriaAdvice"); return transformers; diff --git a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/TransactionInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/TransactionInstrumentation.java index 2d2898f4f2..b2277e6c0b 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/TransactionInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.0/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_0/TransactionInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.hibernate.core.v4_0; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; @@ -31,7 +29,7 @@ public class TransactionInstrumentation extends AbstractHibernateInstrumentation @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.Transaction"))); + return implementsInterface(named("org.hibernate.Transaction")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/ProcedureCallInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/ProcedureCallInstrumentation.java index bb1007628f..6831e9aecf 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/ProcedureCallInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/ProcedureCallInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.hibernate.core.v4_3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -47,7 +45,7 @@ public class ProcedureCallInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.procedure.ProcedureCall"))); + return implementsInterface(named("org.hibernate.procedure.ProcedureCall")); } @Override diff --git a/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/SessionInstrumentation.java b/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/SessionInstrumentation.java index 70ff431051..058409fca5 100644 --- a/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/SessionInstrumentation.java +++ b/dd-java-agent/instrumentation/hibernate/core-4.3/src/main/java/datadog/trace/instrumentation/hibernate/core/v4_3/SessionInstrumentation.java @@ -1,10 +1,9 @@ package datadog.trace.instrumentation.hibernate.core.v4_3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; @@ -53,7 +52,7 @@ public class SessionInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("org.hibernate.SharedSessionContract"))); + return implementsInterface(named("org.hibernate.SharedSessionContract")); } @Override @@ -61,7 +60,7 @@ public class SessionInstrumentation extends Instrumenter.Default { final Map, String> transformers = new HashMap<>(); transformers.put( - isMethod().and(returns(safeHasSuperType(named("org.hibernate.procedure.ProcedureCall")))), + isMethod().and(returns(hasInterface(named("org.hibernate.procedure.ProcedureCall")))), SessionInstrumentation.class.getName() + "$GetProcedureCallAdvice"); return transformers; diff --git a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java index 50b749f3cb..0c160dbdb6 100644 --- a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/HttpUrlConnectionInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.http_url_connection; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; @@ -9,6 +9,7 @@ import static datadog.trace.instrumentation.http_url_connection.HttpUrlConnectio import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; @@ -25,6 +26,7 @@ import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; @AutoService(Instrumenter.class) public class HttpUrlConnectionInstrumentation extends Instrumenter.Default { @@ -35,9 +37,11 @@ public class HttpUrlConnectionInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("java.net.HttpURLConnection")) + return nameStartsWith("java.net.") + .or(ElementMatchers.nameStartsWith("sun.net")) // This class is a simple delegator. Skip because it does not update its `connected` field. - .and(not(named("sun.net.www.protocol.https.HttpsURLConnectionImpl"))); + .and(not(named("sun.net.www.protocol.https.HttpsURLConnectionImpl"))) + .and(extendsClass(named("java.net.HttpURLConnection"))); } @Override diff --git a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java index 83b9af779a..68ea254f58 100644 --- a/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java +++ b/dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java @@ -3,7 +3,10 @@ package datadog.trace.instrumentation.http_url_connection; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.*; +import static net.bytebuddy.matcher.ElementMatchers.is; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; diff --git a/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixInstrumentation.java b/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixInstrumentation.java index a0a5fec253..7629cc09ad 100644 --- a/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixInstrumentation.java +++ b/dd-java-agent/instrumentation/hystrix-1.4/src/main/java/datadog/trace/instrumentation/hystrix/HystrixInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.hystrix; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.instrumentation.hystrix.HystrixDecorator.DECORATE; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; @@ -29,7 +29,7 @@ public class HystrixInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType( + return extendsClass( named("com.netflix.hystrix.HystrixCommand") .or(named("com.netflix.hystrix.HystrixObservableCommand"))); } diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AbstractExecutorInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AbstractExecutorInstrumentation.java index 69a9a7ee37..35a22ef76a 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AbstractExecutorInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AbstractExecutorInstrumentation.java @@ -1,9 +1,8 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; +import static net.bytebuddy.matcher.ElementMatchers.any; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.api.Config; @@ -102,33 +101,37 @@ public abstract class AbstractExecutorInstrumentation extends Instrumenter.Defau @Override public ElementMatcher typeMatcher() { - final ElementMatcher.Junction matcher = - not(isInterface()).and(safeHasSuperType(named(Executor.class.getName()))); - if (TRACE_ALL_EXECUTORS) { - return matcher; - } - return matcher.and( - new ElementMatcher() { - @Override - public boolean matches(final TypeDescription target) { - boolean whitelisted = WHITELISTED_EXECUTORS.contains(target.getName()); + ElementMatcher.Junction matcher = any(); + final ElementMatcher.Junction hasExecutorInterfaceMatcher = + implementsInterface(named(Executor.class.getName())); + if (!TRACE_ALL_EXECUTORS) { + matcher = + matcher.and( + new ElementMatcher() { + @Override + public boolean matches(final TypeDescription target) { + boolean whitelisted = WHITELISTED_EXECUTORS.contains(target.getName()); - // Check for possible prefixes match only if not whitelisted already - if (!whitelisted) { - for (final String name : WHITELISTED_EXECUTORS_PREFIXES) { - if (target.getName().startsWith(name)) { - whitelisted = true; - break; + // Check for possible prefixes match only if not whitelisted already + if (!whitelisted) { + for (final String name : WHITELISTED_EXECUTORS_PREFIXES) { + if (target.getName().startsWith(name)) { + whitelisted = true; + break; + } + } + } + + if (!whitelisted + && log.isDebugEnabled() + && hasExecutorInterfaceMatcher.matches(target)) { + log.debug("Skipping executor instrumentation for {}", target.getName()); + } + return whitelisted; } - } - } - - if (!whitelisted) { - log.debug("Skipping executor instrumentation for {}", target.getName()); - } - return whitelisted; - } - }); + }); + } + return matcher.and(hasExecutorInterfaceMatcher); // Apply expensive matcher last. } @Override diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AkkaForkJoinTaskInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AkkaForkJoinTaskInstrumentation.java index b87aaa5d87..f17b2a4682 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AkkaForkJoinTaskInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AkkaForkJoinTaskInstrumentation.java @@ -1,9 +1,8 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -44,7 +43,7 @@ public final class AkkaForkJoinTaskInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named(TASK_CLASS_NAME))); + return extendsClass(named(TASK_CLASS_NAME)); } @Override diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AsyncPropagatingDisableInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AsyncPropagatingDisableInstrumentation.java index 6549682c55..d759a6224a 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AsyncPropagatingDisableInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/AsyncPropagatingDisableInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.noopSpan; @@ -36,7 +36,7 @@ public final class AsyncPropagatingDisableInstrumentation implements Instrumente new ImmutableMap.Builder< ElementMatcher, ElementMatcher>() - .put(safeHasSuperType(named("rx.Scheduler$Worker")), named("schedulePeriodically")) + .put(extendsClass(named("rx.Scheduler$Worker")), named("schedulePeriodically")) .build(); @Override diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java index cb1ca1406e..fb43119ffd 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/FutureInstrumentation.java @@ -1,10 +1,8 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import com.google.auto.service.AutoService; @@ -78,19 +76,18 @@ public final class FutureInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named(Future.class.getName()))) - .and( - new ElementMatcher() { - @Override - public boolean matches(final TypeDescription target) { - final boolean whitelisted = WHITELISTED_FUTURES.contains(target.getName()); - if (!whitelisted) { - log.debug("Skipping future instrumentation for {}", target.getName()); - } - return whitelisted; - } - }); + final ElementMatcher.Junction hasFutureInterfaceMatcher = + implementsInterface(named(Future.class.getName())); + return new ElementMatcher.Junction.AbstractBase() { + @Override + public boolean matches(final TypeDescription target) { + final boolean whitelisted = WHITELISTED_FUTURES.contains(target.getName()); + if (!whitelisted && log.isDebugEnabled() && hasFutureInterfaceMatcher.matches(target)) { + log.debug("Skipping future instrumentation for {}", target.getName()); + } + return whitelisted; + } + }.and(hasFutureInterfaceMatcher); // Apply expensive matcher last. } @Override diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/JavaForkJoinTaskInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/JavaForkJoinTaskInstrumentation.java index b075eb80ae..dd011f6511 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/JavaForkJoinTaskInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/JavaForkJoinTaskInstrumentation.java @@ -1,8 +1,7 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -41,7 +40,7 @@ public final class JavaForkJoinTaskInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named(ForkJoinTask.class.getName()))); + return extendsClass(named(ForkJoinTask.class.getName())); } @Override diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/RunnableCallableInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/RunnableCallableInstrumentation.java index 1f518d5fd6..4795056c84 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/RunnableCallableInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/RunnableCallableInstrumentation.java @@ -1,10 +1,8 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; @@ -34,8 +32,7 @@ public final class RunnableCallableInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named(Runnable.class.getName()).or(named(Callable.class.getName())))); + return implementsInterface(named(Runnable.class.getName()).or(named(Callable.class.getName()))); } @Override diff --git a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ScalaForkJoinTaskInstrumentation.java b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ScalaForkJoinTaskInstrumentation.java index 2523bdbb37..8a14235dcf 100644 --- a/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ScalaForkJoinTaskInstrumentation.java +++ b/dd-java-agent/instrumentation/java-concurrent/src/main/java/datadog/trace/instrumentation/java/concurrent/ScalaForkJoinTaskInstrumentation.java @@ -1,8 +1,7 @@ package datadog.trace.instrumentation.java.concurrent; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -43,7 +42,7 @@ public final class ScalaForkJoinTaskInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named(TASK_CLASS_NAME))); + return extendsClass(named(TASK_CLASS_NAME)); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-annotations-1/src/main/java/datadog/trace/instrumentation/jaxrs1/JaxRsAnnotationsInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-annotations-1/src/main/java/datadog/trace/instrumentation/jaxrs1/JaxRsAnnotationsInstrumentation.java index 856bab591f..1ddc8b2f27 100644 --- a/dd-java-agent/instrumentation/jax-rs-annotations-1/src/main/java/datadog/trace/instrumentation/jaxrs1/JaxRsAnnotationsInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-annotations-1/src/main/java/datadog/trace/instrumentation/jaxrs1/JaxRsAnnotationsInstrumentation.java @@ -1,8 +1,8 @@ package datadog.trace.instrumentation.jaxrs1; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.hasSuperMethod; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses; +import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasNoResources; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasSuperMethod; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; @@ -12,7 +12,6 @@ import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -37,14 +36,14 @@ public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default // this is required to make sure instrumentation won't apply to jax-rs 2 @Override public ElementMatcher classLoaderMatcher() { - return not(classLoaderHasClasses("javax.ws.rs.container.AsyncResponse")); + return classLoaderHasNoResources("javax/ws/rs/container/AsyncResponse.class"); } @Override public ElementMatcher typeMatcher() { return safeHasSuperType( isAnnotatedWith(named("javax.ws.rs.Path")) - .or(safeHasSuperType(declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path")))))); + .or(declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path"))))); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/AbstractRequestContextInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/AbstractRequestContextInstrumentation.java index 75c1df26fc..968bc72983 100644 --- a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/AbstractRequestContextInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/AbstractRequestContextInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.jaxrs2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jaxrs2.JaxRsAnnotationsDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -30,8 +28,7 @@ public abstract class AbstractRequestContextInstrumentation extends Instrumenter @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("javax.ws.rs.container.ContainerRequestContext"))); + return implementsInterface(named("javax.ws.rs.container.ContainerRequestContext")); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/ContainerRequestFilterInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/ContainerRequestFilterInstrumentation.java index 5f32319508..c2bbbf1add 100644 --- a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/ContainerRequestFilterInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/ContainerRequestFilterInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.jaxrs2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -32,8 +30,7 @@ public class ContainerRequestFilterInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("javax.ws.rs.container.ContainerRequestFilter"))); + return implementsInterface(named("javax.ws.rs.container.ContainerRequestFilter")); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAnnotationsInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAnnotationsInstrumentation.java index 86fb8030f6..30843bfa9d 100644 --- a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAnnotationsInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAnnotationsInstrumentation.java @@ -1,7 +1,7 @@ package datadog.trace.instrumentation.jaxrs2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.hasSuperMethod; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasSuperMethod; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; @@ -43,7 +43,7 @@ public final class JaxRsAnnotationsInstrumentation extends Instrumenter.Default public ElementMatcher typeMatcher() { return safeHasSuperType( isAnnotatedWith(named("javax.ws.rs.Path")) - .or(safeHasSuperType(declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path")))))); + .or(declaresMethod(isAnnotatedWith(named("javax.ws.rs.Path"))))); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAsyncResponseInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAsyncResponseInstrumentation.java index b43c92ea32..4af573b598 100644 --- a/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAsyncResponseInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-annotations-2/src/main/java/datadog/trace/instrumentation/jaxrs2/JaxRsAsyncResponseInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.jaxrs2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.instrumentation.jaxrs2.JaxRsAnnotationsDecorator.DECORATE; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -35,7 +35,7 @@ public final class JaxRsAsyncResponseInstrumentation extends Instrumenter.Defaul @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("javax.ws.rs.container.AsyncResponse")); + return implementsInterface(named("javax.ws.rs.container.AsyncResponse")); } @Override diff --git a/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Instrumentation.java b/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Instrumentation.java index 3c7d1d3246..3661800c0f 100644 --- a/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Instrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-client-1.1/src/main/java/datadog/trace/instrumentation/jaxrs/v1/JaxRsClientV1Instrumentation.java @@ -1,7 +1,8 @@ package datadog.trace.instrumentation.jaxrs.v1; import static datadog.trace.agent.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; @@ -35,7 +36,7 @@ public final class JaxRsClientV1Instrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("com.sun.jersey.api.client.ClientHandler")); + return implementsInterface(named("com.sun.jersey.api.client.ClientHandler")); } @Override @@ -53,10 +54,8 @@ public final class JaxRsClientV1Instrumentation extends Instrumenter.Default { public Map, String> transformers() { return singletonMap( named("handle") - .and( - takesArgument( - 0, safeHasSuperType(named("com.sun.jersey.api.client.ClientRequest")))) - .and(returns(safeHasSuperType(named("com.sun.jersey.api.client.ClientResponse")))), + .and(takesArgument(0, extendsClass(named("com.sun.jersey.api.client.ClientRequest")))) + .and(returns(extendsClass(named("com.sun.jersey.api.client.ClientResponse")))), JaxRsClientV1Instrumentation.class.getName() + "$HandleAdvice"); } diff --git a/dd-java-agent/instrumentation/jax-rs-client-2.0/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java b/dd-java-agent/instrumentation/jax-rs-client-2.0/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java index 19af4fe24e..fe81be3cef 100644 --- a/dd-java-agent/instrumentation/jax-rs-client-2.0/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java +++ b/dd-java-agent/instrumentation/jax-rs-client-2.0/src/main/java/datadog/trace/instrumentation/jaxrs/JaxRsClientInstrumentation.java @@ -1,6 +1,7 @@ package datadog.trace.instrumentation.jaxrs; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; @@ -24,7 +25,7 @@ public final class JaxRsClientInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("javax.ws.rs.client.ClientBuilder")); + return extendsClass(named("javax.ws.rs.client.ClientBuilder")); } @Override @@ -43,7 +44,7 @@ public final class JaxRsClientInstrumentation extends Instrumenter.Default { @Override public Map, String> transformers() { return singletonMap( - named("build").and(returns(safeHasSuperType(named("javax.ws.rs.client.Client")))), + named("build").and(returns(hasInterface(named("javax.ws.rs.client.Client")))), JaxRsClientInstrumentation.class.getName() + "$ClientBuilderAdvice"); } diff --git a/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java b/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java deleted file mode 100644 index 184726b899..0000000000 --- a/dd-java-agent/instrumentation/jboss-classloading/src/main/java/datadog/trace/instrumentation/jboss/JBossClassloadingInstrumentation.java +++ /dev/null @@ -1,54 +0,0 @@ -package datadog.trace.instrumentation.jboss; - -import static net.bytebuddy.matcher.ElementMatchers.named; - -import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.Constants; -import datadog.trace.agent.tooling.Instrumenter; -import java.security.ProtectionDomain; -import java.util.Collections; -import java.util.Map; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.utility.JavaModule; - -@AutoService(Instrumenter.class) -public final class JBossClassloadingInstrumentation extends Instrumenter.Default { - public JBossClassloadingInstrumentation() { - super("jboss-classloading"); - } - - @Override - public ElementMatcher typeMatcher() { - return named("org.jboss.modules.Module"); - } - - @Override - public void postMatch( - final TypeDescription typeDescription, - final ClassLoader classLoader, - final JavaModule module, - final Class classBeingRedefined, - final ProtectionDomain protectionDomain) { - // Set the system prop to tell jboss to delegate classloads for datadog bootstrap classes - final StringBuilder prefixes = new StringBuilder(""); - for (int i = 0; i < Constants.BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) { - if (i > 0) { - prefixes.append(","); - } - prefixes.append(Constants.BOOTSTRAP_PACKAGE_PREFIXES[i]); - } - final String existing = System.getProperty("jboss.modules.system.pkgs"); - if (null == existing) { - System.setProperty("jboss.modules.system.pkgs", prefixes.toString()); - } else if (!existing.contains(prefixes)) { - System.setProperty("jboss.modules.system.pkgs", existing + "," + prefixes.toString()); - } - } - - @Override - public Map, String> transformers() { - return Collections.emptyMap(); - } -} diff --git a/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy b/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy deleted file mode 100644 index 5de9f05779..0000000000 --- a/dd-java-agent/instrumentation/jboss-classloading/src/test/groovy/JBossClassloadingTest.groovy +++ /dev/null @@ -1,12 +0,0 @@ -import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.agent.tooling.Constants - -class JBossClassloadingTest extends AgentTestRunner { - def "delegation property set on module load"() { - setup: - org.jboss.modules.Module.getName() - - expect: - assert Arrays.asList(System.getProperty("jboss.modules.system.pkgs").split(",")).containsAll(Constants.BOOTSTRAP_PACKAGE_PREFIXES) - } -} diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java index a890cbb220..c71ba11576 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/ConnectionInstrumentation.java @@ -1,11 +1,10 @@ package datadog.trace.instrumentation.jdbc; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.hasInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -27,7 +26,7 @@ public final class ConnectionInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("java.sql.Connection"))); + return implementsInterface(named("java.sql.Connection")); } @Override @@ -43,7 +42,7 @@ public final class ConnectionInstrumentation extends Instrumenter.Default { nameStartsWith("prepare") .and(takesArgument(0, String.class)) // Also include CallableStatement, which is a sub type of PreparedStatement - .and(returns(safeHasSuperType(named("java.sql.PreparedStatement")))), + .and(returns(hasInterface(named("java.sql.PreparedStatement")))), ConnectionInstrumentation.class.getName() + "$ConnectionPrepareAdvice"); } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DataSourceInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DataSourceInstrumentation.java index eae2ba545e..529584fd12 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DataSourceInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DataSourceInstrumentation.java @@ -1,14 +1,12 @@ package datadog.trace.instrumentation.jdbc; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jdbc.DataSourceDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -42,7 +40,7 @@ public final class DataSourceInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.sql.DataSource"))); + return implementsInterface(named("javax.sql.DataSource")); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java index d58d921a60..667338d75d 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/DriverInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.jdbc; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -30,7 +28,7 @@ public final class DriverInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("java.sql.Driver"))); + return implementsInterface(named("java.sql.Driver")); } @Override diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java index 13ec4ac81e..8cbedf2c0d 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/PreparedStatementInstrumentation.java @@ -1,16 +1,14 @@ package datadog.trace.instrumentation.jdbc; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jdbc.JDBCDecorator.DECORATE; import static datadog.trace.instrumentation.jdbc.JDBCUtils.connectionFromStatement; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; @@ -35,7 +33,7 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("java.sql.PreparedStatement"))); + return implementsInterface(named("java.sql.PreparedStatement")); } @Override @@ -61,13 +59,13 @@ public final class PreparedStatementInstrumentation extends Instrumenter.Default @Advice.OnMethodEnter(suppress = Throwable.class) public static AgentScope onEnter(@Advice.This final PreparedStatement statement) { - final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(PreparedStatement.class); - if (callDepth > 0) { + final Connection connection = connectionFromStatement(statement); + if (connection == null) { return null; } - final Connection connection = connectionFromStatement(statement); - if (connection == null) { + final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(PreparedStatement.class); + if (callDepth > 0) { return null; } diff --git a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java index a612d8ba3f..e2da6f2371 100644 --- a/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java +++ b/dd-java-agent/instrumentation/jdbc/src/main/java/datadog/trace/instrumentation/jdbc/StatementInstrumentation.java @@ -1,16 +1,14 @@ package datadog.trace.instrumentation.jdbc; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jdbc.JDBCDecorator.DECORATE; import static datadog.trace.instrumentation.jdbc.JDBCUtils.connectionFromStatement; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,7 +33,7 @@ public final class StatementInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("java.sql.Statement"))); + return implementsInterface(named("java.sql.Statement")); } @Override @@ -62,13 +60,13 @@ public final class StatementInstrumentation extends Instrumenter.Default { @Advice.OnMethodEnter(suppress = Throwable.class) public static AgentScope onEnter( @Advice.Argument(0) final String sql, @Advice.This final Statement statement) { - final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Statement.class); - if (callDepth > 0) { + final Connection connection = connectionFromStatement(statement); + if (connection == null) { return null; } - final Connection connection = connectionFromStatement(statement); - if (connection == null) { + final int callDepth = CallDepthThreadLocalMap.incrementCallDepth(Statement.class); + if (callDepth > 0) { return null; } diff --git a/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java b/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java index 9c34b523b4..a521f0af22 100644 --- a/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java +++ b/dd-java-agent/instrumentation/jedis-1.4/src/main/java/datadog/trace/instrumentation/jedis/JedisInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.jedis; -import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses; +import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasNoResources; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jedis.JedisClientDecorator.DECORATE; @@ -8,7 +8,6 @@ import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -34,7 +33,7 @@ public final class JedisInstrumentation extends Instrumenter.Default { @Override public ElementMatcher classLoaderMatcher() { - return not(classLoaderHasClasses("redis.clients.jedis.commands.ProtocolCommand")); + return classLoaderHasNoResources("redis/clients/jedis/commands/ProtocolCommand.class"); } @Override diff --git a/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyDecorator.java b/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyDecorator.java index 95acf9daea..696d69092c 100644 --- a/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyDecorator.java +++ b/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyDecorator.java @@ -38,11 +38,6 @@ public class JettyDecorator null); } - @Override - protected String peerHostname(final HttpServletRequest httpServletRequest) { - return httpServletRequest.getRemoteHost(); - } - @Override protected String peerHostIP(final HttpServletRequest httpServletRequest) { return httpServletRequest.getRemoteAddr(); diff --git a/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyHandlerInstrumentation.java b/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyHandlerInstrumentation.java index f039c4fbdc..339a65af4b 100644 --- a/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyHandlerInstrumentation.java +++ b/dd-java-agent/instrumentation/jetty-8/src/main/java/datadog/trace/instrumentation/jetty8/JettyHandlerInstrumentation.java @@ -1,8 +1,7 @@ package datadog.trace.instrumentation.jetty8; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.not; @@ -29,9 +28,8 @@ public final class JettyHandlerInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("org.eclipse.jetty.server.Handler"))) - .and(not(named("org.eclipse.jetty.server.handler.HandlerWrapper"))); + return not(named("org.eclipse.jetty.server.handler.HandlerWrapper")) + .and(implementsInterface(named("org.eclipse.jetty.server.Handler"))); } @Override diff --git a/dd-java-agent/instrumentation/jetty-8/src/test/groovy/JettyHandlerTest.groovy b/dd-java-agent/instrumentation/jetty-8/src/test/groovy/JettyHandlerTest.groovy index b4b0c7659a..065be47d25 100644 --- a/dd-java-agent/instrumentation/jetty-8/src/test/groovy/JettyHandlerTest.groovy +++ b/dd-java-agent/instrumentation/jetty-8/src/test/groovy/JettyHandlerTest.groovy @@ -4,15 +4,16 @@ import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDTags import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.instrumentation.jetty8.JettyDecorator -import javax.servlet.DispatcherType -import javax.servlet.ServletException -import javax.servlet.http.HttpServletRequest -import javax.servlet.http.HttpServletResponse import org.eclipse.jetty.server.Request import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.handler.AbstractHandler import org.eclipse.jetty.server.handler.ErrorHandler +import javax.servlet.DispatcherType +import javax.servlet.ServletException +import javax.servlet.http.HttpServletRequest +import javax.servlet.http.HttpServletResponse + import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.NOT_FOUND @@ -131,7 +132,6 @@ class JettyHandlerTest extends HttpServerTest { tags { "$Tags.COMPONENT" serverDecorator.component() "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" { it == "localhost" || it == "127.0.0.1" } "$Tags.PEER_HOST_IPV4" { it == null || it == "127.0.0.1" } // Optional "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "${endpoint.resolve(address)}" diff --git a/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageConsumerInstrumentation.java b/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageConsumerInstrumentation.java index 9a60aef0cd..46e147da95 100644 --- a/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageConsumerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageConsumerInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.jms; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jms.JMSDecorator.CONSUMER_DECORATE; import static datadog.trace.instrumentation.jms.MessageExtractAdapter.GETTER; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; import com.google.auto.service.AutoService; @@ -37,7 +35,7 @@ public final class JMSMessageConsumerInstrumentation extends Instrumenter.Defaul @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.jms.MessageConsumer"))); + return implementsInterface(named("javax.jms.MessageConsumer")); } @Override diff --git a/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageListenerInstrumentation.java b/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageListenerInstrumentation.java index ab658c4eab..63c186eac1 100644 --- a/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageListenerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageListenerInstrumentation.java @@ -1,16 +1,14 @@ package datadog.trace.instrumentation.jms; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jms.JMSDecorator.CONSUMER_DECORATE; import static datadog.trace.instrumentation.jms.MessageExtractAdapter.GETTER; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,7 +33,7 @@ public final class JMSMessageListenerInstrumentation extends Instrumenter.Defaul @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.jms.MessageListener"))); + return implementsInterface(named("javax.jms.MessageListener")); } @Override diff --git a/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java b/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java index f7d806b889..8047791a24 100644 --- a/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java +++ b/dd-java-agent/instrumentation/jms/src/main/java/datadog/trace/instrumentation/jms/JMSMessageProducerInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.jms; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jms.JMSDecorator.PRODUCER_DECORATE; import static datadog.trace.instrumentation.jms.MessageInjectAdapter.SETTER; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -37,7 +35,7 @@ public final class JMSMessageProducerInstrumentation extends Instrumenter.Defaul @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.jms.MessageProducer"))); + return implementsInterface(named("javax.jms.MessageProducer")); } @Override diff --git a/dd-java-agent/instrumentation/jsp-2.3/jsp-2.3.gradle b/dd-java-agent/instrumentation/jsp-2.3/jsp-2.3.gradle index 4e2d4d524d..5bfafc2ebd 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/jsp-2.3.gradle +++ b/dd-java-agent/instrumentation/jsp-2.3/jsp-2.3.gradle @@ -32,7 +32,7 @@ dependencies { latestDepTestCompile group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '+' latestDepTestCompile group: 'javax.servlet', name: 'javax.servlet-api', version: '+' - latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '+' - latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '+' - latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-logging-juli', version: '+' + latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '9.+' + latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.+' + latestDepTestCompile group: 'org.apache.tomcat.embed', name: 'tomcat-embed-logging-juli', version: '9.+' } diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java b/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java index c087746398..20659334ac 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java +++ b/dd-java-agent/instrumentation/jsp-2.3/src/main/java/datadog/trace/instrumentation/jsp/JSPInstrumentation.java @@ -1,14 +1,12 @@ package datadog.trace.instrumentation.jsp; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.jsp.JSPDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -31,7 +29,7 @@ public final class JSPInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.servlet.jsp.HttpJspPage"))); + return implementsInterface(named("javax.servlet.jsp.HttpJspPage")); } @Override diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy index 6a9cd9fe2f..82d3ee5cd3 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy +++ b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationBasicTests.groovy @@ -96,7 +96,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/$jspFileName" @@ -172,7 +171,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/getQuery.jsp" @@ -245,7 +243,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/post.jsp" @@ -315,7 +312,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/$jspFileName" @@ -406,7 +402,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/includes/includeHtml.jsp" @@ -475,7 +470,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/includes/includeMulti.jsp" @@ -600,7 +594,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/$jspFileName" @@ -664,7 +657,6 @@ class JSPInstrumentationBasicTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/$staticFile" diff --git a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy index 5a9a0d971d..6bee485037 100644 --- a/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy +++ b/dd-java-agent/instrumentation/jsp-2.3/src/test/groovy/JSPInstrumentationForwardTests.groovy @@ -95,7 +95,6 @@ class JSPInstrumentationForwardTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/$forwardFromFileName" @@ -198,7 +197,6 @@ class JSPInstrumentationForwardTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/forwards/forwardToHtml.jsp" @@ -267,7 +265,6 @@ class JSPInstrumentationForwardTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/forwards/forwardToIncludeMulti.jsp" @@ -423,7 +420,6 @@ class JSPInstrumentationForwardTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/forwards/forwardToJspForward.jsp" @@ -550,7 +546,6 @@ class JSPInstrumentationForwardTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/forwards/forwardToCompileError.jsp" @@ -636,7 +631,6 @@ class JSPInstrumentationForwardTests extends AgentTestRunner { tags { "$Tags.COMPONENT" "java-web-servlet" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/$jspWebappContext/forwards/forwardToNonExistent.jsp" diff --git a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/ChannelFutureListenerInstrumentation.java b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/ChannelFutureListenerInstrumentation.java index 7219f97d20..64cab30b03 100644 --- a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/ChannelFutureListenerInstrumentation.java +++ b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/ChannelFutureListenerInstrumentation.java @@ -1,13 +1,11 @@ package datadog.trace.instrumentation.netty40; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,8 +33,7 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("io.netty.channel.ChannelFutureListener"))); + return implementsInterface(named("io.netty.channel.ChannelFutureListener")); } @Override diff --git a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java index da5a7fb2c7..ea861e1eb4 100644 --- a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java +++ b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/NettyChannelPipelineInstrumentation.java @@ -1,12 +1,10 @@ package datadog.trace.instrumentation.netty40; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -48,7 +46,7 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("io.netty.channel.ChannelPipeline"))); + return implementsInterface(named("io.netty.channel.ChannelPipeline")); } @Override @@ -101,7 +99,7 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Default { return CallDepthThreadLocalMap.incrementCallDepth(ChannelPipeline.class); } - @Advice.OnMethodExit(suppress = Throwable.class) + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void addHandler( @Advice.Enter final int depth, @Advice.This final ChannelPipeline pipeline, diff --git a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java index df7f6896d4..92812681f3 100644 --- a/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/netty-4.0/src/main/java/datadog/trace/instrumentation/netty40/server/NettyHttpServerDecorator.java @@ -42,15 +42,6 @@ public class NettyHttpServerDecorator } } - @Override - protected String peerHostname(final Channel channel) { - final SocketAddress socketAddress = channel.remoteAddress(); - if (socketAddress instanceof InetSocketAddress) { - return ((InetSocketAddress) socketAddress).getHostName(); - } - return null; - } - @Override protected String peerHostIP(final Channel channel) { final SocketAddress socketAddress = channel.remoteAddress(); diff --git a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/ChannelFutureListenerInstrumentation.java b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/ChannelFutureListenerInstrumentation.java index a9f17b0426..2344d11df1 100644 --- a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/ChannelFutureListenerInstrumentation.java +++ b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/ChannelFutureListenerInstrumentation.java @@ -1,13 +1,11 @@ package datadog.trace.instrumentation.netty41; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,8 +33,7 @@ public class ChannelFutureListenerInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("io.netty.channel.ChannelFutureListener"))); + return implementsInterface(named("io.netty.channel.ChannelFutureListener")); } @Override diff --git a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java index b0edd6703a..3429873436 100644 --- a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java +++ b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/NettyChannelPipelineInstrumentation.java @@ -1,12 +1,10 @@ package datadog.trace.instrumentation.netty41; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeScope; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -48,7 +46,7 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("io.netty.channel.ChannelPipeline"))); + return implementsInterface(named("io.netty.channel.ChannelPipeline")); } @Override @@ -110,7 +108,7 @@ public class NettyChannelPipelineInstrumentation extends Instrumenter.Default { return CallDepthThreadLocalMap.incrementCallDepth(handler.getClass()); } - @Advice.OnMethodExit(suppress = Throwable.class) + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) public static void addHandler( @Advice.Enter final int depth, @Advice.This final ChannelPipeline pipeline, diff --git a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java index 20be35a3a8..8c70fb56fd 100644 --- a/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/netty-4.1/src/main/java/datadog/trace/instrumentation/netty41/server/NettyHttpServerDecorator.java @@ -42,15 +42,6 @@ public class NettyHttpServerDecorator } } - @Override - protected String peerHostname(final Channel channel) { - final SocketAddress socketAddress = channel.remoteAddress(); - if (socketAddress instanceof InetSocketAddress) { - return ((InetSocketAddress) socketAddress).getHostName(); - } - return null; - } - @Override protected String peerHostIP(final Channel channel) { final SocketAddress socketAddress = channel.remoteAddress(); diff --git a/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java b/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java deleted file mode 100644 index 3bc464f02d..0000000000 --- a/dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java +++ /dev/null @@ -1,104 +0,0 @@ -package datadog.trace.instrumentation.osgi; - -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isMethod; -import static net.bytebuddy.matcher.ElementMatchers.isPublic; -import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.takesArgument; - -import com.google.auto.service.AutoService; -import datadog.trace.agent.tooling.Constants; -import datadog.trace.agent.tooling.Instrumenter; -import java.security.ProtectionDomain; -import java.util.Map; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.utility.JavaModule; - -@AutoService(Instrumenter.class) -public final class OSGIClassloadingInstrumentation extends Instrumenter.Default { - public OSGIClassloadingInstrumentation() { - super("osgi-classloading"); - } - - @Override - public ElementMatcher typeMatcher() { - // OSGi Bundle class loads the system property which defines bootstrap classes - return named("org.osgi.framework.Bundle") - // OSGi FrameworkFactory can ignore/override the system property - .or(safeHasSuperType(named("org.osgi.framework.launch.FrameworkFactory"))); - } - - @Override - public String[] helperClassNames() { - return new String[] { - Constants.class.getName(), OSGIClassloadingInstrumentation.class.getName() + "$Helper" - }; - } - - @Override - public void postMatch( - final TypeDescription typeDescription, - final ClassLoader classLoader, - final JavaModule module, - final Class classBeingRedefined, - final ProtectionDomain protectionDomain) { - // Set the system prop to tell OSGi to delegate classloads for datadog bootstrap classes - System.setProperty( - Helper.PROPERTY_KEY, Helper.getNewValue(System.getProperty(Helper.PROPERTY_KEY))); - } - - @Override - public Map, String> transformers() { - return singletonMap( - isMethod().and(isPublic()).and(named("newFramework")).and(takesArgument(0, Map.class)), - OSGIClassloadingInstrumentation.class.getName() + "$FrameworkFactoryAdvice"); - } - - /** - * FrameworkFactory implementations receive the expected config via a map rather than the modified - * system property. We must modify that map before being passed along to the framework. - */ - public static class FrameworkFactoryAdvice { - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void methodEnter(@Advice.Argument(0) final Map configuration) { - if (configuration != null) { - configuration.put( - Helper.PROPERTY_KEY, Helper.getNewValue(configuration.get(Helper.PROPERTY_KEY))); - } - } - } - - public static class Helper { - - public static final String PROPERTY_KEY = "org.osgi.framework.bootdelegation"; - public static final String PROPERTY_VALUE; - - static { - // Set the config option to tell osgi to delegate classloads for datadog bootstrap classes - final StringBuilder prefixes = new StringBuilder(""); - for (int i = 0; i < Constants.BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) { - if (i > 0) { - // must append twice. Once for exact package and wildcard for child packages - prefixes.append(","); - } - prefixes.append(Constants.BOOTSTRAP_PACKAGE_PREFIXES[i]).append(".*,"); - prefixes.append(Constants.BOOTSTRAP_PACKAGE_PREFIXES[i]); - } - PROPERTY_VALUE = prefixes.toString(); - } - - public static String getNewValue(final String existingValue) { - if (existingValue == null || "".equals(existingValue)) { - return PROPERTY_VALUE; - } else if (!existingValue.contains(PROPERTY_VALUE)) { - return existingValue + "," + PROPERTY_VALUE; - } else { - return existingValue; - } - } - } -} diff --git a/dd-java-agent/instrumentation/osgi-classloading/src/test/groovy/OSGIClassloadingTest.groovy b/dd-java-agent/instrumentation/osgi-classloading/src/test/groovy/OSGIClassloadingTest.groovy deleted file mode 100644 index 8d4002636f..0000000000 --- a/dd-java-agent/instrumentation/osgi-classloading/src/test/groovy/OSGIClassloadingTest.groovy +++ /dev/null @@ -1,55 +0,0 @@ -import datadog.trace.agent.test.AgentTestRunner -import datadog.trace.instrumentation.osgi.OSGIClassloadingInstrumentation -import org.eclipse.osgi.launch.EquinoxFactory -import org.junit.Rule -import org.junit.contrib.java.lang.system.RestoreSystemProperties -import org.osgi.framework.launch.Framework - -class OSGIClassloadingTest extends AgentTestRunner { - - @Rule - public final RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties() - - static final String BOOT_DELEGATION_ADDITION = "datadog.slf4j.*,datadog.slf4j,datadog.trace.api.*,datadog.trace.api,datadog.trace.bootstrap.*,datadog.trace.bootstrap,datadog.trace.context.*,datadog.trace.context,datadog.trace.instrumentation.api.*,datadog.trace.instrumentation.api,io.opentracing.*,io.opentracing" - - def "delegation property set on module load"() { - when: - org.osgi.framework.Bundle.getName() - - then: - System.getProperty("org.osgi.framework.bootdelegation") == BOOT_DELEGATION_ADDITION - } - - def "test OSGi framework factory"() { - setup: - def config = ["osgi.support.class.certificate": "false"] - - when: - Framework framework = factory.newFramework(config) - - then: - framework != null - - where: - factory | _ - new EquinoxFactory() | _ - new org.apache.felix.framework.FrameworkFactory() | _ - } - - def "test property transformations"() { - when: - def newValue = OSGIClassloadingInstrumentation.Helper.getNewValue(existingValue) - - then: - newValue == expectedNewValue - - where: - existingValue | expectedNewValue - null | BOOT_DELEGATION_ADDITION - "" | BOOT_DELEGATION_ADDITION - BOOT_DELEGATION_ADDITION | BOOT_DELEGATION_ADDITION - "foo.*" | "foo.*," + BOOT_DELEGATION_ADDITION - "foo.*," + BOOT_DELEGATION_ADDITION + ",bar.*" | "foo.*," + BOOT_DELEGATION_ADDITION + ",bar.*" - - } -} diff --git a/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java b/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java index 950fe72d60..b13551951e 100644 --- a/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java +++ b/dd-java-agent/instrumentation/play-2.4/src/main/java/datadog/trace/instrumentation/play24/PlayInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.play24; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.returns; @@ -22,7 +22,7 @@ public final class PlayInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("play.api.mvc.Action")); + return implementsInterface(named("play.api.mvc.Action")); } @Override diff --git a/dd-java-agent/instrumentation/play-2.4/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java b/dd-java-agent/instrumentation/play-2.4/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java index cb10d37047..bfc9333220 100644 --- a/dd-java-agent/instrumentation/play-2.4/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/play-2.4/src/main/java8/datadog/trace/instrumentation/play24/PlayHttpServerDecorator.java @@ -37,11 +37,6 @@ public class PlayHttpServerDecorator extends HttpServerDecorator typeMatcher() { - return safeHasSuperType(named("play.api.mvc.Action")); + return implementsInterface(named("play.api.mvc.Action")); } @Override diff --git a/dd-java-agent/instrumentation/play-2.6/src/main/java8/datadog/trace/instrumentation/play26/PlayHttpServerDecorator.java b/dd-java-agent/instrumentation/play-2.6/src/main/java8/datadog/trace/instrumentation/play26/PlayHttpServerDecorator.java index b66f395391..0001078155 100644 --- a/dd-java-agent/instrumentation/play-2.6/src/main/java8/datadog/trace/instrumentation/play26/PlayHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/play-2.6/src/main/java8/datadog/trace/instrumentation/play26/PlayHttpServerDecorator.java @@ -39,11 +39,6 @@ public class PlayHttpServerDecorator extends HttpServerDecorator typeMatcher() { // CachingAsyncHttpClient rejects overrides to AsyncHandler // It also delegates to another AsyncHttpClient - return safeHasSuperType(named("play.shaded.ahc.org.asynchttpclient.AsyncHttpClient")) - .and(not(named("play.api.libs.ws.ahc.cache.CachingAsyncHttpClient"))); + return nameStartsWith("play.") + .and( + hasInterface(named("play.shaded.ahc.org.asynchttpclient.AsyncHttpClient")) + .and(not(named("play.api.libs.ws.ahc.cache.CachingAsyncHttpClient")))); } @Override diff --git a/dd-java-agent/instrumentation/play-ws-2.1/src/main/java/datadog/trace/instrumentation/playws21/PlayWSClientInstrumentation.java b/dd-java-agent/instrumentation/play-ws-2.1/src/main/java/datadog/trace/instrumentation/playws21/PlayWSClientInstrumentation.java index ab8d3cd5c4..c204610030 100644 --- a/dd-java-agent/instrumentation/play-ws-2.1/src/main/java/datadog/trace/instrumentation/playws21/PlayWSClientInstrumentation.java +++ b/dd-java-agent/instrumentation/play-ws-2.1/src/main/java/datadog/trace/instrumentation/playws21/PlayWSClientInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.playws21; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.playws21.HeadersInjectAdapter.SETTER; @@ -33,7 +33,7 @@ public class PlayWSClientInstrumentation extends Instrumenter.Default { public ElementMatcher typeMatcher() { // CachingAsyncHttpClient rejects overrides to AsyncHandler // It also delegates to another AsyncHttpClient - return safeHasSuperType(named("play.shaded.ahc.org.asynchttpclient.AsyncHttpClient")) + return implementsInterface(named("play.shaded.ahc.org.asynchttpclient.AsyncHttpClient")) .and(not(named("play.api.libs.ws.ahc.cache.CachingAsyncHttpClient"))); } diff --git a/dd-java-agent/instrumentation/play-ws-2/src/main/java/datadog/trace/instrumentation/playws2/PlayWSClientInstrumentation.java b/dd-java-agent/instrumentation/play-ws-2/src/main/java/datadog/trace/instrumentation/playws2/PlayWSClientInstrumentation.java index d4f3ea992c..43c7db7710 100644 --- a/dd-java-agent/instrumentation/play-ws-2/src/main/java/datadog/trace/instrumentation/playws2/PlayWSClientInstrumentation.java +++ b/dd-java-agent/instrumentation/play-ws-2/src/main/java/datadog/trace/instrumentation/playws2/PlayWSClientInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.playws2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.playws2.HeadersInjectAdapter.SETTER; @@ -33,7 +33,7 @@ public class PlayWSClientInstrumentation extends Instrumenter.Default { public ElementMatcher typeMatcher() { // CachingAsyncHttpClient rejects overrides to AsyncHandler // It also delegates to another AsyncHttpClient - return safeHasSuperType(named("play.shaded.ahc.org.asynchttpclient.AsyncHttpClient")) + return implementsInterface(named("play.shaded.ahc.org.asynchttpclient.AsyncHttpClient")) .and(not(named("play.api.libs.ws.ahc.cache.CachingAsyncHttpClient"))); } diff --git a/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitChannelInstrumentation.java b/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitChannelInstrumentation.java index 425cc830d3..08d1bf811c 100644 --- a/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitChannelInstrumentation.java +++ b/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitChannelInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.rabbitmq.amqp; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.noopSpan; @@ -13,7 +13,6 @@ import static datadog.trace.instrumentation.rabbitmq.amqp.TextMapExtractAdapter. import static datadog.trace.instrumentation.rabbitmq.amqp.TextMapInjectAdapter.SETTER; import static net.bytebuddy.matcher.ElementMatchers.canThrow; import static net.bytebuddy.matcher.ElementMatchers.isGetter; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.isSetter; @@ -56,7 +55,7 @@ public class RabbitChannelInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("com.rabbitmq.client.Channel"))); + return implementsInterface(named("com.rabbitmq.client.Channel")); } @Override diff --git a/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitCommandInstrumentation.java b/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitCommandInstrumentation.java index fde3ade5a3..8f5097e5a1 100644 --- a/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitCommandInstrumentation.java +++ b/dd-java-agent/instrumentation/rabbitmq-amqp-2.7/src/main/java/datadog/trace/instrumentation/rabbitmq/amqp/RabbitCommandInstrumentation.java @@ -1,13 +1,11 @@ package datadog.trace.instrumentation.rabbitmq.amqp; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.instrumentation.rabbitmq.amqp.RabbitDecorator.DECORATE; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import com.rabbitmq.client.Command; @@ -28,7 +26,7 @@ public class RabbitCommandInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("com.rabbitmq.client.Command"))); + return implementsInterface(named("com.rabbitmq.client.Command")); } @Override diff --git a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ContinuationInstrumentation.java b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ContinuationInstrumentation.java index be4cdfe46c..88c3f1abc7 100644 --- a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ContinuationInstrumentation.java +++ b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ContinuationInstrumentation.java @@ -1,8 +1,9 @@ package datadog.trace.instrumentation.ratpack; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -25,7 +26,8 @@ public final class ContinuationInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType(named("ratpack.exec.internal.Continuation")); + return nameStartsWith("ratpack.exec.") + .and(implementsInterface(named("ratpack.exec.internal.Continuation"))); } @Override diff --git a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ServerErrorHandlerInstrumentation.java b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ServerErrorHandlerInstrumentation.java index b3908dd848..0ddf2b0feb 100644 --- a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ServerErrorHandlerInstrumentation.java +++ b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java/datadog/trace/instrumentation/ratpack/ServerErrorHandlerInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.ratpack; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isInterface; @@ -25,7 +25,7 @@ public class ServerErrorHandlerInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { return not(isInterface().or(isAbstract())) - .and(safeHasSuperType(named("ratpack.error.ServerErrorHandler"))); + .and(implementsInterface(named("ratpack.error.ServerErrorHandler"))); } @Override diff --git a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java8/datadog/trace/instrumentation/ratpack/RatpackServerDecorator.java b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java8/datadog/trace/instrumentation/ratpack/RatpackServerDecorator.java index 6accb5bdaf..7d8c46a2e0 100644 --- a/dd-java-agent/instrumentation/ratpack-1.4/src/main/java8/datadog/trace/instrumentation/ratpack/RatpackServerDecorator.java +++ b/dd-java-agent/instrumentation/ratpack-1.4/src/main/java8/datadog/trace/instrumentation/ratpack/RatpackServerDecorator.java @@ -48,11 +48,6 @@ public class RatpackServerDecorator extends HttpServerDecorator typeMatcher() { return not(isAbstract()) .and( - safeHasSuperType( + extendsClass( named("reactor.core.publisher.Mono").or(named("reactor.core.publisher.Flux")))); } diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java index c6acebdce8..69c733a30e 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/client/RmiClientInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.rmi.client; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.rmi.client.RmiClientDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -33,7 +31,7 @@ public final class RmiClientInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("sun.rmi.server.UnicastRef"))); + return extendsClass(named("sun.rmi.server.UnicastRef")); } @Override diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java index 1c7b0175bd..138e941c21 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/client/RmiClientContextInstrumentation.java @@ -1,13 +1,11 @@ package datadog.trace.instrumentation.rmi.context.client; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.instrumentation.rmi.context.ContextPropagator.PROPAGATOR; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -53,7 +51,7 @@ public class RmiClientContextInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("sun.rmi.transport.StreamRemoteCall"))); + return extendsClass(named("sun.rmi.transport.StreamRemoteCall")); } @Override diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java index 1ce41f9310..d9422e804b 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/context/server/RmiServerContextInstrumentation.java @@ -1,13 +1,11 @@ package datadog.trace.instrumentation.rmi.context.server; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.instrumentation.rmi.context.ContextPropagator.DD_CONTEXT_CALL_ID; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isStatic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -28,7 +26,7 @@ public class RmiServerContextInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("sun.rmi.transport.ObjectTable"))); + return extendsClass(named("sun.rmi.transport.ObjectTable")); } @Override diff --git a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java index dd96577b52..8bc61e66c5 100644 --- a/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java +++ b/dd-java-agent/instrumentation/rmi/src/main/java/datadog/trace/instrumentation/rmi/server/RmiServerInstrumentation.java @@ -1,12 +1,11 @@ package datadog.trace.instrumentation.rmi.server; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.bootstrap.instrumentation.rmi.ThreadLocalContext.THREAD_LOCAL_CONTEXT; import static datadog.trace.instrumentation.rmi.server.RmiServerDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.isStatic; @@ -43,7 +42,7 @@ public final class RmiServerInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("java.rmi.server.RemoteServer"))); + return extendsClass(named("java.rmi.server.RemoteServer")); } @Override diff --git a/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Decorator.java b/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Decorator.java index 3928d6fbc2..5d79a12bb3 100644 --- a/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Decorator.java +++ b/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Decorator.java @@ -38,11 +38,6 @@ public class Servlet2Decorator null); } - @Override - protected String peerHostname(final HttpServletRequest httpServletRequest) { - return httpServletRequest.getRemoteHost(); - } - @Override protected String peerHostIP(final HttpServletRequest httpServletRequest) { return httpServletRequest.getRemoteAddr(); diff --git a/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Instrumentation.java b/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Instrumentation.java index 8490d7a237..a45790ae25 100644 --- a/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Instrumentation.java +++ b/dd-java-agent/instrumentation/servlet/request-2/src/main/java/datadog/trace/instrumentation/servlet2/Servlet2Instrumentation.java @@ -1,12 +1,10 @@ package datadog.trace.instrumentation.servlet2; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; -import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasClasses; +import static datadog.trace.agent.tooling.ClassLoaderMatcher.classLoaderHasNoResources; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -26,7 +24,8 @@ public final class Servlet2Instrumentation extends Instrumenter.Default { // this is required to make sure servlet 2 instrumentation won't apply to servlet 3 @Override public ElementMatcher classLoaderMatcher() { - return not(classLoaderHasClasses("javax.servlet.AsyncEvent", "javax.servlet.AsyncListener")); + return classLoaderHasNoResources( + "javax/servlet/AsyncEvent.class", "javax/servlet/AsyncListener.class"); } @Override @@ -43,10 +42,8 @@ public final class Servlet2Instrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and( - safeHasSuperType( - named("javax.servlet.FilterChain").or(named("javax.servlet.http.HttpServlet")))); + return safeHasSuperType( + named("javax.servlet.FilterChain").or(named("javax.servlet.http.HttpServlet"))); } @Override diff --git a/dd-java-agent/instrumentation/servlet/request-2/src/test/groovy/JettyServlet2Test.groovy b/dd-java-agent/instrumentation/servlet/request-2/src/test/groovy/JettyServlet2Test.groovy index b9b69299a6..49821f2a13 100644 --- a/dd-java-agent/instrumentation/servlet/request-2/src/test/groovy/JettyServlet2Test.groovy +++ b/dd-java-agent/instrumentation/servlet/request-2/src/test/groovy/JettyServlet2Test.groovy @@ -4,11 +4,12 @@ import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDTags import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.instrumentation.servlet2.Servlet2Decorator -import javax.servlet.http.HttpServletRequest import org.eclipse.jetty.server.Server import org.eclipse.jetty.server.handler.ErrorHandler import org.eclipse.jetty.servlet.ServletContextHandler +import javax.servlet.http.HttpServletRequest + import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.AUTH_REQUIRED import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION @@ -97,7 +98,6 @@ class JettyServlet2Test extends HttpServerTest { tags { "$Tags.COMPONENT" serverDecorator.component() "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" // No peer port "$Tags.HTTP_URL" "${endpoint.resolve(address)}" diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/AsyncContextInstrumentation.java b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/AsyncContextInstrumentation.java index a3b932455b..71e03d573d 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/AsyncContextInstrumentation.java +++ b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/AsyncContextInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.servlet3; import static datadog.trace.agent.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; import static datadog.trace.instrumentation.servlet3.HttpServletRequestInjectAdapter.SETTER; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -38,7 +36,7 @@ public final class AsyncContextInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.servlet.AsyncContext"))); + return implementsInterface(named("javax.servlet.AsyncContext")); } @Override diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java index 2fbf859a58..5fadec4d10 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java +++ b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Decorator.java @@ -39,11 +39,6 @@ public class Servlet3Decorator null); } - @Override - protected String peerHostname(final HttpServletRequest httpServletRequest) { - return httpServletRequest.getRemoteHost(); - } - @Override protected String peerHostIP(final HttpServletRequest httpServletRequest) { return httpServletRequest.getRemoteAddr(); diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Instrumentation.java b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Instrumentation.java index 42c982b169..5f0315734d 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Instrumentation.java +++ b/dd-java-agent/instrumentation/servlet/request-3/src/main/java/datadog/trace/instrumentation/servlet3/Servlet3Instrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.servlet3; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -35,10 +33,8 @@ public final class Servlet3Instrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and( - safeHasSuperType( - named("javax.servlet.FilterChain").or(named("javax.servlet.http.HttpServlet")))); + return safeHasSuperType( + named("javax.servlet.FilterChain").or(named("javax.servlet.http.HttpServlet"))); } @Override diff --git a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/AbstractServlet3Test.groovy b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/AbstractServlet3Test.groovy index c507ecc424..7b152e39e6 100644 --- a/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/AbstractServlet3Test.groovy +++ b/dd-java-agent/instrumentation/servlet/request-3/src/test/groovy/AbstractServlet3Test.groovy @@ -4,10 +4,11 @@ import datadog.trace.api.DDSpanTypes import datadog.trace.api.DDTags import datadog.trace.bootstrap.instrumentation.api.Tags import datadog.trace.instrumentation.servlet3.Servlet3Decorator -import javax.servlet.Servlet import okhttp3.Request import org.apache.catalina.core.ApplicationFilterChain +import javax.servlet.Servlet + import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.AUTH_REQUIRED import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.ERROR import static datadog.trace.agent.test.base.HttpServerTest.ServerEndpoint.EXCEPTION @@ -86,7 +87,6 @@ abstract class AbstractServlet3Test extends HttpServerTest typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.servlet.RequestDispatcher"))); + return implementsInterface(named("javax.servlet.RequestDispatcher")); } @Override diff --git a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/dispatcher/ServletContextInstrumentation.java b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/dispatcher/ServletContextInstrumentation.java index 9c3df78076..ec70e1e1aa 100644 --- a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/dispatcher/ServletContextInstrumentation.java +++ b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/dispatcher/ServletContextInstrumentation.java @@ -1,11 +1,9 @@ package datadog.trace.instrumentation.servlet.dispatcher; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.returns; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; @@ -27,7 +25,7 @@ public final class ServletContextInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.servlet.ServletContext"))); + return implementsInterface(named("javax.servlet.ServletContext")); } @Override diff --git a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/filter/FilterInstrumentation.java b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/filter/FilterInstrumentation.java index 0795c548ac..9099f65b01 100644 --- a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/filter/FilterInstrumentation.java +++ b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/filter/FilterInstrumentation.java @@ -1,15 +1,13 @@ package datadog.trace.instrumentation.servlet.filter; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.servlet.filter.FilterDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -44,7 +42,7 @@ public final class FilterInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.servlet.Filter"))); + return implementsInterface(named("javax.servlet.Filter")); } @Override diff --git a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletInstrumentation.java b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletInstrumentation.java index ccac20c47e..cd5cbebeb2 100644 --- a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletInstrumentation.java +++ b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletInstrumentation.java @@ -1,17 +1,15 @@ package datadog.trace.instrumentation.servlet.http; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.servlet.http.HttpServletDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isProtected; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import com.google.auto.service.AutoService; @@ -46,7 +44,7 @@ public final class HttpServletInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()).and(safeHasSuperType(named("javax.servlet.http.HttpServlet"))); + return extendsClass(named("javax.servlet.http.HttpServlet")); } /** diff --git a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletResponseInstrumentation.java b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletResponseInstrumentation.java index f78ca4fb86..e2823249b7 100644 --- a/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletResponseInstrumentation.java +++ b/dd-java-agent/instrumentation/servlet/src/main/java/datadog/trace/instrumentation/servlet/http/HttpServletResponseInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.servlet.http; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.propagate; @@ -8,9 +8,7 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.servlet.ServletRequestSetter.SETTER; import static datadog.trace.instrumentation.servlet.http.HttpServletResponseDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -43,8 +41,7 @@ public final class HttpServletResponseInstrumentation extends Instrumenter.Defau @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("javax.servlet.http.HttpServletResponse"))); + return implementsInterface(named("javax.servlet.http.HttpServletResponse")); } @Override diff --git a/dd-java-agent/instrumentation/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy b/dd-java-agent/instrumentation/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy index 6ffa1cf841..f63951f3e1 100644 --- a/dd-java-agent/instrumentation/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy +++ b/dd-java-agent/instrumentation/sparkjava-2.3/src/test/groovy/SparkJavaBasedTest.groovy @@ -53,7 +53,6 @@ class SparkJavaBasedTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "jetty-handler" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "127.0.0.1" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" "http://localhost:$port/param/asdf1234" diff --git a/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java b/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java index b06a699291..8e8f2401f0 100644 --- a/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-data-1.8/src/main/java/datadog/trace/instrumentation/springdata/SpringRepositoryInstrumentation.java @@ -6,9 +6,7 @@ import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSp import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.springdata.SpringDataDecorator.DECORATOR; import static net.bytebuddy.matcher.ElementMatchers.isConstructor; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; @@ -38,8 +36,7 @@ public final class SpringRepositoryInstrumentation extends Instrumenter.Default @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(named("org.springframework.data.repository.core.support.RepositoryFactorySupport")); + return named("org.springframework.data.repository.core.support.RepositoryFactorySupport"); } @Override diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/spring-scheduling-3.1.gradle b/dd-java-agent/instrumentation/spring-scheduling-3.1/spring-scheduling-3.1.gradle new file mode 100644 index 0000000000..2281901bbc --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/spring-scheduling-3.1.gradle @@ -0,0 +1,28 @@ +muzzle { + pass { + group = 'org.springframework' + module = 'spring-context' + versions = "[3.1.0.RELEASE,]" + assertInverse = true + } +} + +apply from: "${rootDir}/gradle/java.gradle" + +apply plugin: 'org.unbroken-dome.test-sets' + +testSets { + latestDepTest { + dirName = 'test' + } +} + +dependencies { + // 3.2.3 is the first version with which the tests will run. Lower versions require other + // classes and packages to be imported. Versions 3.1.0+ work with the instrumentation. + compileOnly group: 'org.springframework', name: 'spring-context', version: '3.1.0.RELEASE' + testCompile group: 'org.springframework', name: 'spring-context', version: '3.2.3.RELEASE' + + // this is the latest version that supports Java 7 + latestDepTestCompile group: 'org.springframework', name: 'spring-context', version: '4.+' +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java new file mode 100644 index 0000000000..39e84a681b --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingDecorator.java @@ -0,0 +1,45 @@ +package datadog.trace.instrumentation.springscheduling; + +import datadog.trace.agent.decorator.BaseDecorator; +import datadog.trace.api.DDTags; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.support.ScheduledMethodRunnable; + +@Slf4j +public class SpringSchedulingDecorator extends BaseDecorator { + public static final SpringSchedulingDecorator DECORATE = new SpringSchedulingDecorator(); + + private SpringSchedulingDecorator() {} + + @Override + protected String[] instrumentationNames() { + return new String[] {"spring-scheduling"}; + } + + @Override + protected String spanType() { + return null; + } + + @Override + protected String component() { + return "spring-scheduling"; + } + + public AgentSpan onRun(final AgentSpan span, final Runnable runnable) { + if (runnable != null) { + String resourceName = ""; + if (runnable instanceof ScheduledMethodRunnable) { + final ScheduledMethodRunnable scheduledMethodRunnable = (ScheduledMethodRunnable) runnable; + resourceName = spanNameForMethod(scheduledMethodRunnable.getMethod()); + } else { + final String className = spanNameForClass(runnable.getClass()); + final String methodName = "run"; + resourceName = className + "." + methodName; + } + span.setTag(DDTags.RESOURCE_NAME, resourceName); + } + return span; + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java new file mode 100644 index 0000000000..ed849d1887 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/main/java/datadog/trace/instrumentation/springscheduling/SpringSchedulingInstrumentation.java @@ -0,0 +1,94 @@ +package datadog.trace.instrumentation.springscheduling; + +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; +import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; +import static datadog.trace.instrumentation.springscheduling.SpringSchedulingDecorator.DECORATE; +import static java.util.Collections.singletonMap; +import static net.bytebuddy.matcher.ElementMatchers.isConstructor; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.bootstrap.instrumentation.api.AgentScope; +import datadog.trace.bootstrap.instrumentation.api.AgentSpan; +import java.util.Map; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(Instrumenter.class) +public final class SpringSchedulingInstrumentation extends Instrumenter.Default { + + public SpringSchedulingInstrumentation() { + super("spring-scheduling"); + } + + @Override + public ElementMatcher typeMatcher() { + return named("org.springframework.scheduling.config.Task"); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.agent.decorator.BaseDecorator", + packageName + ".SpringSchedulingDecorator", + getClass().getName() + "$RunnableWrapper", + }; + } + + @Override + public Map, String> transformers() { + return singletonMap( + isConstructor().and(takesArgument(0, Runnable.class)), + SpringSchedulingInstrumentation.class.getName() + "$SpringSchedulingAdvice"); + } + + public static class SpringSchedulingAdvice { + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onConstruction( + @Advice.Argument(value = 0, readOnly = false) Runnable runnable) { + runnable = RunnableWrapper.wrapIfNeeded(runnable); + } + } + + public static class RunnableWrapper implements Runnable { + private final Runnable runnable; + + private RunnableWrapper(final Runnable runnable) { + this.runnable = runnable; + } + + @Override + public void run() { + final AgentSpan span = startSpan("scheduled.call"); + DECORATE.afterStart(span); + + try (final AgentScope scope = activateSpan(span, false)) { + DECORATE.onRun(span, runnable); + scope.setAsyncPropagation(true); + + try { + runnable.run(); + } catch (final Throwable throwable) { + DECORATE.onError(span, throwable); + throw throwable; + } + } finally { + DECORATE.beforeFinish(span); + span.finish(); + } + } + + public static Runnable wrapIfNeeded(final Runnable task) { + // We wrap only lambdas' anonymous classes and if given object has not already been wrapped. + // Anonymous classes have '/' in class name which is not allowed in 'normal' classes. + if (task instanceof RunnableWrapper) { + return task; + } + return new RunnableWrapper(task); + } + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/groovy/SpringSchedulingTest.groovy b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/groovy/SpringSchedulingTest.groovy new file mode 100644 index 0000000000..92c4aa4e04 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/groovy/SpringSchedulingTest.groovy @@ -0,0 +1,57 @@ +import datadog.trace.agent.test.AgentTestRunner +import datadog.trace.bootstrap.instrumentation.api.Tags +import org.springframework.context.annotation.AnnotationConfigApplicationContext + +class SpringSchedulingTest extends AgentTestRunner { + + def "schedule trigger test according to cron expression"() { + setup: + def context = new AnnotationConfigApplicationContext(TriggerTaskConfig) + def task = context.getBean(TriggerTask) + + task.blockUntilExecute() + + expect: + assert task != null + assertTraces(1) { + trace(0, 1) { + span(0) { + resourceName "TriggerTask.run" + operationName "scheduled.call" + parent() + errored false + tags { + "$Tags.COMPONENT" "spring-scheduling" + defaultTags() + } + } + } + } + } + + def "schedule interval test"() { + setup: + def context = new AnnotationConfigApplicationContext(IntervalTaskConfig) + def task = context.getBean(IntervalTask) + + task.blockUntilExecute() + + expect: + assert task != null + assertTraces(1) { + trace(0, 1) { + span(0) { + resourceName "IntervalTask.run" + operationName "scheduled.call" + parent() + errored false + tags { + "$Tags.COMPONENT" "spring-scheduling" + defaultTags() + } + } + } + } + + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/IntervalTask.java b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/IntervalTask.java new file mode 100644 index 0000000000..4858ad2003 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/IntervalTask.java @@ -0,0 +1,20 @@ +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class IntervalTask implements Runnable { + + private final CountDownLatch latch = new CountDownLatch(1); + + @Scheduled(fixedRate = 5000) + @Override + public void run() { + latch.countDown(); + } + + public void blockUntilExecute() throws InterruptedException { + latch.await(5, TimeUnit.SECONDS); + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/IntervalTaskConfig.java b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/IntervalTaskConfig.java new file mode 100644 index 0000000000..58309a70ba --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/IntervalTaskConfig.java @@ -0,0 +1,12 @@ +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class IntervalTaskConfig { + @Bean + public IntervalTask scheduledTasks() { + return new IntervalTask(); + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/TriggerTask.java b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/TriggerTask.java new file mode 100644 index 0000000000..dc434f539f --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/TriggerTask.java @@ -0,0 +1,20 @@ +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class TriggerTask implements Runnable { + + private final CountDownLatch latch = new CountDownLatch(1); + + @Scheduled(cron = "0/5 * * * * *") + @Override + public void run() { + latch.countDown(); + } + + public void blockUntilExecute() throws InterruptedException { + latch.await(5, TimeUnit.SECONDS); + } +} diff --git a/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/TriggerTaskConfig.java b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/TriggerTaskConfig.java new file mode 100644 index 0000000000..e032d082d3 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-scheduling-3.1/src/test/java/TriggerTaskConfig.java @@ -0,0 +1,12 @@ +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +@Configuration +@EnableScheduling +public class TriggerTaskConfig { + @Bean + public TriggerTask triggerTasks() { + return new TriggerTask(); + } +} diff --git a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/DefaultWebClientInstrumentation.java b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/DefaultWebClientInstrumentation.java index ca23a46fce..bb7c2b0868 100644 --- a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/DefaultWebClientInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/client/DefaultWebClientInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.springwebflux.client; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; @@ -37,7 +37,7 @@ public class DefaultWebClientInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return safeHasSuperType( + return implementsInterface( named("org.springframework.web.reactive.function.client.ExchangeFunction")); } diff --git a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/HandlerAdapterInstrumentation.java b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/HandlerAdapterInstrumentation.java index 89d9e946c9..dc297dd96c 100644 --- a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/HandlerAdapterInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/HandlerAdapterInstrumentation.java @@ -1,9 +1,8 @@ package datadog.trace.instrumentation.springwebflux.server; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.named; @@ -23,9 +22,8 @@ public final class HandlerAdapterInstrumentation extends AbstractWebfluxInstrume @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(not(isAbstract())) - .and(safeHasSuperType(named("org.springframework.web.reactive.HandlerAdapter"))); + return not(isAbstract()) + .and(implementsInterface(named("org.springframework.web.reactive.HandlerAdapter"))); } @Override diff --git a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/RouterFunctionInstrumentation.java b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/RouterFunctionInstrumentation.java index bc1b5a9322..c6a6bf6443 100644 --- a/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/RouterFunctionInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-webflux-5/src/main/java/datadog/trace/instrumentation/springwebflux/server/RouterFunctionInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.springwebflux.server; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static java.util.Collections.singletonMap; import static net.bytebuddy.matcher.ElementMatchers.isAbstract; import static net.bytebuddy.matcher.ElementMatchers.isMethod; @@ -28,7 +28,7 @@ public final class RouterFunctionInstrumentation extends AbstractWebfluxInstrume public ElementMatcher typeMatcher() { return not(isAbstract()) .and( - safeHasSuperType( + extendsClass( // TODO: this doesn't handle nested routes (DefaultNestedRouterFunction) named( "org.springframework.web.reactive.function.server.RouterFunctions$DefaultRouterFunction"))); diff --git a/dd-java-agent/instrumentation/spring-webflux-5/src/test/groovy/SpringWebfluxTest.groovy b/dd-java-agent/instrumentation/spring-webflux-5/src/test/groovy/SpringWebfluxTest.groovy index 54508fbc26..f94e1cd0b5 100644 --- a/dd-java-agent/instrumentation/spring-webflux-5/src/test/groovy/SpringWebfluxTest.groovy +++ b/dd-java-agent/instrumentation/spring-webflux-5/src/test/groovy/SpringWebfluxTest.groovy @@ -84,7 +84,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url @@ -158,7 +157,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url @@ -219,7 +217,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url @@ -284,7 +281,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url @@ -327,7 +323,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url @@ -401,7 +396,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url @@ -451,7 +445,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" finalUrl @@ -514,7 +507,6 @@ class SpringWebfluxTest extends AgentTestRunner { tags { "$Tags.COMPONENT" "netty" "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" "localhost" "$Tags.PEER_HOST_IPV4" "127.0.0.1" "$Tags.PEER_PORT" Integer "$Tags.HTTP_URL" url diff --git a/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/HandlerAdapterInstrumentation.java b/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/HandlerAdapterInstrumentation.java index ce682cc51f..e63f1e56cc 100644 --- a/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/HandlerAdapterInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/HandlerAdapterInstrumentation.java @@ -1,18 +1,16 @@ package datadog.trace.instrumentation.springweb; import static datadog.trace.agent.decorator.HttpServerDecorator.DD_SPAN_ATTRIBUTE; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activeSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.springweb.SpringWebHttpServerDecorator.DECORATE; import static java.util.Collections.singletonMap; -import static net.bytebuddy.matcher.ElementMatchers.isInterface; import static net.bytebuddy.matcher.ElementMatchers.isMethod; import static net.bytebuddy.matcher.ElementMatchers.isPublic; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.named; -import static net.bytebuddy.matcher.ElementMatchers.not; import static net.bytebuddy.matcher.ElementMatchers.takesArgument; import static net.bytebuddy.matcher.ElementMatchers.takesArguments; @@ -36,8 +34,7 @@ public final class HandlerAdapterInstrumentation extends Instrumenter.Default { @Override public ElementMatcher typeMatcher() { - return not(isInterface()) - .and(safeHasSuperType(named("org.springframework.web.servlet.HandlerAdapter"))); + return implementsInterface(named("org.springframework.web.servlet.HandlerAdapter")); } @Override diff --git a/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java b/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java index 1036dce911..1399fbc573 100644 --- a/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java +++ b/dd-java-agent/instrumentation/spring-webmvc-3.1/src/main/java/datadog/trace/instrumentation/springweb/SpringWebHttpServerDecorator.java @@ -60,11 +60,6 @@ public class SpringWebHttpServerDecorator null); } - @Override - protected String peerHostname(final HttpServletRequest httpServletRequest) { - return httpServletRequest.getRemoteHost(); - } - @Override protected String peerHostIP(final HttpServletRequest httpServletRequest) { return httpServletRequest.getRemoteAddr(); diff --git a/dd-java-agent/instrumentation/spring-webmvc-3.1/src/test/groovy/test/SpringBootBasedTest.groovy b/dd-java-agent/instrumentation/spring-webmvc-3.1/src/test/groovy/test/SpringBootBasedTest.groovy index 1e5e44f970..9ff4697894 100644 --- a/dd-java-agent/instrumentation/spring-webmvc-3.1/src/test/groovy/test/SpringBootBasedTest.groovy +++ b/dd-java-agent/instrumentation/spring-webmvc-3.1/src/test/groovy/test/SpringBootBasedTest.groovy @@ -128,7 +128,6 @@ class SpringBootBasedTest extends HttpServerTest typeMatcher() { - return safeHasSuperType(named("org.apache.catalina.loader.WebappClassLoaderBase")); - } - - @Override - public String[] helperClassNames() { - return new String[] {Constants.class.getName()}; - } - - @Override - public Map, String> transformers() { - return singletonMap( - isMethod() - .and(named("filter")) - .and(takesArgument(0, String.class)) - // Older versions have 1 argument method, newer versions have two arguments - .and(takesArguments(2).or(takesArguments(1))), - TomcatClassloadingInstrumentation.class.getName() + "$WebappClassLoaderAdvice"); - } - - public static class WebappClassLoaderAdvice { - @Advice.OnMethodExit(suppress = Throwable.class) - public static void methodExit( - @Advice.Argument(0) final String name, @Advice.Return(readOnly = false) boolean result) { - if (result) { - return; - } - for (final String prefix : Constants.BOOTSTRAP_PACKAGE_PREFIXES) { - if (name.startsWith(prefix)) { - result = true; - break; - } - } - } - } -} diff --git a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java index b557891110..9fa6ad989c 100644 --- a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java +++ b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceAnnotationsInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.trace_annotation; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static datadog.trace.instrumentation.trace_annotation.TraceConfigInstrumentation.PACKAGE_CLASS_NAME_REGEX; import static net.bytebuddy.matcher.ElementMatchers.declaresMethod; import static net.bytebuddy.matcher.ElementMatchers.is; diff --git a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java index 5be4930288..e9217453da 100644 --- a/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java +++ b/dd-java-agent/instrumentation/trace-annotation/src/main/java/datadog/trace/instrumentation/trace_annotation/TraceConfigInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.trace_annotation; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.safeHasSuperType; import static net.bytebuddy.matcher.ElementMatchers.named; import com.google.auto.service.AutoService; @@ -46,8 +46,8 @@ public class TraceConfigInstrumentation implements Instrumenter { private final Map> classMethodsToTrace; - private boolean validateConfigString(String configString) { - for (String segment : configString.split(";")) { + private boolean validateConfigString(final String configString) { + for (final String segment : configString.split(";")) { if (!segment.trim().matches(CONFIG_FORMAT)) { return false; } diff --git a/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioAsyncInstrumentation.java b/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioAsyncInstrumentation.java index 08a0b10d29..5eb21f110f 100644 --- a/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioAsyncInstrumentation.java +++ b/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioAsyncInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.twilio; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.twilio.TwilioClientDecorator.DECORATE; @@ -37,7 +37,7 @@ public class TwilioAsyncInstrumentation extends Instrumenter.Default { /** Match any child class of the base Twilio service classes. */ @Override public ElementMatcher typeMatcher() { - return safeHasSuperType( + return extendsClass( named("com.twilio.base.Creator") .or(named("com.twilio.base.Deleter")) .or(named("com.twilio.base.Fetcher")) diff --git a/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioSyncInstrumentation.java b/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioSyncInstrumentation.java index 734d102d3e..261309b1c1 100644 --- a/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioSyncInstrumentation.java +++ b/dd-java-agent/instrumentation/twilio/src/main/java/datadog/trace/instrumentation/twilio/TwilioSyncInstrumentation.java @@ -1,6 +1,6 @@ package datadog.trace.instrumentation.twilio; -import static datadog.trace.agent.tooling.ByteBuddyElementMatchers.safeHasSuperType; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.activateSpan; import static datadog.trace.bootstrap.instrumentation.api.AgentTracer.startSpan; import static datadog.trace.instrumentation.twilio.TwilioClientDecorator.DECORATE; @@ -35,7 +35,7 @@ public class TwilioSyncInstrumentation extends Instrumenter.Default { public net.bytebuddy.matcher.ElementMatcher< ? super net.bytebuddy.description.type.TypeDescription> typeMatcher() { - return safeHasSuperType( + return extendsClass( named("com.twilio.base.Creator") .or(named("com.twilio.base.Deleter")) .or(named("com.twilio.base.Fetcher")) diff --git a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy index 4739d5dc54..2e4e2ab001 100644 --- a/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy +++ b/dd-java-agent/testing/src/main/groovy/datadog/trace/agent/test/base/HttpServerTest.groovy @@ -526,7 +526,6 @@ abstract class HttpServerTest ext tags { "$Tags.COMPONENT" serverDecorator.component() "$Tags.SPAN_KIND" Tags.SPAN_KIND_SERVER - "$Tags.PEER_HOSTNAME" { it == "localhost" || it == "127.0.0.1" } "$Tags.PEER_PORT" Integer "$Tags.PEER_HOST_IPV4" { it == null || it == "127.0.0.1" } // Optional "$Tags.HTTP_URL" "${endpoint.resolve(address)}" diff --git a/dd-smoke-tests/springboot/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java b/dd-smoke-tests/springboot/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java index c80e4cc2aa..03cc979108 100644 --- a/dd-smoke-tests/springboot/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java +++ b/dd-smoke-tests/springboot/src/main/java/datadog/smoketest/springboot/SpringbootApplication.java @@ -1,5 +1,6 @@ package datadog.smoketest.springboot; +import java.lang.management.ManagementFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -8,5 +9,6 @@ public class SpringbootApplication { public static void main(final String[] args) { SpringApplication.run(SpringbootApplication.class, args); + System.out.println("Started in " + ManagementFactory.getRuntimeMXBean().getUptime() + "ms"); } } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/Config.java b/dd-trace-api/src/main/java/datadog/trace/api/Config.java index bee68ea85e..e52a915620 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/Config.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/Config.java @@ -58,6 +58,8 @@ public class Config { public static final String TRACE_RESOLVER_ENABLED = "trace.resolver.enabled"; public static final String SERVICE_MAPPING = "service.mapping"; + public static final String TAGS = "tags"; + @Deprecated // Use dd.tags instead public static final String GLOBAL_TAGS = "trace.global.tags"; public static final String SPAN_TAGS = "trace.span.tags"; public static final String JMX_TAGS = "trace.jmx.tags"; @@ -168,7 +170,7 @@ public class Config { public static final boolean DEFAULT_PROFILING_ENABLED = false; public static final String DEFAULT_PROFILING_URL = - "https://beta-intake.profile.datadoghq.com/v1/input"; + "https://intake.profile.datadoghq.com/v1/input"; public static final int DEFAULT_PROFILING_STARTUP_DELAY = 10; public static final int DEFAULT_PROFILING_UPLOAD_PERIOD = 60; // 1 min public static final int DEFAULT_PROFILING_UPLOAD_TIMEOUT = 30; // seconds @@ -211,7 +213,8 @@ public class Config { @Getter private final boolean prioritySamplingEnabled; @Getter private final boolean traceResolverEnabled; @Getter private final Map serviceMapping; - private final Map globalTags; + private final Map tags; + @Deprecated private final Map globalTags; private final Map spanTags; private final Map jmxTags; @Getter private final List excludedClasses; @@ -303,6 +306,7 @@ public class Config { getBooleanSettingFromEnvironment(TRACE_RESOLVER_ENABLED, DEFAULT_TRACE_RESOLVER_ENABLED); serviceMapping = getMapSettingFromEnvironment(SERVICE_MAPPING, null); + tags = getMapSettingFromEnvironment(TAGS, null); globalTags = getMapSettingFromEnvironment(GLOBAL_TAGS, null); spanTags = getMapSettingFromEnvironment(SPAN_TAGS, null); jmxTags = getMapSettingFromEnvironment(JMX_TAGS, null); @@ -485,6 +489,7 @@ public class Config { getPropertyBooleanValue(properties, TRACE_RESOLVER_ENABLED, parent.traceResolverEnabled); serviceMapping = getPropertyMapValue(properties, SERVICE_MAPPING, parent.serviceMapping); + tags = getPropertyMapValue(properties, TAGS, parent.tags); globalTags = getPropertyMapValue(properties, GLOBAL_TAGS, parent.globalTags); spanTags = getPropertyMapValue(properties, SPAN_TAGS, parent.spanTags); jmxTags = getPropertyMapValue(properties, JMX_TAGS, parent.jmxTags); @@ -638,9 +643,9 @@ public class Config { } public Map getMergedSpanTags() { - // DO not include runtimeId into span tags: we only want that added to the root span - final Map result = newHashMap(globalTags.size() + spanTags.size()); - result.putAll(globalTags); + // Do not include runtimeId into span tags: we only want that added to the root span + final Map result = newHashMap(getGlobalTags().size() + spanTags.size()); + result.putAll(getGlobalTags()); result.putAll(spanTags); return Collections.unmodifiableMap(result); } @@ -649,8 +654,8 @@ public class Config { final Map runtimeTags = getRuntimeTags(); final Map result = newHashMap( - globalTags.size() + jmxTags.size() + runtimeTags.size() + 1 /* for serviceName */); - result.putAll(globalTags); + getGlobalTags().size() + jmxTags.size() + runtimeTags.size() + 1 /* for serviceName */); + result.putAll(getGlobalTags()); result.putAll(jmxTags); result.putAll(runtimeTags); // service name set here instead of getRuntimeTags because apm already manages the service tag @@ -665,12 +670,12 @@ public class Config { final String host = getHostName(); final Map result = newHashMap( - globalTags.size() + getGlobalTags().size() + profilingTags.size() + runtimeTags.size() + 3 /* for serviceName and host and language */); result.put(HOST_TAG, host); // Host goes first to allow to override it - result.putAll(globalTags); + result.putAll(getGlobalTags()); result.putAll(profilingTags); result.putAll(runtimeTags); // service name set here instead of getRuntimeTags because apm already manages the service tag @@ -694,6 +699,14 @@ public class Config { return DEFAULT_ANALYTICS_SAMPLE_RATE; } + /** + * Provide 'global' tags, i.e. tags set everywhere. We have to support old (dd.trace.global.tags) + * version of this setting if new (dd.tags) version has not been specified. + */ + private Map getGlobalTags() { + return tags.isEmpty() ? globalTags : tags; + } + /** * Return a map of tags required by the datadog backend to link runtime metrics (i.e. jmx) and * traces. diff --git a/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy b/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy index 9f994204d2..c42adc0ea4 100644 --- a/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy +++ b/dd-trace-api/src/test/groovy/datadog/trace/api/ConfigTest.groovy @@ -56,6 +56,7 @@ import static datadog.trace.api.Config.SERVICE_NAME import static datadog.trace.api.Config.SERVICE_TAG import static datadog.trace.api.Config.SPAN_TAGS import static datadog.trace.api.Config.SPLIT_BY_TAGS +import static datadog.trace.api.Config.TAGS import static datadog.trace.api.Config.TRACE_AGENT_PORT import static datadog.trace.api.Config.TRACE_ENABLED import static datadog.trace.api.Config.TRACE_RATE_LIMIT @@ -76,8 +77,11 @@ class ConfigTest extends DDSpecification { private static final DD_TRACE_ENABLED_ENV = "DD_TRACE_ENABLED" private static final DD_WRITER_TYPE_ENV = "DD_WRITER_TYPE" private static final DD_SERVICE_MAPPING_ENV = "DD_SERVICE_MAPPING" - private static final DD_SPAN_TAGS_ENV = "DD_SPAN_TAGS" - private static final DD_HEADER_TAGS_ENV = "DD_HEADER_TAGS" + private static final DD_TAGS_ENV = "DD_TAGS" + private static final DD_GLOBAL_TAGS_ENV = "DD_TRACE_GLOBAL_TAGS" + private static final DD_SPAN_TAGS_ENV = "DD_TRACE_SPAN_TAGS" + private static final DD_HEADER_TAGS_ENV = "DD_TRACE_HEADER_TAGS" + private static final DD_JMX_TAGS_ENV = "DD_TRACE_JMX_TAGS" private static final DD_PROPAGATION_STYLE_EXTRACT = "DD_PROPAGATION_STYLE_EXTRACT" private static final DD_PROPAGATION_STYLE_INJECT = "DD_PROPAGATION_STYLE_INJECT" private static final DD_JMXFETCH_METRICS_CONFIGS_ENV = "DD_JMXFETCH_METRICS_CONFIGS" @@ -85,8 +89,9 @@ class ConfigTest extends DDSpecification { private static final DD_AGENT_PORT_LEGACY_ENV = "DD_AGENT_PORT" private static final DD_TRACE_REPORT_HOSTNAME = "DD_TRACE_REPORT_HOSTNAME" - private static final DD_PROFILING_API_KEY = "DD_PROFILING_API_KEY" - private static final DD_PROFILING_API_KEY_OLD = "DD_PROFILING_APIKEY" + private static final DD_PROFILING_API_KEY_ENV = "DD_PROFILING_API_KEY" + private static final DD_PROFILING_API_KEY_OLD_ENV = "DD_PROFILING_APIKEY" + private static final DD_PROFILING_TAGS_ENV = "DD_PROFILING_TAGS" def "verify defaults"() { when: @@ -379,7 +384,7 @@ class ConfigTest extends DDSpecification { environmentVariables.set(DD_PROPAGATION_STYLE_INJECT, "Datadog B3") environmentVariables.set(DD_JMXFETCH_METRICS_CONFIGS_ENV, "some/file") environmentVariables.set(DD_TRACE_REPORT_HOSTNAME, "true") - environmentVariables.set(DD_PROFILING_API_KEY, "test-api-key") + environmentVariables.set(DD_PROFILING_API_KEY_ENV, "test-api-key") when: def config = new Config() @@ -990,7 +995,7 @@ class ConfigTest extends DDSpecification { def "verify api key loaded from file: #path"() { setup: - environmentVariables.set(DD_PROFILING_API_KEY, "default-api-key") + environmentVariables.set(DD_PROFILING_API_KEY_ENV, "default-api-key") System.setProperty(PREFIX + PROFILING_API_KEY_FILE, path) when: @@ -1007,7 +1012,7 @@ class ConfigTest extends DDSpecification { def "verify api key loaded from file for old option name: #path"() { setup: - environmentVariables.set(DD_PROFILING_API_KEY_OLD, "default-api-key") + environmentVariables.set(DD_PROFILING_API_KEY_OLD_ENV, "default-api-key") System.setProperty(PREFIX + PROFILING_API_KEY_FILE_OLD, path) when: @@ -1033,4 +1038,65 @@ class ConfigTest extends DDSpecification { then: config.profilingApiKey == "test-api-key" } + + def "verify dd.tags overrides global tags in properties"() { + setup: + def prop = new Properties() + prop.setProperty(TAGS, "a:1") + prop.setProperty(GLOBAL_TAGS, "b:2") + prop.setProperty(SPAN_TAGS, "c:3") + prop.setProperty(JMX_TAGS, "d:4") + prop.setProperty(HEADER_TAGS, "e:5") + prop.setProperty(PROFILING_TAGS, "f:6") + + when: + Config config = Config.get(prop) + + then: + config.mergedSpanTags == [a: "1", c: "3"] + config.mergedJmxTags == [a: "1", d: "4", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName] + config.headerTags == [e: "5"] + + config.mergedProfilingTags == [a: "1", f: "6", (HOST_TAG): config.getHostName(), (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] + } + + def "verify dd.tags overrides global tags in system properties"() { + setup: + System.setProperty(PREFIX + TAGS, "a:1") + System.setProperty(PREFIX + GLOBAL_TAGS, "b:2") + System.setProperty(PREFIX + SPAN_TAGS, "c:3") + System.setProperty(PREFIX + JMX_TAGS, "d:4") + System.setProperty(PREFIX + HEADER_TAGS, "e:5") + System.setProperty(PREFIX + PROFILING_TAGS, "f:6") + + when: + Config config = new Config() + + then: + config.mergedSpanTags == [a: "1", c: "3"] + config.mergedJmxTags == [a: "1", d: "4", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName] + config.headerTags == [e: "5"] + + config.mergedProfilingTags == [a: "1", f: "6", (HOST_TAG): config.getHostName(), (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] + } + + def "verify dd.tags overrides global tags in env variables"() { + setup: + environmentVariables.set(DD_TAGS_ENV, "a:1") + environmentVariables.set(DD_GLOBAL_TAGS_ENV, "b:2") + environmentVariables.set(DD_SPAN_TAGS_ENV, "c:3") + environmentVariables.set(DD_JMX_TAGS_ENV, "d:4") + environmentVariables.set(DD_HEADER_TAGS_ENV, "e:5") + environmentVariables.set(DD_PROFILING_TAGS_ENV, "f:6") + + when: + Config config = new Config() + + then: + config.mergedSpanTags == [a: "1", c: "3"] + config.mergedJmxTags == [a: "1", d: "4", (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName] + config.headerTags == [e: "5"] + + config.mergedProfilingTags == [a: "1", f: "6", (HOST_TAG): config.getHostName(), (RUNTIME_ID_TAG): config.getRuntimeId(), (SERVICE_TAG): config.serviceName, (LANGUAGE_TAG_KEY): LANGUAGE_TAG_VALUE] + } } diff --git a/dd-trace-java.gradle b/dd-trace-java.gradle index d89b6cd7f6..d02591f7b6 100644 --- a/dd-trace-java.gradle +++ b/dd-trace-java.gradle @@ -16,7 +16,7 @@ def isCI = System.getenv("CI") != null allprojects { group = 'com.datadoghq' - version = '0.44.0-SNAPSHOT' + version = '0.45.0-SNAPSHOT' if (isCI) { buildDir = "${rootDir}/workspace/${projectDir.path.replace(rootDir.path, '')}/build/" diff --git a/dd-trace-ot/dd-trace-ot.gradle b/dd-trace-ot/dd-trace-ot.gradle index 3d5772654e..9ec332506d 100644 --- a/dd-trace-ot/dd-trace-ot.gradle +++ b/dd-trace-ot/dd-trace-ot.gradle @@ -17,7 +17,8 @@ excludedClassesCoverage += [ 'datadog.trace.common.sampling.PrioritySampling', // This code is copied from okHttp samples and we have integration tests to verify that it works. 'datadog.trace.common.writer.unixdomainsockets.TunnelingUnixSocket', - 'datadog.trace.common.writer.unixdomainsockets.UnixDomainSocketFactory' + 'datadog.trace.common.writer.unixdomainsockets.UnixDomainSocketFactory', + 'datadog.opentracing.StringCachingBigInteger' ] apply plugin: 'org.unbroken-dome.test-sets' @@ -138,7 +139,7 @@ jmh { // warmupBenchmarks = ['.*Warmup'] // Warmup benchmarks to include in the run in addition to already selected. JMH will not measure these benchmarks, but only use them for the warmup. // zip64 = true // Use ZIP64 format for bigger archives - jmhVersion = '1.21' // Specifies JMH version + jmhVersion = '1.23' // Specifies JMH version // includeTests = true // Allows to include test sources into generate JMH jar, i.e. use it when benchmarks depend on the test classes. duplicateClassesStrategy = 'warn' // Strategy to apply when encountring duplicate classes during creation of the fat jar (i.e. while executing jmhJar task) diff --git a/dd-trace-ot/jfr-openjdk/src/test/groovy/ScopeEventTest.groovy b/dd-trace-ot/jfr-openjdk/src/test/groovy/ScopeEventTest.groovy index b5f6e02899..a687ac9655 100644 --- a/dd-trace-ot/jfr-openjdk/src/test/groovy/ScopeEventTest.groovy +++ b/dd-trace-ot/jfr-openjdk/src/test/groovy/ScopeEventTest.groovy @@ -37,8 +37,9 @@ class ScopeEventTest extends Specification { false, "fakeType", null, - new PendingTrace(tracer, 123, [:]), - tracer) + new PendingTrace(tracer, 123), + tracer, + [:]) def builder = tracer.buildSpan("test operation") .asChildOf(parentContext) .withServiceName("test service") diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/DDSpanContext.java b/dd-trace-ot/src/main/java/datadog/opentracing/DDSpanContext.java index 766cc82f2a..88e0974135 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDSpanContext.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDSpanContext.java @@ -72,6 +72,8 @@ public class DDSpanContext implements io.opentracing.SpanContext { private final String threadName = Thread.currentThread().getName(); private final long threadId = Thread.currentThread().getId(); + private final Map serviceNameMappings; + public DDSpanContext( final BigInteger traceId, final BigInteger spanId, @@ -86,7 +88,8 @@ public class DDSpanContext implements io.opentracing.SpanContext { final String spanType, final Map tags, final PendingTrace trace, - final DDTracer tracer) { + final DDTracer tracer, + final Map serviceNameMappings) { assert tracer != null; assert trace != null; @@ -110,7 +113,8 @@ public class DDSpanContext implements io.opentracing.SpanContext { this.tags.putAll(tags); } - this.serviceName = serviceName; + this.serviceNameMappings = serviceNameMappings; + setServiceName(serviceName); this.operationName = operationName; this.resourceName = resourceName; this.errorFlag = errorFlag; @@ -155,7 +159,11 @@ public class DDSpanContext implements io.opentracing.SpanContext { } public void setServiceName(final String serviceName) { - this.serviceName = serviceName; + if (serviceNameMappings.containsKey(serviceName)) { + this.serviceName = serviceNameMappings.get(serviceName); + } else { + this.serviceName = serviceName; + } } public String getResourceName() { @@ -292,6 +300,7 @@ public class DDSpanContext implements io.opentracing.SpanContext { return trace; } + @Deprecated public DDTracer getTracer() { return tracer; } diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java index 5c803618f2..0c2782a1db 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/DDTracer.java @@ -411,7 +411,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace } @Override - public DDSpanBuilder buildSpan(final String operationName) { + public SpanBuilder buildSpan(final String operationName) { return new DDSpanBuilder(operationName, scopeManager); } @@ -592,13 +592,13 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace return this; } - private DDSpan startSpan() { + private Span startSpan() { return new DDSpan(timestampMicro, buildSpanContext()); } @Override public Scope startActive(final boolean finishSpanOnClose) { - final DDSpan span = startSpan(); + final Span span = startSpan(); final Scope scope = scopeManager.activate(span, finishSpanOnClose); log.debug("Starting a new active span: {}", span); return scope; @@ -606,13 +606,13 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace @Override @Deprecated - public DDSpan startManual() { + public Span startManual() { return start(); } @Override - public DDSpan start() { - final DDSpan span = startSpan(); + public Span start() { + final Span span = startSpan(); log.debug("Starting a new span: {}", span); return span; } @@ -716,7 +716,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace // case BigInteger value; do { - value = new BigInteger(63, ThreadLocalRandom.current()); + value = new StringCachingBigInteger(63, ThreadLocalRandom.current()); } while (value.signum() == 0); return value; @@ -788,7 +788,7 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace tags.putAll(localRootSpanTags); - parentTrace = new PendingTrace(DDTracer.this, traceId, serviceNameMappings); + parentTrace = new PendingTrace(DDTracer.this, traceId); } if (serviceName == null) { @@ -813,7 +813,8 @@ public class DDTracer implements io.opentracing.Tracer, Closeable, datadog.trace spanType, tags, parentTrace, - DDTracer.this); + DDTracer.this, + serviceNameMappings); // Apply Decorators to handle any tags that may have been set via the builder. for (final Map.Entry tag : tags.entrySet()) { diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java b/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java index 60a4fc26fa..b8317b0afe 100644 --- a/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java +++ b/dd-trace-ot/src/main/java/datadog/opentracing/PendingTrace.java @@ -12,7 +12,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; @@ -28,7 +27,6 @@ public class PendingTrace extends ConcurrentLinkedDeque { private final DDTracer tracer; private final BigInteger traceId; - private final Map serviceNameMappings; // TODO: consider moving these time fields into DDTracer to ensure that traces have precise // relative time @@ -60,13 +58,9 @@ public class PendingTrace extends ConcurrentLinkedDeque { /** Ensure a trace is never written multiple times */ private final AtomicBoolean isWritten = new AtomicBoolean(false); - PendingTrace( - final DDTracer tracer, - final BigInteger traceId, - final Map serviceNameMappings) { + PendingTrace(final DDTracer tracer, final BigInteger traceId) { this.tracer = tracer; this.traceId = traceId; - this.serviceNameMappings = serviceNameMappings; startTimeNano = Clock.currentNanoTime(); startNanoTicks = Clock.currentNanoTicks(); @@ -150,10 +144,6 @@ public class PendingTrace extends ConcurrentLinkedDeque { } if (!isWritten.get()) { - if (serviceNameMappings.containsKey(span.getServiceName())) { - span.setServiceName(serviceNameMappings.get(span.getServiceName())); - } - addFirst(span); } else { log.debug("{} - finished after trace reported.", span); diff --git a/dd-trace-ot/src/main/java/datadog/opentracing/StringCachingBigInteger.java b/dd-trace-ot/src/main/java/datadog/opentracing/StringCachingBigInteger.java new file mode 100644 index 0000000000..9f55278fde --- /dev/null +++ b/dd-trace-ot/src/main/java/datadog/opentracing/StringCachingBigInteger.java @@ -0,0 +1,56 @@ +package datadog.opentracing; + +import java.math.BigInteger; +import java.util.Random; + +/** + * Because we are using BigInteger for Trace and Span Id, the toString() operator may result in + * heavy computation and string allocation overhead. In order to limit this, we are caching the + * result of toString, thereby taking advantage of the immutability of BigInteger. + */ +public class StringCachingBigInteger extends BigInteger { + + private String cachedString; + + public StringCachingBigInteger(byte[] val) { + super(val); + } + + public StringCachingBigInteger(int signum, byte[] magnitude) { + super(signum, magnitude); + } + + public StringCachingBigInteger(String val, int radix) { + super(val, radix); + } + + public StringCachingBigInteger(String val) { + super(val); + } + + public StringCachingBigInteger(int numBits, Random rnd) { + super(numBits, rnd); + } + + public StringCachingBigInteger(int bitLength, int certainty, Random rnd) { + super(bitLength, certainty, rnd); + } + + @Override + public String toString() { + if (cachedString == null) { + this.cachedString = super.toString(); + } + return cachedString; + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + + @Override + public int hashCode() { + return super.hashCode(); + } +} diff --git a/dd-trace-ot/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java b/dd-trace-ot/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java index a0a0f7ad02..43199a4eab 100644 --- a/dd-trace-ot/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java +++ b/dd-trace-ot/src/main/java/datadog/trace/common/writer/ddagent/DDAgentApi.java @@ -60,30 +60,16 @@ public class DDAgentApi { Types.newParameterizedType(Map.class, String.class, Double.class))); private static final MediaType MSGPACK = MediaType.get("application/msgpack"); - private final OkHttpClient httpClient; - private final HttpUrl tracesUrl; + private final String host; + private final int port; + private final String unixDomainSocketPath; + private OkHttpClient httpClient; + private HttpUrl tracesUrl; public DDAgentApi(final String host, final int port, final String unixDomainSocketPath) { - this( - host, - port, - endpointAvailable(getUrl(host, port, TRACES_ENDPOINT_V4), unixDomainSocketPath, true), - unixDomainSocketPath); - } - - DDAgentApi( - final String host, - final int port, - final boolean v4EndpointsAvailable, - final String unixDomainSocketPath) { - httpClient = buildHttpClient(unixDomainSocketPath); - - if (v4EndpointsAvailable) { - tracesUrl = getUrl(host, port, TRACES_ENDPOINT_V4); - } else { - log.debug("API v0.4 endpoints not available. Downgrading to v0.3"); - tracesUrl = getUrl(host, port, TRACES_ENDPOINT_V3); - } + this.host = host; + this.port = port; + this.unixDomainSocketPath = unixDomainSocketPath; } public void addResponseListener(final DDAgentResponseListener listener) { @@ -128,6 +114,10 @@ public class DDAgentApi { Response sendSerializedTraces( final int representativeCount, final Integer sizeInBytes, final List traces) { + if (httpClient == null) { + detectEndpointAndBuildClient(); + } + try { final RequestBody body = new RequestBody() { @@ -298,6 +288,19 @@ public class DDAgentApi { } } + private synchronized void detectEndpointAndBuildClient() { + if (httpClient == null) { + final HttpUrl v4Url = getUrl(host, port, TRACES_ENDPOINT_V4); + if (endpointAvailable(v4Url, unixDomainSocketPath, true)) { + tracesUrl = v4Url; + } else { + log.debug("API v0.4 endpoints not available. Downgrading to v0.3"); + tracesUrl = getUrl(host, port, TRACES_ENDPOINT_V3); + } + httpClient = buildHttpClient(unixDomainSocketPath); + } + } + @Override public String toString() { return "DDApi { tracesUrl=" + tracesUrl + " }"; diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy index 8c194c9a5a..8c753ce8f1 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanBuilderTest.groovy @@ -156,7 +156,7 @@ class DDSpanBuilderTest extends DDSpecification { 1 * mockedContext.getSpanId() >> spanId _ * mockedContext.getServiceName() >> "foo" 1 * mockedContext.getBaggageItems() >> [:] - 1 * mockedContext.getTrace() >> new PendingTrace(tracer, 1G, [:]) + 1 * mockedContext.getTrace() >> new PendingTrace(tracer, 1G) final String expectedName = "fakeName" diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanSerializationTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanSerializationTest.groovy index 7e3ee405b2..fa8d46580a 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanSerializationTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanSerializationTest.groovy @@ -60,8 +60,9 @@ class DDSpanSerializationTest extends DDSpecification { false, spanType, ["k1": "v1"], - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) DDSpan span = new DDSpan(100L, context) @@ -95,8 +96,9 @@ class DDSpanSerializationTest extends DDSpecification { false, spanType, Collections.emptyMap(), - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) def span = new DDSpan(0, context) def buffer = new ArrayBufferOutput() def packer = MessagePack.newDefaultPacker(buffer) diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy index 88de2df8df..0cbc4c58c0 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/DDSpanTest.groovy @@ -35,8 +35,9 @@ class DDSpanTest extends DDSpecification { false, "fakeType", null, - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) final DDSpan span = new DDSpan(1L, context) diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/PendingTraceTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/PendingTraceTest.groovy index 6613e74706..00c027fb0f 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/PendingTraceTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/PendingTraceTest.groovy @@ -28,7 +28,7 @@ class PendingTraceTest extends DDSpecification { BigInteger traceId = BigInteger.valueOf(System.identityHashCode(this)) @Subject - PendingTrace trace = new PendingTrace(tracer, traceId, [:]) + PendingTrace trace = new PendingTrace(tracer, traceId) DDSpan rootSpan = SpanFactory.newSpanOf(trace) @@ -147,7 +147,7 @@ class PendingTraceTest extends DDSpecification { def "register span to wrong trace fails"() { setup: - def otherTrace = new PendingTrace(tracer, traceId - 10, [:]) + def otherTrace = new PendingTrace(tracer, traceId - 10) otherTrace.registerSpan(new DDSpan(0, rootSpan.context())) expect: @@ -158,7 +158,7 @@ class PendingTraceTest extends DDSpecification { def "add span to wrong trace fails"() { setup: - def otherTrace = new PendingTrace(tracer, traceId - 10, [:]) + def otherTrace = new PendingTrace(tracer, traceId - 10) rootSpan.finish() otherTrace.addSpan(rootSpan) @@ -196,7 +196,7 @@ class PendingTraceTest extends DDSpecification { properties.setProperty(PARTIAL_FLUSH_MIN_SPANS, "1") def config = Config.get(properties) def tracer = DDTracer.builder().config(config).writer(writer).build() - def trace = new PendingTrace(tracer, traceId, [:]) + def trace = new PendingTrace(tracer, traceId) def rootSpan = SpanFactory.newSpanOf(trace) def child1 = tracer.buildSpan("child1").asChildOf(rootSpan).start() def child2 = tracer.buildSpan("child2").asChildOf(rootSpan).start() @@ -242,7 +242,7 @@ class PendingTraceTest extends DDSpecification { properties.setProperty(PARTIAL_FLUSH_MIN_SPANS, "1") def config = Config.get(properties) def tracer = DDTracer.builder().config(config).writer(writer).build() - def trace = new PendingTrace(tracer, traceId, [:]) + def trace = new PendingTrace(tracer, traceId) def rootSpan = SpanFactory.newSpanOf(trace) def child1 = tracer.buildSpan("child1").asChildOf(rootSpan).start() def child2 = tracer.buildSpan("child2").asChildOf(rootSpan).start() diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/SpanFactory.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/SpanFactory.groovy index 5b1028c969..20a4985d2a 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/SpanFactory.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/SpanFactory.groovy @@ -24,8 +24,8 @@ class SpanFactory { false, "fakeType", Collections.emptyMap(), - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, [:]) Thread.currentThread().setName(currentThreadName) return new DDSpan(timestampMicro, context) } @@ -44,8 +44,8 @@ class SpanFactory { false, "fakeType", Collections.emptyMap(), - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, [:]) return new DDSpan(1, context) } @@ -64,7 +64,7 @@ class SpanFactory { "fakeType", Collections.emptyMap(), trace, - trace.tracer) + trace.tracer, [:]) return new DDSpan(1, context) } @@ -84,8 +84,9 @@ class SpanFactory { false, "fakeType", Collections.emptyMap(), - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) context.setTag("env", envName) return new DDSpan(0l, context) } diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy index 87744428b3..094b5d77ce 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/SpanDecoratorTest.groovy @@ -127,7 +127,7 @@ class SpanDecoratorTest extends DDSpecification { "other-context" | "my-service" | "my-service" } - def "set service name from servlet.context with context '#context' for service #serviceName"() { + def "mapping causes servlet.context to not change service name"() { setup: tracer = DDTracer.builder() .serviceName(serviceName) @@ -142,18 +142,12 @@ class SpanDecoratorTest extends DDSpecification { span.finish() then: - span.serviceName == expected + span.serviceName == "new-service" where: - context | serviceName | expected - "/" | DEFAULT_SERVICE_NAME | "new-service" - "" | DEFAULT_SERVICE_NAME | "new-service" - "/some-context" | DEFAULT_SERVICE_NAME | "some-context" - "other-context" | DEFAULT_SERVICE_NAME | "other-context" - "/" | "my-service" | "new-service" - "" | "my-service" | "new-service" - "/some-context" | "my-service" | "new-service" - "other-context" | "my-service" | "new-service" + context | serviceName + "/some-context" | DEFAULT_SERVICE_NAME + "/some-context" | "my-service" mapping = [(serviceName): "new-service"] } diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/URLAsResourceNameTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/URLAsResourceNameTest.groovy index 8f4366c7f5..85945089f9 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/URLAsResourceNameTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/decorators/URLAsResourceNameTest.groovy @@ -115,12 +115,13 @@ class URLAsResourceNameTest extends DDSpecification { "fakeResource", PrioritySampling.UNSET, null, - Collections. emptyMap(), + [:], false, "fakeType", tags, - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) then: decorator.shouldSetTag(context, Tags.HTTP_URL.getKey(), value) diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/B3HttpInjectorTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/B3HttpInjectorTest.groovy index 5634abcf96..82d802f17e 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/B3HttpInjectorTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/B3HttpInjectorTest.groovy @@ -40,8 +40,9 @@ class B3HttpInjectorTest extends DDSpecification { false, "fakeType", null, - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) final Map carrier = Mock() diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/DatadogHttpInjectorTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/DatadogHttpInjectorTest.groovy index b8433cc226..62a4602462 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/DatadogHttpInjectorTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/DatadogHttpInjectorTest.groovy @@ -42,8 +42,9 @@ class DatadogHttpInjectorTest extends DDSpecification { false, "fakeType", null, - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) final Map carrier = Mock() diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HaystackHttpInjectorTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HaystackHttpInjectorTest.groovy index d9f9276eeb..face24ac90 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HaystackHttpInjectorTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HaystackHttpInjectorTest.groovy @@ -40,8 +40,9 @@ class HaystackHttpInjectorTest extends DDSpecification { false, "fakeType", null, - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) final Map carrier = Mock() diff --git a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HttpInjectorTest.groovy b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HttpInjectorTest.groovy index 9aed342a91..fb08150cd6 100644 --- a/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HttpInjectorTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/opentracing/propagation/HttpInjectorTest.groovy @@ -45,8 +45,9 @@ class HttpInjectorTest extends DDSpecification { false, "fakeType", null, - new PendingTrace(tracer, 1G, [:]), - tracer) + new PendingTrace(tracer, 1G), + tracer, + [:]) final Map carrier = Mock() diff --git a/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy b/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy index de8e2dcbec..3ade91e971 100644 --- a/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/trace/DDTracerTest.groovy @@ -46,10 +46,6 @@ class DDTracerTest extends DDSpecification { tracer.serviceName == "unnamed-java-app" tracer.sampler instanceof RateByServiceSampler tracer.writer instanceof DDAgentWriter - ((DDAgentWriter) tracer.writer).api.tracesUrl.host() == "localhost" - ((DDAgentWriter) tracer.writer).api.tracesUrl.port() == 8126 - ((DDAgentWriter) tracer.writer).api.tracesUrl.encodedPath() == "/v0.3/traces" || - ((DDAgentWriter) tracer.writer).api.tracesUrl.encodedPath() == "/v0.4/traces" tracer.writer.monitor instanceof Monitor.Noop tracer.spanContextDecorators.size() == 15 @@ -117,9 +113,9 @@ class DDTracerTest extends DDSpecification { when: System.setProperty(PREFIX + key, value) def tracer = DDTracer.builder().config(new Config()).build() - then: tracer.writer instanceof DDAgentWriter + ((DDAgentWriter) tracer.writer).api.sendTraces([]) ((DDAgentWriter) tracer.writer).api.tracesUrl.host() == value ((DDAgentWriter) tracer.writer).api.tracesUrl.port() == 8126 @@ -135,6 +131,7 @@ class DDTracerTest extends DDSpecification { then: tracer.writer instanceof DDAgentWriter + ((DDAgentWriter) tracer.writer).api.sendTraces([]) ((DDAgentWriter) tracer.writer).api.tracesUrl.host() == "localhost" ((DDAgentWriter) tracer.writer).api.tracesUrl.port() == Integer.valueOf(value) diff --git a/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentApiTest.groovy b/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentApiTest.groovy index 6e6a0fb5e6..e5737d0460 100644 --- a/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentApiTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentApiTest.groovy @@ -34,10 +34,10 @@ class DDAgentApiTest extends DDSpecification { def client = new DDAgentApi("localhost", agent.address.port, null) expect: - client.tracesUrl.toString() == "http://localhost:${agent.address.port}/v0.4/traces" def response = client.sendTraces([]) response.success() response.status() == 200 + agent.getLastRequest().path == "/v0.4/traces" cleanup: agent.close() @@ -50,16 +50,19 @@ class DDAgentApiTest extends DDSpecification { put("v0.4/traces") { response.status(404).send() } + + put("v0.3/traces") { + response.status(404).send() + } } } def client = new DDAgentApi("localhost", agent.address.port, null) expect: - client.tracesUrl.toString() == "http://localhost:${agent.address.port}/v0.3/traces" - def response = client.sendTraces([]) !response.success() response.status() == 404 + agent.getLastRequest().path == "/v0.3/traces" cleanup: agent.close() @@ -77,7 +80,6 @@ class DDAgentApiTest extends DDSpecification { def client = new DDAgentApi("localhost", agent.address.port, null) expect: - client.tracesUrl.toString() == "http://localhost:${agent.address.port}/v0.4/traces" client.sendTraces(traces).success() agent.lastRequest.contentType == "application/msgpack" agent.lastRequest.headers.get("Datadog-Meta-Lang") == "java" @@ -166,8 +168,8 @@ class DDAgentApiTest extends DDSpecification { def client = new DDAgentApi("localhost", v3Agent.address.port, null) expect: - client.tracesUrl.toString() == "http://localhost:${v3Agent.address.port}/v0.3/traces" client.sendTraces([]).success() + v3Agent.getLastRequest().path == "/v0.3/traces" cleanup: v3Agent.close() @@ -191,9 +193,13 @@ class DDAgentApiTest extends DDSpecification { } def port = badPort ? 999 : agent.address.port def client = new DDAgentApi("localhost", port, null) + def result = client.sendTraces([]) expect: - client.tracesUrl.toString() == "http://localhost:${port}/$endpointVersion/traces" + result.success() == !badPort // Expect success of port is ok + if (!badPort) { + assert agent.getLastRequest().path == "/$endpointVersion/traces" + } cleanup: agent.close() diff --git a/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentWriterTest.groovy b/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentWriterTest.groovy index e0a0342eae..8e8e5f1d07 100644 --- a/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentWriterTest.groovy +++ b/dd-trace-ot/src/test/groovy/datadog/trace/api/writer/DDAgentWriterTest.groovy @@ -201,12 +201,13 @@ class DDAgentWriterTest extends DDSpecification { "", PrioritySampling.UNSET, "", - Collections.emptyMap(), + [:], false, "", - Collections.emptyMap(), + [:], Mock(PendingTrace), - Mock(DDTracer)) + Mock(DDTracer), + [:]) minimalSpan = new DDSpan(0, minimalContext) minimalTrace = [minimalSpan] traceSize = calculateSize(minimalTrace) @@ -262,12 +263,13 @@ class DDAgentWriterTest extends DDSpecification { "", PrioritySampling.UNSET, "", - Collections.emptyMap(), + [:], false, "", - Collections.emptyMap(), + [:], Mock(PendingTrace), - Mock(DDTracer)) + Mock(DDTracer), + [:]) def minimalSpan = new DDSpan(0, minimalContext) def minimalTrace = [minimalSpan] diff --git a/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy b/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy index 620e85044d..fdc16e4e00 100644 --- a/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy +++ b/dd-trace-ot/src/traceAgentTest/groovy/DDApiIntegrationTest.groovy @@ -16,157 +16,137 @@ import java.time.Duration import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicReference -class DDApiIntegrationTest { - // Do not run tests locally on Java7 since testcontainers are not compatible with Java7 - // It is fine to run on CI because CI provides rabbitmq externally, not through testcontainers - @Requires({ "true" == System.getenv("CI") || jvm.java8Compatible }) - static class DDAgentApiIntegrationV4Test extends DDSpecification { - static final WRITER = new ListWriter() - static final TRACER = DDTracer.builder().writer(WRITER).build() - static final CONTEXT = new DDSpanContext( - 1G, - 1G, - 0G, - "fakeService", - "fakeOperation", - "fakeResource", - PrioritySampling.UNSET, - null, - Collections.emptyMap(), - false, - "fakeType", - Collections.emptyMap(), - new PendingTrace(TRACER, 1G, [:]), - TRACER) +// Do not run tests locally on Java7 since testcontainers are not compatible with Java7 +// It is fine to run on CI because CI provides agent externally, not through testcontainers +@Requires({ "true" == System.getenv("CI") || jvm.java8Compatible }) +class DDApiIntegrationTest extends DDSpecification { + static final WRITER = new ListWriter() + static final TRACER = DDTracer.builder().writer(WRITER).build() + static final CONTEXT = new DDSpanContext( + 1G, + 1G, + 0G, + "fakeService", + "fakeOperation", + "fakeResource", + PrioritySampling.UNSET, + null, + [:], + false, + "fakeType", + [:], + new PendingTrace(TRACER, 1G), + TRACER, + [:]) - // Looks like okHttp needs to resolve this, even for connection over socket - static final SOMEHOST = "datadoghq.com" - static final SOMEPORT = 123 + // Looks like okHttp needs to resolve this, even for connection over socket + static final SOMEHOST = "datadoghq.com" + static final SOMEPORT = 123 + + /* + Note: type here has to stay undefined, otherwise tests will fail in CI in Java 7 because + 'testcontainers' are built for Java 8 and Java 7 cannot load this class. + */ + @Shared + def agentContainer + @Shared + def agentContainerHost = "localhost" + @Shared + def agentContainerPort = 8126 + @Shared + Process process + @Shared + File socketPath + + def api + def unixDomainSocketApi + + def endpoint = new AtomicReference(null) + def agentResponse = new AtomicReference>>(null) + + DDAgentResponseListener responseListener = { String receivedEndpoint, Map> responseJson -> + endpoint.set(receivedEndpoint) + agentResponse.set(responseJson) + } + + def setupSpec() { /* - Note: type here has to stay undefined, otherwise tests will fail in CI in Java 7 because - 'testcontainers' are built for Java 8 and Java 7 cannot load this class. - */ - @Shared - def agentContainer - @Shared - def agentContainerHost = "localhost" - @Shared - def agentContainerPort = 8126 - @Shared - Process process - @Shared - File socketPath - - def api - def unixDomainSocketApi - - def endpoint = new AtomicReference(null) - def agentResponse = new AtomicReference>>(null) - - DDAgentResponseListener responseListener = { String receivedEndpoint, Map> responseJson -> - endpoint.set(receivedEndpoint) - agentResponse.set(responseJson) + CI will provide us with agent container running along side our build. + When building locally, however, we need to take matters into our own hands + and we use 'testcontainers' for this. + */ + if ("true" != System.getenv("CI")) { + agentContainer = new GenericContainer("datadog/docker-dd-agent:latest") + .withEnv(["DD_APM_ENABLED": "true", + "DD_BIND_HOST" : "0.0.0.0", + "DD_API_KEY" : "invalid_key_but_this_is_fine", + "DD_LOGS_STDOUT": "yes"]) + .withExposedPorts(datadog.trace.api.Config.DEFAULT_TRACE_AGENT_PORT) + .withStartupTimeout(Duration.ofSeconds(120)) + // Apparently we need to sleep for a bit so agent's response `{"service:,env:":1}` in rate_by_service. + // This is clearly a race-condition and maybe we should avoid verifying complete response + .withStartupCheckStrategy(new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(10))) + // .withLogConsumer { output -> + // print output.utf8String + // } + agentContainer.start() + agentContainerHost = agentContainer.containerIpAddress + agentContainerPort = agentContainer.getMappedPort(datadog.trace.api.Config.DEFAULT_TRACE_AGENT_PORT) } - def setupSpec() { + File tmpDir = File.createTempDir() + tmpDir.deleteOnExit() + socketPath = new File(tmpDir, "socket") + println "!!!socat UNIX-LISEN:${socketPath},reuseaddr,fork TCP-CONNECT:${agentContainerHost}:${agentContainerPort}" + process = Runtime.getRuntime().exec("socat UNIX-LISTEN:${socketPath},reuseaddr,fork TCP-CONNECT:${agentContainerHost}:${agentContainerPort}") + } - /* - CI will provide us with rabbitmq container running along side our build. - When building locally, however, we need to take matters into our own hands - and we use 'testcontainers' for this. - */ - if ("true" != System.getenv("CI")) { - agentContainer = new GenericContainer("datadog/docker-dd-agent:latest") - .withEnv(["DD_APM_ENABLED": "true", - "DD_BIND_HOST" : "0.0.0.0", - "DD_API_KEY" : "invalid_key_but_this_is_fine", - "DD_LOGS_STDOUT": "yes"]) - .withExposedPorts(datadog.trace.api.Config.DEFAULT_TRACE_AGENT_PORT) - .withStartupTimeout(Duration.ofSeconds(120)) - // Apparently we need to sleep for a bit so agent's response `{"service:,env:":1}` in rate_by_service. - // This is clearly a race-condition and maybe we should av oid verifying complete response - .withStartupCheckStrategy(new MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(10))) - // .withLogConsumer { output -> - // print output.utf8String - // } - agentContainer.start() - agentContainerHost = agentContainer.containerIpAddress - agentContainerPort = agentContainer.getMappedPort(datadog.trace.api.Config.DEFAULT_TRACE_AGENT_PORT) - } - - File tmpDir = File.createTempDir() - tmpDir.deleteOnExit() - socketPath = new File(tmpDir, "socket") - process = Runtime.getRuntime().exec("socat UNIX-LISTEN:${socketPath},reuseaddr,fork TCP-CONNECT:${agentContainerHost}:${agentContainerPort}") + def cleanupSpec() { + if (agentContainer) { + agentContainer.stop() } + process.destroy() + } - def cleanupSpec() { - if (agentContainer) { - agentContainer.stop() - } - process.destroy() - } + def setup() { + api = new DDAgentApi(agentContainerHost, agentContainerPort, null) + api.addResponseListener(responseListener) - def setup() { - api = new DDAgentApi(agentContainerHost, agentContainerPort, v4(), null) - api.addResponseListener(responseListener) + unixDomainSocketApi = new DDAgentApi(SOMEHOST, SOMEPORT, socketPath.toString()) + unixDomainSocketApi.addResponseListener(responseListener) + } - unixDomainSocketApi = new DDAgentApi(SOMEHOST, SOMEPORT, v4(), socketPath.toString()) - unixDomainSocketApi.addResponseListener(responseListener) - } + def "Sending traces succeeds (test #test)"() { + expect: + api.sendTraces(traces) + assert endpoint.get() == "http://${agentContainerHost}:${agentContainerPort}/v0.4/traces" + assert agentResponse.get() == [rate_by_service: ["service:,env:": 1]] - boolean v4() { - return true - } - - def "Sending traces succeeds (test #test)"() { - expect: - api.sendTraces(traces) - if (v4()) { - assert endpoint.get() == "http://${agentContainerHost}:${agentContainerPort}/v0.4/traces" - assert agentResponse.get() == [rate_by_service: ["service:,env:": 1]] - } - - where: - traces | test - [] | 1 - [[], []] | 2 - [[new DDSpan(1, CONTEXT)]] | 3 - [[new DDSpan(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()), CONTEXT)]] | 4 - (1..15).collect { [] } | 5 - (1..16).collect { [] } | 6 - // Larger traces take more than 1 second to send to the agent and get a timeout exception: + where: + traces | test + [] | 1 + [[], []] | 2 + [[new DDSpan(1, CONTEXT)]] | 3 + [[new DDSpan(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()), CONTEXT)]] | 4 + (1..15).collect { [] } | 5 + (1..16).collect { [] } | 6 + // Larger traces take more than 1 second to send to the agent and get a timeout exception: // (1..((1 << 16) - 1)).collect { [] } | 7 // (1..(1 << 16)).collect { [] } | 8 - } - - def "Sending traces to unix domain socket succeeds (test #test)"() { - expect: - unixDomainSocketApi.sendTraces(traces) - if (v4()) { - assert endpoint.get() == "http://${SOMEHOST}:${SOMEPORT}/v0.4/traces" - assert agentResponse.get() == [rate_by_service: ["service:,env:": 1]] - } - - where: - traces | test - [] | 1 - [[], []] | 2 - [[new DDSpan(1, CONTEXT)]] | 3 - [[new DDSpan(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()), CONTEXT)]] | 4 - } } - @Requires({ "true" == System.getenv("CI") || jvm.java8Compatible }) - static class DDAgentApiIntegrationV3Test extends DDAgentApiIntegrationV4Test { - boolean v4() { - return false - } + def "Sending traces to unix domain socket succeeds (test #test)"() { + expect: + unixDomainSocketApi.sendTraces(traces) + assert endpoint.get() == "http://${SOMEHOST}:${SOMEPORT}/v0.4/traces" + assert agentResponse.get() == [rate_by_service: ["service:,env:": 1]] - def cleanup() { - assert endpoint.get() == null - assert agentResponse.get() == null - } + where: + traces | test + [] | 1 + [[], []] | 2 + [[new DDSpan(1, CONTEXT)]] | 3 + [[new DDSpan(TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()), CONTEXT)]] | 4 } } diff --git a/settings.gradle b/settings.gradle index 1fc1e8d81c..d5fd3bc155 100644 --- a/settings.gradle +++ b/settings.gradle @@ -56,6 +56,10 @@ include ':dd-java-agent:instrumentation:apache-httpclient-4' include ':dd-java-agent:instrumentation:aws-java-sdk-1.11.0' include ':dd-java-agent:instrumentation:aws-java-sdk-2.2' include ':dd-java-agent:instrumentation:cdi-1.2' +include ':dd-java-agent:instrumentation:classloading' +include ':dd-java-agent:instrumentation:classloading:jboss-testing' +include ':dd-java-agent:instrumentation:classloading:osgi-testing' +include ':dd-java-agent:instrumentation:classloading:tomcat-testing' include ':dd-java-agent:instrumentation:couchbase-2.0' include ':dd-java-agent:instrumentation:couchbase-2.6' include ':dd-java-agent:instrumentation:datastax-cassandra-3' @@ -93,7 +97,6 @@ include ':dd-java-agent:instrumentation:java-concurrent:kotlin-testing' include ':dd-java-agent:instrumentation:java-concurrent:scala-testing' include ':dd-java-agent:instrumentation:java-concurrent:akka-testing' include ':dd-java-agent:instrumentation:java-concurrent:akka-2.5-testing' -include ':dd-java-agent:instrumentation:jboss-classloading' include ':dd-java-agent:instrumentation:jdbc' include ':dd-java-agent:instrumentation:jedis-1.4' include ':dd-java-agent:instrumentation:jedis-3.0' @@ -111,7 +114,6 @@ include ':dd-java-agent:instrumentation:mongo:driver-async-3.3' include ':dd-java-agent:instrumentation:netty-4.0' include ':dd-java-agent:instrumentation:netty-4.1' include ':dd-java-agent:instrumentation:okhttp-3' -include ':dd-java-agent:instrumentation:osgi-classloading' include ':dd-java-agent:instrumentation:play-2.4' include ':dd-java-agent:instrumentation:play-2.6' include ':dd-java-agent:instrumentation:play-ws-1' @@ -128,10 +130,10 @@ include ':dd-java-agent:instrumentation:servlet:request-3' include ':dd-java-agent:instrumentation:slf4j-mdc' include ':dd-java-agent:instrumentation:sparkjava-2.3' include ':dd-java-agent:instrumentation:spring-data-1.8' +include ':dd-java-agent:instrumentation:spring-scheduling-3.1' include ':dd-java-agent:instrumentation:spring-webmvc-3.1' include ':dd-java-agent:instrumentation:spring-webflux-5' include ':dd-java-agent:instrumentation:spymemcached-2.12' -include ':dd-java-agent:instrumentation:tomcat-classloading' include ':dd-java-agent:instrumentation:trace-annotation' include ':dd-java-agent:instrumentation:twilio' include ':dd-java-agent:instrumentation:vertx'