Set bootstrap delegation for osgi classloading
ADD
dd-java-agent/instrumentation/osgi-classloading/osgi-classloading.gradle
+apply from: "${rootDir}/gradle/java.gradle"
+
+dependencies {
+ compile project(':dd-java-agent:agent-tooling')
+ compile deps.bytebuddy
+ compile deps.autoservice
+
+ testCompile group: 'org.osgi', name: 'org.osgi.core', version: '4.0.0'
+ testCompile project(':dd-java-agent:testing')
+}

ADD
dd-java-agent/instrumentation/osgi-classloading/src/main/java/datadog/trace/instrumentation/osgi/OSGIClassloadingInstrumentation.java
+package datadog.trace.instrumentation.osgi;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+import com.google.auto.service.AutoService;
+import datadog.trace.agent.tooling.Instrumenter;
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.dynamic.DynamicType;
+import net.bytebuddy.utility.JavaModule;
+
+@AutoService(Instrumenter.class)
+public final class OSGIClassloadingInstrumentation extends Instrumenter.Configurable {
+ private static final String[] BOOTSTRAP_PACKAGE_PREFIXES = {
+ "io.opentracing", "datadog.slf4j", "datadog.trace"
+ };
+
+ public OSGIClassloadingInstrumentation() {
+ super("osgi-classloading");
+ }
+
+ @Override
+ public AgentBuilder apply(final AgentBuilder agentBuilder) {
+ return agentBuilder
+ // OSGI Bundle class loads the sys prop which defines bootstrap classes
+ .type(named("org.osgi.framework.Bundle"))
+ .transform(
+ new AgentBuilder.Transformer() {
+ @Override
+ public DynamicType.Builder<?> transform(
+ DynamicType.Builder<?> builder,
+ TypeDescription typeDescription,
+ ClassLoader classLoader,
+ JavaModule javaModule) {
+ // This instrumentation modifies no bytes.
+ // Instead it sets a system prop to tell osgi to delegate
+ // classloads for datadog bootstrap classes
+ StringBuilder ddPrefixes = new StringBuilder("");
+ for (int i = 0; i < BOOTSTRAP_PACKAGE_PREFIXES.length; ++i) {
+ if (i > 0) {
+ // must append twice. Once for exact package and wildcard for child packages
+ ddPrefixes.append(",");
+ }
+ ddPrefixes.append(BOOTSTRAP_PACKAGE_PREFIXES[i]).append(".*,");
+ ddPrefixes.append(BOOTSTRAP_PACKAGE_PREFIXES[i]);
+ }
+ final String existing = System.getProperty("org.osgi.framework.bootdelegation");
+ if (null == existing) {
+ System.setProperty("org.osgi.framework.bootdelegation", ddPrefixes.toString());
+ } else if (!existing.contains(ddPrefixes)) {
+ System.setProperty(
+ "org.osgi.framework.bootdelegation", existing + "," + ddPrefixes.toString());
+ }
+ return builder;
+ }
+ })
+ .asDecorator();
+ }
+}

ADD
dd-java-agent/instrumentation/osgi-classloading/src/test/groovy/OSGIClassloadingTest.groovy
+import datadog.trace.agent.test.AgentTestRunner
+
+class OSGIClassloadingTest extends AgentTestRunner {
+ def "delegation property set on module load"() {
+ setup:
+ org.osgi.framework.Bundle.getName()
+
+ expect:
+ System.getProperty("org.osgi.framework.bootdelegation") == "io.opentracing.*,io.opentracing,datadog.slf4j.*,datadog.slf4j,datadog.trace.*,datadog.trace"
+ }
+}

MODIFY
settings.gradle
settings.gradle
@@ -23,6 +23,7 @@ include ':dd-java-agent:instrumentation:kafka-streams-0.11'
include ':dd-java-agent:instrumentation:mongo-3.1'
include ':dd-java-agent:instrumentation:mongo-async-3.3'
include ':dd-java-agent:instrumentation:okhttp-3'
+include ':dd-java-agent:instrumentation:osgi-classloading'
include ':dd-java-agent:instrumentation:servlet-2'
include ':dd-java-agent:instrumentation:servlet-3'
include ':dd-java-agent:instrumentation:spring-web'

Set bootstrap delegation for osgi classloading