Do not trace openConnection for Datadog ClassLoader
MODIFY
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/DatadogClassLoader.java
package datadog.trace.bootstrap;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
-import java.net.URLConnection;
-import java.net.URLStreamHandler;
-import java.nio.file.NoSuchFileException;
-import java.security.Permission;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
import lombok.extern.slf4j.Slf4j;
/**
@@ -116,99 +104,4 @@ public class DatadogClassLoader extends URLClassLoader {
throw new ClassNotFoundException(name);
}
}
-
- protected static class InternalJarURLHandler extends URLStreamHandler {
- private final Map<String, byte[]> filenameToBytes = new HashMap<>();
-
- public InternalJarURLHandler(
- final String internalJarFileName, final ClassLoader classloaderForJarResource) {
-
- // "/" is used as the default url of the jar
- // This is called by the SecureClassLoader trying to obtain permissions
- filenameToBytes.put("/", new byte[] {});
-
- final InputStream jarStream =
- classloaderForJarResource.getResourceAsStream(internalJarFileName);
-
- if (jarStream != null) {
- try (final JarInputStream inputStream = new JarInputStream(jarStream)) {
- JarEntry entry = inputStream.getNextJarEntry();
-
- while (entry != null) {
- filenameToBytes.put("/" + entry.getName(), getBytes(inputStream));
-
- entry = inputStream.getNextJarEntry();
- }
-
- } catch (final IOException e) {
- log.error("Unable to read internal jar", e);
- }
- } else {
- log.error("Internal jar not found");
- }
- }
-
- @Override
- protected URLConnection openConnection(final URL url) throws IOException {
- final byte[] bytes = filenameToBytes.get(url.getFile());
-
- if (bytes == null) {
- throw new NoSuchFileException(url.getFile(), null, url.getFile() + " not in internal jar");
- }
-
- return new InternalJarURLConnection(url, bytes);
- }
- }
-
- protected static class InternalJarURLConnection extends URLConnection {
- private final byte[] bytes;
-
- private InternalJarURLConnection(final URL url, final byte[] bytes) {
- super(url);
- this.bytes = bytes;
- }
-
- @Override
- public void connect() throws IOException {
- connected = true;
- }
-
- @Override
- public InputStream getInputStream() throws IOException {
- return new ByteArrayInputStream(bytes);
- }
-
- @Override
- public Permission getPermission() {
- // No permissions needed because all classes are in memory
- return null;
- }
- }
-
- /**
- * Standard "copy InputStream to byte[]" implementation using a ByteArrayOutputStream
- *
- * <p>IOUtils.toByteArray() or Java 9's InputStream.readAllBytes() could be replacements if they
- * were available
- *
- * <p>This can be optimized using the JarEntry's size(), but its not always available
- *
- * @param inputStream
- * @return a byte[] from the inputstream
- * @throws IOException
- */
- private static byte[] getBytes(final InputStream inputStream) throws IOException {
- final byte[] buffer = new byte[4096];
-
- int bytesRead = inputStream.read(buffer, 0, buffer.length);
- try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
- while (bytesRead != -1) {
- outputStream.write(buffer, 0, bytesRead);
-
- bytesRead = inputStream.read(buffer, 0, buffer.length);
- }
-
- return outputStream.toByteArray();
- }
- }
}

ADD
dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/InternalJarURLHandler.java
+package datadog.trace.bootstrap;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.nio.file.NoSuchFileException;
+import java.security.Permission;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class InternalJarURLHandler extends URLStreamHandler {
+ private final Map<String, byte[]> filenameToBytes = new HashMap<>();
+
+ InternalJarURLHandler(
+ final String internalJarFileName, final ClassLoader classloaderForJarResource) {
+
+ // "/" is used as the default url of the jar
+ // This is called by the SecureClassLoader trying to obtain permissions
+ filenameToBytes.put("/", new byte[] {});
+
+ final InputStream jarStream =
+ classloaderForJarResource.getResourceAsStream(internalJarFileName);
+
+ if (jarStream != null) {
+ try (final JarInputStream inputStream = new JarInputStream(jarStream)) {
+ JarEntry entry = inputStream.getNextJarEntry();
+
+ while (entry != null) {
+ filenameToBytes.put("/" + entry.getName(), getBytes(inputStream));
+
+ entry = inputStream.getNextJarEntry();
+ }
+
+ } catch (final IOException e) {
+ log.error("Unable to read internal jar", e);
+ }
+ } else {
+ log.error("Internal jar not found");
+ }
+ }
+
+ @Override
+ protected URLConnection openConnection(final URL url) throws IOException {
+ final byte[] bytes = filenameToBytes.get(url.getFile());
+
+ if (bytes == null) {
+ throw new NoSuchFileException(url.getFile(), null, url.getFile() + " not in internal jar");
+ }
+
+ return new InternalJarURLConnection(url, bytes);
+ }
+
+ /**
+ * Standard "copy InputStream to byte[]" implementation using a ByteArrayOutputStream
+ *
+ * <p>IOUtils.toByteArray() or Java 9's InputStream.readAllBytes() could be replacements if they
+ * were available
+ *
+ * <p>This can be optimized using the JarEntry's size(), but its not always available
+ *
+ * @param inputStream stream to read
+ * @return a byte[] from the inputstream
+ */
+ private static byte[] getBytes(final InputStream inputStream) throws IOException {
+ final byte[] buffer = new byte[4096];
+
+ int bytesRead = inputStream.read(buffer, 0, buffer.length);
+ try (final ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
+ while (bytesRead != -1) {
+ outputStream.write(buffer, 0, bytesRead);
+
+ bytesRead = inputStream.read(buffer, 0, buffer.length);
+ }
+
+ return outputStream.toByteArray();
+ }
+ }
+
+ private static class InternalJarURLConnection extends URLConnection {
+ private final byte[] bytes;
+
+ private InternalJarURLConnection(final URL url, final byte[] bytes) {
+ super(url);
+ this.bytes = bytes;
+ }
+
+ @Override
+ public void connect() throws IOException {
+ connected = true;
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ @Override
+ public Permission getPermission() {
+ // No permissions needed because all classes are in memory
+ return null;
+ }
+ }
+}

MODIFY
dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java
dd-java-agent/instrumentation/http-url-connection/src/main/java/datadog/trace/instrumentation/http_url_connection/UrlInstrumentation.java
@@ -12,11 +12,13 @@ import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.Config;
import datadog.trace.api.DDSpanTypes;
import datadog.trace.api.DDTags;
+import datadog.trace.bootstrap.InternalJarURLHandler;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.net.URL;
+import java.net.URLStreamHandler;
import java.util.Collections;
import java.util.Map;
import net.bytebuddy.asm.Advice;
@@ -49,10 +51,14 @@ public class UrlInstrumentation extends Instrumenter.Default {
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void errorSpan(
- @Advice.This final URL url, @Advice.Thrown final Throwable throwable) {
+ @Advice.This final URL url,
+ @Advice.Thrown final Throwable throwable,
+ @Advice.FieldValue("handler") final URLStreamHandler handler) {
if (throwable != null) {
- final boolean isTraceRequest = Thread.currentThread().getName().equals("dd-agent-writer");
- if (isTraceRequest) {
+ // Various agent components end up calling `openConnection` indirectly
+ // when loading classes. Avoid tracing these calls.
+ final boolean disableTracing = handler instanceof InternalJarURLHandler;
+ if (disableTracing) {
return;
}

Do not trace openConnection for Datadog ClassLoader