diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java index c896983af22..627aa05606e 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/BootstrapInitializationTelemetry.java @@ -1,11 +1,10 @@ package datadog.trace.bootstrap; import datadog.json.JsonWriter; -import java.io.IOException; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; /** Thread safe telemetry class used to relay information about tracer activation. */ public abstract class BootstrapInitializationTelemetry { @@ -179,7 +178,7 @@ public void finish() { } public interface JsonSender { - void send(byte[] payload) throws IOException; + void send(byte[] payload); } public static final class ForwarderJsonSender implements JsonSender { @@ -190,19 +189,36 @@ public static final class ForwarderJsonSender implements JsonSender { } @Override - public void send(byte[] payload) throws IOException { - ProcessBuilder builder = new ProcessBuilder(forwarderPath, "library_entrypoint"); + public void send(byte[] payload) { + ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, payload); + t.setDaemon(true); + t.start(); + } + } - Process process = builder.start(); - try (OutputStream out = process.getOutputStream()) { - out.write(payload); - } + public static final class ForwarderJsonSenderThread extends Thread { + private final String forwarderPath; + private final byte[] payload; + + public ForwarderJsonSenderThread(String forwarderPath, byte[] payload) { + super("dd-forwarder-json-sender"); + this.forwarderPath = forwarderPath; + this.payload = payload; + } + + @SuppressForbidden + @Override + public void run() { + ProcessBuilder builder = new ProcessBuilder(forwarderPath, "library_entrypoint"); try { - process.waitFor(1, TimeUnit.SECONDS); - } catch (InterruptedException e) { - // just for hygiene, reset the interrupt status - Thread.currentThread().interrupt(); + Process process = builder.start(); + try (OutputStream out = process.getOutputStream()) { + out.write(payload); + } + } catch (Throwable e) { + // We don't have a log manager here, so just print. + System.err.println("Failed to send telemetry: " + e.getMessage()); } } } diff --git a/dd-java-agent/src/test/groovy/datadog/trace/agent/InitializationTelemetryTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/agent/InitializationTelemetryTest.groovy index d70b7d6e534..af05b91571b 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/agent/InitializationTelemetryTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/agent/InitializationTelemetryTest.groovy @@ -21,7 +21,7 @@ class InitializationTelemetryTest extends Specification { def "normal start-up"() { when: - def result = InitializationTelemetryCheck.runTestJvm(null) + def result = InitializationTelemetryCheck.runTestJvm(null, false, "sleep") then: result.exitCode == 0 @@ -33,7 +33,7 @@ class InitializationTelemetryTest extends Specification { // agent initialization to fail. However, we should catch the exception allowing the application // to run normally. when: - def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockByteBuddy) + def result = InitializationTelemetryCheck.runTestJvm(InitializationTelemetryCheck.BlockByteBuddy, false, "sleep") then: result.exitCode == 0 diff --git a/dd-java-agent/src/test/java/jvmbootstraptest/InitializationTelemetryCheck.java b/dd-java-agent/src/test/java/jvmbootstraptest/InitializationTelemetryCheck.java index d7bf9db7d36..0db64149b3d 100644 --- a/dd-java-agent/src/test/java/jvmbootstraptest/InitializationTelemetryCheck.java +++ b/dd-java-agent/src/test/java/jvmbootstraptest/InitializationTelemetryCheck.java @@ -20,7 +20,13 @@ *
Checks edge cases where InitializationTelemetry is blocked by SecurityManagers
*/
public class InitializationTelemetryCheck {
- public static void main(String[] args) {}
+ public static void main(String[] args) throws InterruptedException {
+ // Emulates the real application performing work in main().
+ // That should give enough time to send initial telemetry from daemon thread.
+ if (args.length > 0 && "sleep".equals(args[0])) {
+ Thread.sleep(1000);
+ }
+ }
/** Blocks the loading of the agent bootstrap */
public static class BlockAgentLoading extends TestSecurityManager {
@@ -71,12 +77,20 @@ protected boolean checkFileExecutePermission(FilePermission perm, Object ctx, St
public static final Result runTestJvm(Class extends TestSecurityManager> securityManagerClass)
throws Exception {
- return runTestJvm(securityManagerClass, false);
+ return runTestJvm(securityManagerClass, false, null);
}
public static final Result runTestJvm(
Class extends TestSecurityManager> securityManagerClass, boolean printStreams)
throws Exception {
+ return runTestJvm(securityManagerClass, printStreams, null);
+ }
+
+ public static final Result runTestJvm(
+ Class extends TestSecurityManager> securityManagerClass,
+ boolean printStreams,
+ String mainArgs)
+ throws Exception {
File jarFile =
IntegrationTestUtils.createJarFileWithClasses(requiredClasses(securityManagerClass));
@@ -95,7 +109,7 @@ public static final Result runTestJvm(
IntegrationTestUtils.runOnSeparateJvm(
InitializationTelemetryCheck.class.getName(),
InitializationTelemetryCheck.jvmArgs(securityManagerClass),
- InitializationTelemetryCheck.mainArgs(),
+ InitializationTelemetryCheck.mainArgs(mainArgs),
InitializationTelemetryCheck.envVars(forwarderFile),
jarFile,
printStreams);
@@ -162,8 +176,12 @@ public static final String[] jvmArgs(Class extends TestSecurityManager> securi
}
}
- public static final String[] mainArgs() {
- return new String[] {};
+ public static final String[] mainArgs(String args) {
+ if (args == null) {
+ return new String[] {};
+ } else {
+ return args.split(",");
+ }
}
public static final Map