diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/AgentClassLoading.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/AgentClassLoading.java new file mode 100644 index 00000000000..1bdf2ed431d --- /dev/null +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/AgentClassLoading.java @@ -0,0 +1,34 @@ +package datadog.trace.bootstrap; + +/** + * Helps distinguish agent class-loading requests from application requests. + * + *

Should be used in a short try..finally block around the class-loader call. + */ +public enum AgentClassLoading { + /** Lightweight class-loader probing to select instrumentations. */ + PROBING_CLASSLOADER, + /** Locating class resources for Byte-Buddy. */ + LOCATING_CLASS, + /** Injecting helper classes into class-loaders. */ + INJECTING_HELPERS; + + private static final ThreadLocal REQUEST = new ThreadLocal<>(); + + /** + * Gets the current agent class-loading request type; {@code null} if there's no agent request. + */ + public static AgentClassLoading type() { + return REQUEST.get(); + } + + /** Records that this agent class-loading request has begun. */ + public final void begin() { + REQUEST.set(this); + } + + /** Records that this agent class-loading request has ended. */ + public final void end() { + REQUEST.remove(); + } +} 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 f49fd15aa8d..59e89692749 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,5 +1,7 @@ package datadog.trace.agent.tooling; +import static datadog.trace.bootstrap.AgentClassLoading.PROBING_CLASSLOADER; + import datadog.trace.api.Tracer; import datadog.trace.bootstrap.PatchLogger; import datadog.trace.bootstrap.WeakCache; @@ -140,12 +142,17 @@ private WeakCache getCache() { } private boolean hasResources(final ClassLoader cl) { - for (final String resource : resources) { - if (cl.getResource(resource) == null) { - return false; + PROBING_CLASSLOADER.begin(); + try { + for (final String resource : resources) { + if (cl.getResource(resource) == null) { + return false; + } } + return true; + } finally { + PROBING_CLASSLOADER.end(); } - return true; } @Override diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java index cea41875c1f..89170541021 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/HelperInjector.java @@ -1,6 +1,7 @@ package datadog.trace.agent.tooling; import static datadog.trace.agent.tooling.ClassLoaderMatcher.BOOTSTRAP_CLASSLOADER; +import static datadog.trace.bootstrap.AgentClassLoading.INJECTING_HELPERS; import datadog.trace.api.Config; import java.io.File; @@ -165,6 +166,7 @@ private Map> injectBootstrapClassLoader( // Failures to create a tempDir are propagated as IOException and handled by transform final File tempDir = createTempDir(); + INJECTING_HELPERS.begin(); try { return ClassInjector.UsingInstrumentation.of( tempDir, @@ -172,6 +174,7 @@ private Map> injectBootstrapClassLoader( AgentInstaller.getInstrumentation()) .injectRaw(classnameToBytes); } finally { + INJECTING_HELPERS.end(); // Delete fails silently deleteTempDir(tempDir); } @@ -179,7 +182,12 @@ private Map> injectBootstrapClassLoader( private Map> injectClassLoader( final ClassLoader classLoader, final Map classnameToBytes) { - return new ClassInjector.UsingReflection(classLoader).injectRaw(classnameToBytes); + INJECTING_HELPERS.begin(); + try { + return new ClassInjector.UsingReflection(classLoader).injectRaw(classnameToBytes); + } finally { + INJECTING_HELPERS.end(); + } } private void ensureModuleCanReadHelperModules(final JavaModule target) { diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java index 80dfca2ef1a..8c7e1c30ca6 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDCachingPoolStrategy.java @@ -1,5 +1,6 @@ package datadog.trace.agent.tooling.bytebuddy; +import static datadog.trace.bootstrap.AgentClassLoading.LOCATING_CLASS; import static net.bytebuddy.agent.builder.AgentBuilder.PoolStrategy; import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; @@ -295,6 +296,7 @@ public TypeDescription resolve() { if (!isResolved) { Class klass = null; ClassLoader classLoader = null; + LOCATING_CLASS.begin(); try { // Please note that by doing a loadClass, the type we are resolving will bypass // transformation since we are in the middle of a transformation. This should @@ -310,6 +312,8 @@ public TypeDescription resolve() { klass = Class.forName(className, false, null); } } catch (Throwable ignored) { + } finally { + LOCATING_CLASS.end(); } if (klass != null) { // We managed to load the class diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDClassFileLocator.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDClassFileLocator.java new file mode 100644 index 00000000000..a67ffdfa8e7 --- /dev/null +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDClassFileLocator.java @@ -0,0 +1,62 @@ +package datadog.trace.agent.tooling.bytebuddy; + +import static datadog.trace.bootstrap.AgentClassLoading.LOCATING_CLASS; + +import datadog.trace.agent.tooling.Utils; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import net.bytebuddy.dynamic.ClassFileLocator; +import net.bytebuddy.utility.StreamDrainer; + +/** + * Locate resources with the loading classloader. Because of a quirk with the way classes appended + * to the bootstrap classpath work, we first check our bootstrap proxy. If the loading classloader + * cannot find the desired resource, check up the classloader hierarchy until a resource is found. + */ +public final class DDClassFileLocator extends WeakReference + implements ClassFileLocator { + + public DDClassFileLocator(final ClassLoader classLoader) { + super(classLoader); + } + + @Override + public Resolution locate(final String className) throws IOException { + String resourceName = className.replace('.', '/') + ".class"; + + // try bootstrap first + Resolution resolution = loadClassResource(Utils.getBootstrapProxy(), resourceName); + ClassLoader cl = get(); + + // now go up the classloader hierarchy + if (null == resolution && null != cl) { + LOCATING_CLASS.begin(); + try { + do { + resolution = loadClassResource(cl, resourceName); + cl = cl.getParent(); + } while (null == resolution && null != cl); + } finally { + LOCATING_CLASS.end(); + } + } + + return resolution != null ? resolution : new Resolution.Illegal(className); + } + + @Override + public void close() { + // nothing to close + } + + private static Resolution loadClassResource( + final ClassLoader classLoader, final String resourceName) throws IOException { + try (InputStream in = classLoader.getResourceAsStream(resourceName)) { + if (null != in) { + return new Resolution.Explicit(StreamDrainer.DEFAULT.drain(in)); + } + return null; + } + } +} diff --git a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java index a3ec740f9d7..ee1eb72251a 100644 --- a/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java +++ b/dd-java-agent/agent-tooling/src/main/java/datadog/trace/agent/tooling/bytebuddy/DDLocationStrategy.java @@ -1,30 +1,18 @@ 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; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.utility.JavaModule; -/** - * Locate resources with the loading classloader. Because of a quirk with the way classes appended - * to the bootstrap classpath work, we first check our bootstrap proxy. If the loading classloader - * cannot find the desired resource, check up the classloader hierarchy until a resource is found. - */ -public class DDLocationStrategy implements AgentBuilder.LocationStrategy { +/** Strategy that uses {@link DDClassFileLocator} to locate class files. */ +public final class DDLocationStrategy implements AgentBuilder.LocationStrategy { public ClassFileLocator classFileLocator(final ClassLoader classLoader) { return classFileLocator(classLoader, null); } @Override - public ClassFileLocator classFileLocator(ClassLoader classLoader, final JavaModule javaModule) { - final List locators = new ArrayList<>(); - locators.add(ClassFileLocator.ForClassLoader.of(Utils.getBootstrapProxy())); - while (classLoader != null) { - locators.add(ClassFileLocator.ForClassLoader.WeaklyReferenced.of(classLoader)); - classLoader = classLoader.getParent(); - } - return new ClassFileLocator.Compound(locators.toArray(new ClassFileLocator[0])); + public ClassFileLocator classFileLocator( + final ClassLoader classLoader, final JavaModule javaModule) { + return new DDClassFileLocator(classLoader); } } diff --git a/dd-java-agent/instrumentation/osgi-4.3/osgi-4.3.gradle b/dd-java-agent/instrumentation/osgi-4.3/osgi-4.3.gradle new file mode 100644 index 00000000000..bdd779e33e9 --- /dev/null +++ b/dd-java-agent/instrumentation/osgi-4.3/osgi-4.3.gradle @@ -0,0 +1,21 @@ +muzzle { + // old coordinates + pass { + group = 'org.osgi' + module = 'org.osgi.core' + versions = '[4.3,]' + } + + // new coordinates + pass { + group = 'org.osgi' + module = 'osgi.core' + versions = '[4.3.1,]' + } +} + +apply from: "$rootDir/gradle/java.gradle" + +dependencies { + compileOnly group: 'org.osgi', name: 'org.osgi.core', version: '4.3.0' +} diff --git a/dd-java-agent/instrumentation/osgi-4.3/src/main/java/datadog/trace/instrumentation/osgi43/BundleReferenceInstrumentation.java b/dd-java-agent/instrumentation/osgi-4.3/src/main/java/datadog/trace/instrumentation/osgi43/BundleReferenceInstrumentation.java new file mode 100644 index 00000000000..83e835be544 --- /dev/null +++ b/dd-java-agent/instrumentation/osgi-4.3/src/main/java/datadog/trace/instrumentation/osgi43/BundleReferenceInstrumentation.java @@ -0,0 +1,190 @@ +package datadog.trace.instrumentation.osgi43; + +import static datadog.trace.agent.tooling.ClassLoaderMatcher.hasClassesNamed; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.extendsClass; +import static datadog.trace.agent.tooling.bytebuddy.matcher.DDElementMatchers.implementsInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static datadog.trace.bootstrap.AgentClassLoading.PROBING_CLASSLOADER; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +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.Instrumenter; +import datadog.trace.bootstrap.AgentClassLoading; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +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 org.osgi.framework.BundleReference; + +@AutoService(Instrumenter.class) +public final class BundleReferenceInstrumentation extends Instrumenter.Tracing { + public BundleReferenceInstrumentation() { + super("classloading", "osgi"); + } + + @Override + public ElementMatcher classLoaderMatcher() { + return hasClassesNamed("org.osgi.framework.wiring.BundleWiring"); + } + + @Override + public ElementMatcher typeMatcher() { + return extendsClass(named("java.lang.ClassLoader")) + .and(implementsInterface(named("org.osgi.framework.BundleReference"))); + } + + @Override + public String[] helperClassNames() { + return new String[] { + packageName + ".BundleWiringHelper", + packageName + ".BundleWiringHelper$1", + packageName + ".BundleWiringHelper$2" + }; + } + + @Override + public Map, String> transformers() { + final Map, String> transformers = new HashMap<>(); + transformers.put( + isMethod() + .and(named("getResource")) + .and(takesArguments(1).and(takesArgument(0, String.class))), + BundleReferenceInstrumentation.class.getName() + "$WidenGetResourceAdvice"); + transformers.put( + isMethod() + .and(named("getResourceAsStream")) + .and(takesArguments(1).and(takesArgument(0, String.class))), + BundleReferenceInstrumentation.class.getName() + "$WidenGetResourceAsStreamAdvice"); + transformers.put( + isMethod() + .and(named("loadClass")) + .and( + takesArguments(1) + .and(takesArgument(0, String.class)) + .or( + takesArguments(2) + .and(takesArgument(0, String.class)) + .and(takesArgument(1, boolean.class)))), + BundleReferenceInstrumentation.class.getName() + "$WidenLoadClassAdvice"); + return transformers; + } + + /** + * Bypass local visibility rules by repeating failed requests from bundles wired as dependencies. + * Also supports light probing of class-loaders without triggering further resolution of bundles. + * + *

We only do this for agent requests that require this additional visibility. + */ + public static class WidenGetResourceAdvice { + @Advice.OnMethodEnter(skipOn = Advice.OnNonDefaultValue.class, suppress = Throwable.class) + public static Object onEnter( + @Advice.This final BundleReference thiz, @Advice.Argument(0) final String name) { + AgentClassLoading requestType = AgentClassLoading.type(); + // avoid probing "java/..." class resources, use standard lookup for them + if (PROBING_CLASSLOADER == requestType && !name.startsWith("java/")) { + return BundleWiringHelper.probeResource(thiz.getBundle(), name); + } + return null; + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.This final BundleReference thiz, + @Advice.Argument(0) final String name, + @Advice.Return(readOnly = false) URL result, + @Advice.Thrown(readOnly = false) Throwable error, + @Advice.Enter final Object resultFromProbe) { + if (null != resultFromProbe) { + if (resultFromProbe instanceof URL) { + result = (URL) resultFromProbe; + } else { + // probe returned SKIP_REQUEST + } + } else if (null == result) { + AgentClassLoading requestType = AgentClassLoading.type(); + if (null != requestType) { + requestType.end(); // avoid looping back into our advice + try { + // widen search by peeking inside bundle wiring + result = BundleWiringHelper.getResource(thiz.getBundle(), name); + if (null != result) { + error = null; // clear any error from original call + } + } finally { + requestType.begin(); + } + } + } + } + } + + /** + * Bypass local visibility rules by repeating failed requests from bundles wired as dependencies. + * + *

We only do this for agent requests that require this additional visibility. + */ + public static class WidenGetResourceAsStreamAdvice { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.This final BundleReference thiz, + @Advice.Argument(0) final String name, + @Advice.Return(readOnly = false) InputStream result, + @Advice.Thrown(readOnly = false) Throwable error) { + if (null == result) { + AgentClassLoading requestType = AgentClassLoading.type(); + if (null != requestType) { + requestType.end(); // avoid looping back into our advice + try { + // widen search by peeking inside bundle wiring + URL resource = BundleWiringHelper.getResource(thiz.getBundle(), name); + if (null != resource) { + result = resource.openStream(); + error = null; // clear any error from original call + } + } catch (IOException e) { + // ignore missing resource + } finally { + requestType.begin(); + } + } + } + } + } + + /** + * Bypass local visibility rules by repeating failed requests from bundles wired as dependencies. + * + *

We only do this for agent requests that require this additional visibility. + */ + public static class WidenLoadClassAdvice { + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.This final BundleReference thiz, + @Advice.Argument(0) final String name, + @Advice.Return(readOnly = false) Class result, + @Advice.Thrown(readOnly = false) Throwable error) { + if (null == result) { + AgentClassLoading requestType = AgentClassLoading.type(); + if (null != requestType) { + requestType.end(); // avoid looping back into our advice + try { + // widen search by peeking inside bundle wiring + result = BundleWiringHelper.loadClass(thiz.getBundle(), name); + if (null != result) { + error = null; // clear any error from original call + } + } finally { + requestType.begin(); + } + } + } + } + } +} diff --git a/dd-java-agent/instrumentation/osgi-4.3/src/main/java/datadog/trace/instrumentation/osgi43/BundleWiringHelper.java b/dd-java-agent/instrumentation/osgi-4.3/src/main/java/datadog/trace/instrumentation/osgi43/BundleWiringHelper.java new file mode 100644 index 00000000000..cd5304c6ce9 --- /dev/null +++ b/dd-java-agent/instrumentation/osgi-4.3/src/main/java/datadog/trace/instrumentation/osgi43/BundleWiringHelper.java @@ -0,0 +1,141 @@ +package datadog.trace.instrumentation.osgi43; + +import static org.osgi.framework.wiring.BundleRevision.PACKAGE_NAMESPACE; + +import datadog.trace.api.Config; +import datadog.trace.api.Function; +import java.net.URL; +import java.util.ArrayDeque; +import java.util.HashSet; +import java.util.List; +import java.util.Queue; +import java.util.Set; +import org.osgi.framework.Bundle; +import org.osgi.framework.wiring.BundleRevision; +import org.osgi.framework.wiring.BundleWire; +import org.osgi.framework.wiring.BundleWiring; + +/** + * {@link BundleWiring} helper that searches a bundle's required wires to see if they have access to + * resources and classes that are not visible from the initial bundle. This relaxation of modularity + * rules is sometimes necessary when injecting advice, because it may refer to related packages that + * would have been imported if the original code had needed them. + */ +public final class BundleWiringHelper { + + // how far to take the breadth-first search of required wires (Import-Package, etc.) + private static final int MAX_DEPTH = Config.get().getOsgiSearchDepth(); + + // placeholder when we want byte-buddy to skip the original call and return null + private static final Object SKIP_REQUEST = new Object(); + + /** Probes for the named resource without using any class-loader related methods. */ + public static Object probeResource(final Bundle origin, final String resourceName) { + URL resource = origin.getEntry(resourceName); + if (null != resource) { + return resource; + } + // not in the bundle, lets check for a direct import of the containing package + BundleWiring wiring = (BundleWiring) origin.adapt(BundleWiring.class); + List importWires = wiring.getRequiredWires(PACKAGE_NAMESPACE); + if (null != importWires) { + int lastSlash = resourceName.lastIndexOf('/'); + if (lastSlash > 0) { + String pkg = resourceName.substring(0, lastSlash).replace('/', '.'); + for (BundleWire wire : importWires) { + if (pkg.equals(wire.getCapability().getAttributes().get(PACKAGE_NAMESPACE))) { + // class resource comes from a transitive import - to avoid cost of finding it, and + // because classloader matching/probing just checks existence, we return a resource + // we know exists to stand-in for the real resource + return origin.getEntry("META-INF/MANIFEST.MF"); + } + } + } + } + return SKIP_REQUEST; + } + + /** Delegates the resource request to any bundles wired as dependencies. */ + public static URL getResource(final Bundle origin, final String resourceName) { + return searchTransitiveWires( + origin, + new Function() { + @Override + public URL apply(final BundleWiring wiring) { + return wiring.getBundle().getResource(resourceName); + } + }); + } + + /** Delegates the class-load request to any bundles wired as dependencies. */ + public static Class loadClass(final Bundle origin, final String className) { + return searchTransitiveWires( + origin, + new Function>() { + @Override + public Class apply(final BundleWiring wiring) { + try { + return wiring.getBundle().loadClass(className); + } catch (ClassNotFoundException e) { + return null; + } + } + }); + } + + /** Searches any bundles wired as transitive dependencies using the filter to find a match. */ + private static T searchTransitiveWires( + final Bundle origin, final Function filter) { + BundleWiring wiring = (BundleWiring) origin.adapt(BundleWiring.class); + + Queue search = new ArrayDeque<>(); + Set visited = new HashSet<>(); + + search.add(wiring); + visited.add(wiring.getRevision()); // avoid dependency cycles + + int countToNextDepth = search.size(); + int depth = 1; + + // breadth-first search, keep track of how many bundles to search before the next level + while (depth <= MAX_DEPTH && !search.isEmpty()) { + T result = searchDirectWires(search, filter, depth < MAX_DEPTH, visited); + if (null != result) { + return result; + } + + if (--countToNextDepth == 0) { + if (depth < MAX_DEPTH) { + countToNextDepth = search.size(); + } + depth++; + } + } + + return null; + } + + /** Searches a bundle's direct dependencies (Import-Package, Require-Bundle etc.) */ + private static T searchDirectWires( + final Queue search, + final Function filter, + final boolean expandSearch, + final Set visited) { + + List wires = search.remove().getRequiredWires(null); + if (null != wires) { + for (BundleWire wire : wires) { + BundleWiring wiring = wire.getProviderWiring(); + if (null != wiring && visited.add(wiring.getRevision())) { + T result = filter.apply(wiring); + if (null != result) { + return result; + } else if (expandSearch) { + search.add(wiring); // will be processed at the next level of search + } + } + } + } + return null; + } +} diff --git a/dd-smoke-tests/osgi/src/test/groovy/datadog/smoketest/AbstractOSGiSmokeTest.groovy b/dd-smoke-tests/osgi/src/test/groovy/datadog/smoketest/AbstractOSGiSmokeTest.groovy index a900b75b3ee..a2abcabb990 100644 --- a/dd-smoke-tests/osgi/src/test/groovy/datadog/smoketest/AbstractOSGiSmokeTest.groovy +++ b/dd-smoke-tests/osgi/src/test/groovy/datadog/smoketest/AbstractOSGiSmokeTest.groovy @@ -18,6 +18,7 @@ abstract class AbstractOSGiSmokeTest extends AbstractSmokeTest { List command = new ArrayList<>() command.add(javaPath()) command.addAll(defaultJavaProperties) + command.add("-Ddd.profiling.enabled=false") command.add((String) "-Dorg.osgi.framework.storage=${storageDir}") command.add("-Dorg.osgi.framework.bootdelegation=") command.add("-Dorg.osgi.framework.bundle.parent=framework") @@ -39,10 +40,23 @@ abstract class AbstractOSGiSmokeTest extends AbstractSmokeTest { def "example application runs without errors"() { when: testedProcess.waitFor() - checkLog() + boolean instrumentedMessageClient = false + checkLog { + // check for additional OSGi class-loader issues + if (it.contains("Cannot resolve type description") || + it.contains("Instrumentation muzzled")) { + println it + logHasErrors = true + } + if (it.contains("Transformed datadog.smoketest.osgi.client.MessageClient")) { + println it + instrumentedMessageClient = true + } + } then: testedProcess.exitValue() == 0 + instrumentedMessageClient !logHasErrors } } diff --git a/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java b/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java index cc3dc57ebb8..7a107a49198 100644 --- a/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java +++ b/dd-trace-api/src/main/java/datadog/trace/api/config/TraceInstrumentationConfig.java @@ -44,6 +44,9 @@ public final class TraceInstrumentationConfig { "kafka.client.base64.decoding.enabled"; public static final String HYSTRIX_TAGS_ENABLED = "hystrix.tags.enabled"; + + public static final String OSGI_SEARCH_DEPTH = "osgi.search.depth"; + public static final String SERVLET_PRINCIPAL_ENABLED = "trace.servlet.principal.enabled"; public static final String SERVLET_ASYNC_TIMEOUT_ERROR = "trace.servlet.async-timeout.error"; diff --git a/internal-api/src/main/java/datadog/trace/api/Config.java b/internal-api/src/main/java/datadog/trace/api/Config.java index d54d220deab..bec12ee723c 100644 --- a/internal-api/src/main/java/datadog/trace/api/Config.java +++ b/internal-api/src/main/java/datadog/trace/api/Config.java @@ -70,6 +70,7 @@ import static datadog.trace.api.config.TraceInstrumentationConfig.JDBC_PREPARED_STATEMENT_CLASS_NAME; import static datadog.trace.api.config.TraceInstrumentationConfig.LEGACY_CONTEXT_FIELD_INJECTION; import static datadog.trace.api.config.TraceInstrumentationConfig.LOGS_MDC_TAGS_INJECTION_ENABLED; +import static datadog.trace.api.config.TraceInstrumentationConfig.OSGI_SEARCH_DEPTH; import static datadog.trace.api.config.TraceInstrumentationConfig.SERIALVERSIONUID_FIELD_INJECTION; import static datadog.trace.api.config.TracerConfig.ENABLE_TRACE_AGENT_V05; @@ -400,6 +401,9 @@ private String profilingProxyPasswordMasker() { @Getter private final boolean kafkaClientBase64DecodingEnabled; @Getter private final boolean hystrixTagsEnabled; + + @Getter private final int osgiSearchDepth; + @Getter private final boolean servletPrincipalEnabled; @Getter private final boolean servletAsyncTimeoutError; @@ -761,6 +765,8 @@ private Config(final String runtimeId, final ConfigProvider configProvider) { hystrixTagsEnabled = configProvider.getBoolean(HYSTRIX_TAGS_ENABLED, false); + osgiSearchDepth = configProvider.getInteger(OSGI_SEARCH_DEPTH, 1); + servletPrincipalEnabled = configProvider.getBoolean(TraceInstrumentationConfig.SERVLET_PRINCIPAL_ENABLED, false); diff --git a/settings.gradle b/settings.gradle index 39c3fcf70b6..56c219336ef 100644 --- a/settings.gradle +++ b/settings.gradle @@ -165,6 +165,7 @@ include ':dd-java-agent:instrumentation:opentelemetry' include ':dd-java-agent:instrumentation:opentracing' include ':dd-java-agent:instrumentation:opentracing:api-0.31' include ':dd-java-agent:instrumentation:opentracing:api-0.32' +include ':dd-java-agent:instrumentation:osgi-4.3' include ':dd-java-agent:instrumentation:play-2.3' include ':dd-java-agent:instrumentation:play-2.4' include ':dd-java-agent:instrumentation:play-2.6'