From 5e9b6bae9e183a0682cb3021e16a490c44f74708 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Tue, 20 May 2025 15:28:18 -0400 Subject: [PATCH 01/14] Added special lightweight pre-main class to enable SSI inject for Java 6. --- dd-java-agent/build.gradle | 28 +++- .../trace/bootstrap/AgentBootstrapJava6.java | 153 ++++++++++++++++++ 2 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 1b2c3804acb..9b6f192a218 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -17,8 +17,30 @@ configurations { traceShadowInclude } -sourceCompatibility = JavaVersion.VERSION_1_7 -targetCompatibility = JavaVersion.VERSION_1_7 +// Support SSI inject for Java 7. +tasks.named("compileJava", JavaCompile).configure { + sourceCompatibility = JavaVersion.VERSION_1_7 + targetCompatibility = JavaVersion.VERSION_1_7 +} + +// Support SSI inject for Java 6. +sourceSets { + java6 { + java { + srcDirs = ['src/main/java6'] + } + } +} + +tasks.register('compileJava6', JavaCompile) { + classpath = sourceSets.main.compileClasspath + source = sourceSets.java6.java + destinationDirectory = layout.buildDirectory.dir("classes/java/main") + sourceCompatibility = JavaVersion.VERSION_1_6 + targetCompatibility = JavaVersion.VERSION_1_6 +} + +tasks.compileJava.dependsOn compileJava6 /* * Several shadow jars are created @@ -176,7 +198,7 @@ shadowJar generalShadowJarConfig >> { attributes( "Main-Class": "datadog.trace.bootstrap.AgentBootstrap", "Agent-Class": "datadog.trace.bootstrap.AgentBootstrap", - "Premain-Class": "datadog.trace.bootstrap.AgentBootstrap", + "Premain-Class": "datadog.trace.bootstrap.AgentBootstrapJava6", "Can-Redefine-Classes": true, "Can-Retransform-Classes": true, ) diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java new file mode 100644 index 00000000000..ef143cd118f --- /dev/null +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java @@ -0,0 +1,153 @@ +package datadog.trace.bootstrap; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Method; + +/** Special lightweight pre-main class to enable SSI inject for Java 6. */ +public class AgentBootstrapJava6 { + public static void premain(final String agentArgs, final Instrumentation inst) { + agentmain(agentArgs, inst); + } + + public static void agentmain(final String agentArgs, final Instrumentation inst) { + try { + String version = System.getProperty("java.version"); + // Found Java 6 + if (version.startsWith("1.6")) { + reportUnsupportedJava6(version); + } else { + continueBootstrap(agentArgs, inst); + } + } catch (Throwable e) { + error("Agent pre-main function failed", e); + } + } + + private static void error(String msg, Throwable e) { + log(msg + ": " + e.getMessage()); + } + + private static void log(String msg) { + // We don't have a log manager here, so just print. + System.out.println(msg); + } + + public static void reportUnsupportedJava6(String javaVersion) { + try { + String agentVersion = getAgentVersion(); + log( + "Warning: " + + agentVersion + + " of dd-java-agent is not compatible with Java " + + javaVersion + + " and will not be installed."); + log("Please upgrade your Java version to 8+"); + String forwarderPath = null; + try { + forwarderPath = System.getenv("DD_TELEMETRY_FORWARDER_PATH"); + } catch (SecurityException e) { + log("Failed to get DD_TELEMETRY_FORWARDER_PATH: " + e.getMessage()); + } + if (forwarderPath == null) { + log("Telemetry forwarder path is null."); + return; + } + String payload = + "{\"metadata\":{" + + "\"runtime_name\":\"jvm\"," + + "\"language_name\":\"jvm\"," + + "\"runtime_version\":\"" + + javaVersion + + "\"," + + "\"language_version\":\"" + + javaVersion + + "\"," + + "\"tracer_version\":\"" + + agentVersion + + "\"}," + + "\"points\":\"[{" + + "\"name\":\"library_entrypoint.abort\"," + + "\"tags\":[\"reason:incompatible_runtime\"]" + + "}]" + + "}"; + + ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, payload); + t.start(); + + try { + t.join(1000); + } catch (InterruptedException e) { + // just for hygiene, reset the interrupt status + Thread.currentThread().interrupt(); + } + } catch (Throwable e) { + error("Failed to report telemetry", e); + } + } + + public static String getAgentVersion() { + try { + // Get the resource as an InputStream + InputStream is = AgentBootstrapJava6.class.getResourceAsStream("/dd-java-agent.version"); + if (is == null) { + return "n/a"; + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + final StringBuilder sb = new StringBuilder(); + for (int c = reader.read(); c != -1; c = reader.read()) { + sb.append((char) c); + } + reader.close(); + + return sb.toString().trim(); + } catch (Throwable e) { + return "unknown"; + } + } + + private static void continueBootstrap(final String agentArgs, final Instrumentation inst) { + try { + Class clazz = Class.forName("datadog.trace.bootstrap.AgentBootstrap"); + Method agentMain = clazz.getMethod("agentmain", String.class, Instrumentation.class); + agentMain.invoke(null, agentArgs, inst); + } catch (Throwable e) { + System.err.println("Failed to install dd-java-agent: " + e.getMessage()); + } + } + + public static final class ForwarderJsonSenderThread extends Thread { + private final String forwarderPath; + private final String payload; + + public ForwarderJsonSenderThread(String forwarderPath, String payload) { + super("dd-forwarder-json-sender"); + setDaemon(true); + this.forwarderPath = forwarderPath; + this.payload = payload; + } + + @Override + public void run() { + ProcessBuilder builder = new ProcessBuilder(forwarderPath, "library_entrypoint"); + try { + Process process = builder.start(); + OutputStream out = null; + try { + out = process.getOutputStream(); + out.write(payload.getBytes()); + } finally { + if (out != null) { + out.close(); + } + } + } catch (Throwable e) { + error("Failed to send telemetry", e); + } + } + } +} From c40db792e59c074fb25c3970835daa207d03413c Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Tue, 20 May 2025 16:29:39 -0400 Subject: [PATCH 02/14] Fixed SuppressForbidden test. --- dd-java-agent/build.gradle | 6 +++++- .../java6/datadog/trace/bootstrap/AgentBootstrapJava6.java | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 9b6f192a218..d6dc3f93df9 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -40,6 +40,10 @@ tasks.register('compileJava6', JavaCompile) { targetCompatibility = JavaVersion.VERSION_1_6 } +dependencies { + java6CompileOnly 'de.thetaphi:forbiddenapis:3.4' +} + tasks.compileJava.dependsOn compileJava6 /* @@ -90,7 +94,7 @@ ext.generalShadowJarConfig = { if (!projectName.equals('instrumentation')) { relocate 'org.yaml.snakeyaml', 'datadog.snakeyaml' relocate 'okhttp3', 'datadog.okhttp3' - relocate 'okio', 'datadog.okio' + relocate 'okio', 'datadog.okio' } if (!project.hasProperty("disableShadowRelocate") || !disableShadowRelocate) { diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java index ef143cd118f..38c5cd45b83 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java @@ -1,5 +1,6 @@ package datadog.trace.bootstrap; +import de.thetaphi.forbiddenapis.SuppressForbidden; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -31,6 +32,7 @@ private static void error(String msg, Throwable e) { log(msg + ": " + e.getMessage()); } + @SuppressForbidden private static void log(String msg) { // We don't have a log manager here, so just print. System.out.println(msg); @@ -110,6 +112,7 @@ public static String getAgentVersion() { } } + @SuppressForbidden private static void continueBootstrap(final String agentArgs, final Instrumentation inst) { try { Class clazz = Class.forName("datadog.trace.bootstrap.AgentBootstrap"); From 125a148af9611978fa9a410ccb9f153211f7bfc3 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Thu, 22 May 2025 22:47:01 -0400 Subject: [PATCH 03/14] Refactored pre-check logic. --- dd-java-agent/build.gradle | 12 +- .../trace/bootstrap/AgentBootstrap.java | 66 +----- .../trace/bootstrap/AgentBootstrapJava6.java | 156 -------------- .../trace/bootstrap/AgentPreCheck.java | 191 ++++++++++++++++++ .../trace/bootstrap/AgentBootstrapTest.groovy | 91 --------- .../trace/bootstrap/AgentPreCheckTest.groovy | 140 +++++++++++++ 6 files changed, 336 insertions(+), 320 deletions(-) delete mode 100644 dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java create mode 100644 dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java create mode 100644 dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index d6dc3f93df9..f001c02fb5e 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -17,13 +17,8 @@ configurations { traceShadowInclude } -// Support SSI inject for Java 7. -tasks.named("compileJava", JavaCompile).configure { - sourceCompatibility = JavaVersion.VERSION_1_7 - targetCompatibility = JavaVersion.VERSION_1_7 -} - -// Support SSI inject for Java 6. +// The special pre-check should be compiled with Java 6 to detect unsupported Java versions and +// prevent issues for users that still using them. sourceSets { java6 { java { @@ -42,6 +37,7 @@ tasks.register('compileJava6', JavaCompile) { dependencies { java6CompileOnly 'de.thetaphi:forbiddenapis:3.4' + testImplementation sourceSets.java6.output } tasks.compileJava.dependsOn compileJava6 @@ -202,7 +198,7 @@ shadowJar generalShadowJarConfig >> { attributes( "Main-Class": "datadog.trace.bootstrap.AgentBootstrap", "Agent-Class": "datadog.trace.bootstrap.AgentBootstrap", - "Premain-Class": "datadog.trace.bootstrap.AgentBootstrapJava6", + "Premain-Class": "datadog.trace.bootstrap.AgentPreCheck", "Can-Redefine-Classes": true, "Can-Retransform-Classes": true, ) diff --git a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java index ed0db2fc50a..77bc9f8685e 100644 --- a/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java +++ b/dd-java-agent/src/main/java/datadog/trace/bootstrap/AgentBootstrap.java @@ -9,7 +9,6 @@ import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.io.PrintStream; import java.lang.instrument.Instrumentation; import java.lang.reflect.Method; import java.net.URI; @@ -126,10 +125,6 @@ private static void agentmainImpl( // since tracer is presumably initialized elsewhere, still considering this complete return; } - if (lessThanJava8()) { - initTelemetry.onAbort("incompatible_runtime"); - return; - } if (isJdkTool()) { initTelemetry.onAbort("jdk_tool"); return; @@ -170,7 +165,7 @@ static boolean getConfig(String configName) { } static boolean exceptionCauseChainContains(Throwable ex, String exClassName) { - Set stack = Collections.newSetFromMap(new IdentityHashMap()); + Set stack = Collections.newSetFromMap(new IdentityHashMap<>()); Throwable t = ex; while (t != null && stack.add(t) && stack.size() <= MAX_EXCEPTION_CHAIN_LENGTH) { // cannot do an instanceof check since most of the agent's code is loaded by an isolated CL @@ -193,36 +188,6 @@ private static boolean alreadyInitialized() { return false; } - @SuppressForbidden - private static boolean lessThanJava8() { - try { - return lessThanJava8(System.getProperty("java.version"), System.err); - } catch (SecurityException e) { - // Hypothetically, we could version sniff the supported version level - // For now, just skip the check and let the JVM handle things instead - return false; - } - } - - // Reachable for testing - static boolean lessThanJava8(String version, PrintStream output) { - if (parseJavaMajorVersion(version) < 8) { - String agentRawVersion = AgentJar.tryGetAgentVersion(); - String agentVersion = agentRawVersion == null ? "This version" : "Version " + agentRawVersion; - - output.println( - "Warning: " - + agentVersion - + " of dd-java-agent is not compatible with Java " - + version - + " and will not be installed."); - output.println( - "Please upgrade your Java version to 8+ or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0"); - return true; - } - return false; - } - private static boolean isJdkTool() { String moduleMain = SystemUtils.tryGetProperty("jdk.module.main"); if (null != moduleMain && !moduleMain.isEmpty() && moduleMain.charAt(0) == 'j') { @@ -263,32 +228,6 @@ private static boolean isJdkTool() { return false; } - // Reachable for testing - static int parseJavaMajorVersion(String version) { - int major = 0; - if (null == version || version.isEmpty()) { - return major; - } - int start = 0; - if (version.charAt(0) == '1' - && version.length() >= 3 - && version.charAt(1) == '.' - && Character.isDigit(version.charAt(2))) { - start = 2; - } - // Parse the major digit and be a bit lenient, allowing digits followed by any non digit - for (int i = start; i < version.length(); i++) { - char c = version.charAt(i); - if (Character.isDigit(c)) { - major *= 10; - major += Character.digit(c, 10); - } else { - break; - } - } - return major; - } - @SuppressForbidden static boolean shouldAbortDueToOtherJavaAgents() { // We don't abort if either @@ -333,9 +272,6 @@ static boolean shouldAbortDueToOtherJavaAgents() { } public static void main(final String[] args) { - if (lessThanJava8()) { - return; - } AgentJar.main(args); } diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java deleted file mode 100644 index 38c5cd45b83..00000000000 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentBootstrapJava6.java +++ /dev/null @@ -1,156 +0,0 @@ -package datadog.trace.bootstrap; - -import de.thetaphi.forbiddenapis.SuppressForbidden; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.lang.instrument.Instrumentation; -import java.lang.reflect.Method; - -/** Special lightweight pre-main class to enable SSI inject for Java 6. */ -public class AgentBootstrapJava6 { - public static void premain(final String agentArgs, final Instrumentation inst) { - agentmain(agentArgs, inst); - } - - public static void agentmain(final String agentArgs, final Instrumentation inst) { - try { - String version = System.getProperty("java.version"); - // Found Java 6 - if (version.startsWith("1.6")) { - reportUnsupportedJava6(version); - } else { - continueBootstrap(agentArgs, inst); - } - } catch (Throwable e) { - error("Agent pre-main function failed", e); - } - } - - private static void error(String msg, Throwable e) { - log(msg + ": " + e.getMessage()); - } - - @SuppressForbidden - private static void log(String msg) { - // We don't have a log manager here, so just print. - System.out.println(msg); - } - - public static void reportUnsupportedJava6(String javaVersion) { - try { - String agentVersion = getAgentVersion(); - log( - "Warning: " - + agentVersion - + " of dd-java-agent is not compatible with Java " - + javaVersion - + " and will not be installed."); - log("Please upgrade your Java version to 8+"); - String forwarderPath = null; - try { - forwarderPath = System.getenv("DD_TELEMETRY_FORWARDER_PATH"); - } catch (SecurityException e) { - log("Failed to get DD_TELEMETRY_FORWARDER_PATH: " + e.getMessage()); - } - if (forwarderPath == null) { - log("Telemetry forwarder path is null."); - return; - } - String payload = - "{\"metadata\":{" - + "\"runtime_name\":\"jvm\"," - + "\"language_name\":\"jvm\"," - + "\"runtime_version\":\"" - + javaVersion - + "\"," - + "\"language_version\":\"" - + javaVersion - + "\"," - + "\"tracer_version\":\"" - + agentVersion - + "\"}," - + "\"points\":\"[{" - + "\"name\":\"library_entrypoint.abort\"," - + "\"tags\":[\"reason:incompatible_runtime\"]" - + "}]" - + "}"; - - ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, payload); - t.start(); - - try { - t.join(1000); - } catch (InterruptedException e) { - // just for hygiene, reset the interrupt status - Thread.currentThread().interrupt(); - } - } catch (Throwable e) { - error("Failed to report telemetry", e); - } - } - - public static String getAgentVersion() { - try { - // Get the resource as an InputStream - InputStream is = AgentBootstrapJava6.class.getResourceAsStream("/dd-java-agent.version"); - if (is == null) { - return "n/a"; - } - - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - final StringBuilder sb = new StringBuilder(); - for (int c = reader.read(); c != -1; c = reader.read()) { - sb.append((char) c); - } - reader.close(); - - return sb.toString().trim(); - } catch (Throwable e) { - return "unknown"; - } - } - - @SuppressForbidden - private static void continueBootstrap(final String agentArgs, final Instrumentation inst) { - try { - Class clazz = Class.forName("datadog.trace.bootstrap.AgentBootstrap"); - Method agentMain = clazz.getMethod("agentmain", String.class, Instrumentation.class); - agentMain.invoke(null, agentArgs, inst); - } catch (Throwable e) { - System.err.println("Failed to install dd-java-agent: " + e.getMessage()); - } - } - - public static final class ForwarderJsonSenderThread extends Thread { - private final String forwarderPath; - private final String payload; - - public ForwarderJsonSenderThread(String forwarderPath, String payload) { - super("dd-forwarder-json-sender"); - setDaemon(true); - this.forwarderPath = forwarderPath; - this.payload = payload; - } - - @Override - public void run() { - ProcessBuilder builder = new ProcessBuilder(forwarderPath, "library_entrypoint"); - try { - Process process = builder.start(); - OutputStream out = null; - try { - out = process.getOutputStream(); - out.write(payload.getBytes()); - } finally { - if (out != null) { - out.close(); - } - } - } catch (Throwable e) { - error("Failed to send telemetry", e); - } - } - } -} diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java new file mode 100644 index 00000000000..64fd8644af7 --- /dev/null +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -0,0 +1,191 @@ +package datadog.trace.bootstrap; + +import de.thetaphi.forbiddenapis.SuppressForbidden; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.PrintStream; +import java.lang.instrument.Instrumentation; +import java.lang.reflect.Method; + +/** Special lightweight pre-main class that skips installation on incompatible JVMs. */ +public class AgentPreCheck { + public static final String AGENT_BOOTSTRAP_CLASS = "datadog.trace.bootstrap.AgentBootstrap"; + + public static void premain(final String agentArgs, final Instrumentation inst) { + agentmain(agentArgs, inst); + } + + public static void agentmain(final String agentArgs, final Instrumentation inst) { + try { + if (compatible()) { + agentBootstrapPreMain(agentArgs, inst); + } + } catch (Throwable e) { + // If agent failed we should not fail the application. + // We don't have a log manager here, so just print. + System.err.println("ERROR: " + e.getMessage()); + } + } + + private static void reportIncompatibleJava( + String javaVersion, int majorJavaVersion, String agentVersion, PrintStream output) { + output.println( + "Warning: " + + (agentVersion == null ? "This version" : "Version " + agentVersion) + + " of dd-java-agent is not compatible with Java " + + javaVersion + + " and will not be installed."); + + String msg = "Please upgrade your Java version to 8+"; + if (majorJavaVersion == 7) { + msg += + " or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0"; + } + output.println(msg); + } + + static void sendTelemetry(String forwarderPath, String javaVersion, String agentVersion) { + // Hardcoded payload for unsupported Java version. + String payload = + "{\"metadata\":{" + + "\"runtime_name\":\"jvm\"," + + "\"language_name\":\"jvm\"," + + "\"runtime_version\":\"" + + javaVersion + + "\"," + + "\"language_version\":\"" + + javaVersion + + "\"," + + "\"tracer_version\":\"" + + agentVersion + + "\"}," + + "\"points\":[{" + + "\"name\":\"library_entrypoint.abort\"," + + "\"tags\":[\"reason:incompatible_runtime\"]" + + "}]" + + "}"; + + ForwarderJsonSenderThread t = new ForwarderJsonSenderThread(forwarderPath, payload); + t.setDaemon(true); + t.start(); + } + + @SuppressForbidden + private static boolean compatible() { + return compatible(System.getProperty("java.version"), System.err); + } + + // Reachable for testing + static boolean compatible(String javaVersion, PrintStream output) { + int majorJavaVersion = parseJavaMajorVersion(javaVersion); + + if (majorJavaVersion >= 8) { + return true; + } + + String agentVersion = getAgentVersion(); + + reportIncompatibleJava(javaVersion, majorJavaVersion, agentVersion, output); + + String forwarderPath = System.getenv("DD_TELEMETRY_FORWARDER_PATH"); + if (forwarderPath != null) { + sendTelemetry(forwarderPath, javaVersion, agentVersion); + } + + return false; + } + + // Reachable for testing + static int parseJavaMajorVersion(String javaVersion) { + int major = 0; + if (javaVersion == null || javaVersion.isEmpty()) { + return major; + } + + int start = 0; + if (javaVersion.charAt(0) == '1' + && javaVersion.length() >= 3 + && javaVersion.charAt(1) == '.' + && Character.isDigit(javaVersion.charAt(2))) { + start = 2; + } + + // Parse the major digit and be a bit lenient, allowing digits followed by any non digit + for (int i = start; i < javaVersion.length(); i++) { + char c = javaVersion.charAt(i); + if (Character.isDigit(c)) { + major *= 10; + major += Character.digit(c, 10); + } else { + break; + } + } + return major; + } + + private static String getAgentVersion() { + try { + // Get the resource as an InputStream + InputStream is = AgentPreCheck.class.getResourceAsStream("/dd-java-agent.version"); + if (is == null) { + return null; + } + + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + final StringBuilder sb = new StringBuilder(); + for (int c = reader.read(); c != -1; c = reader.read()) { + sb.append((char) c); + } + reader.close(); + + return sb.toString().trim(); + } catch (Throwable e) { + return null; + } + } + + @SuppressForbidden + private static void agentBootstrapPreMain(final String agentArgs, final Instrumentation inst) { + try { + Class clazz = Class.forName(AGENT_BOOTSTRAP_CLASS); + Method agentMain = clazz.getMethod("agentmain", String.class, Instrumentation.class); + agentMain.invoke(null, agentArgs, inst); + } catch (Throwable e) { + System.err.printf( + "Failed to execute %s.agentmain(): %s%n", AGENT_BOOTSTRAP_CLASS, e.getMessage()); + } + } + + public static final class ForwarderJsonSenderThread extends Thread { + private final String forwarderPath; + private final String payload; + + public ForwarderJsonSenderThread(String forwarderPath, String payload) { + super("dd-forwarder-json-sender"); + setDaemon(true); + this.forwarderPath = forwarderPath; + this.payload = payload; + } + + @Override + public void run() { + ProcessBuilder builder = new ProcessBuilder(forwarderPath, "library_entrypoint"); + try { + Process process = builder.start(); + OutputStream out = null; + try { + out = process.getOutputStream(); + out.write(payload.getBytes()); + } finally { + if (out != null) { + out.close(); + } + } + } catch (Throwable e) { + System.err.println("Failed to send telemetry: " + e.getMessage()); + } + } + } +} diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentBootstrapTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentBootstrapTest.groovy index ddeb330b672..6f2cd97fb77 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentBootstrapTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentBootstrapTest.groovy @@ -3,97 +3,6 @@ package datadog.trace.bootstrap import spock.lang.Specification class AgentBootstrapTest extends Specification { - def 'parse java.version strings'() { - when: - def major = AgentBootstrap.parseJavaMajorVersion(version) - - then: - major == expected - - where: - version | expected - null | 0 - '' | 0 - 'a.0.0' | 0 - '0.a.0' | 0 - '0.0.a' | 0 - '1.a.0_0' | 1 - '1.8.a_0' | 8 - '1.8.0_a' | 8 - '1.7' | 7 - '1.7.0' | 7 - '1.7.0_221' | 7 - '1.8' | 8 - '1.8.0' | 8 - '1.8.0_212' | 8 - '1.8.0_292' | 8 - '9-ea' | 9 - '9.0.4' | 9 - '9.1.2' | 9 - '10.0.2' | 10 - '11' | 11 - '11a' | 11 - '11.0.6' | 11 - '11.0.11' | 11 - '12.0.2' | 12 - '13.0.2' | 13 - '14' | 14 - '14.0.2' | 14 - '15' | 15 - '15.0.2' | 15 - '16.0.1' | 16 - '11.0.9.1+1' | 11 - '11.0.6+10' | 11 - } - - def 'log warning message when java version is less than 8'() { - setup: - def baos = new ByteArrayOutputStream() - def logStream = new PrintStream(baos) - - when: - def isLowerThan8 = AgentBootstrap.lessThanJava8(version, logStream) - logStream.flush() - def logLines = Arrays.asList(baos.toString().split('\n')) - // If the list only contains a single String and that is the empty String, then the set is empty - if (logLines.size() == 1 && logLines.contains('')) { - logLines = [] - } - - then: - isLowerThan8 == expectedLower - if (!expectedLower) { - assert logLines.isEmpty() - } else { - assert logLines.size() == 2 - assert logLines == [ - "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java ${version} and will not be installed.", - 'Please upgrade your Java version to 8+ or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0' - ] - } - - where: - version | expectedLower - null | true - '' | true - 'a.0.0' | true - '0.a.0' | true - '0.0.a' | true - '1.a.0_0' | true - '1.8.a_0' | false - '1.8.0_a' | false - '1.7' | true - '1.7.0' | true - '1.7.0_221' | true - '1.8' | false - '9.0.4' | false - '10.0.2' | false - '11a' | false - '15' | false - '11.0.9.1+1' | false - - } - def 'return true when first exception in the cause chain is the specified exception'() { setup: def ex = new IOException() diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy new file mode 100644 index 00000000000..a8b3c2897c2 --- /dev/null +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -0,0 +1,140 @@ +package datadog.trace.bootstrap + +import spock.lang.Specification +import spock.util.concurrent.PollingConditions + +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.attribute.PosixFilePermissions + +class AgentPreCheckTest extends Specification { + def 'parse java.version of #versionÆ’ as #expected'() { + when: + def major = AgentPreCheck.parseJavaMajorVersion(version) + + then: + major == expected + + where: + version | expected + null | 0 + '' | 0 + 'a.0.0' | 0 + '0.a.0' | 0 + '0.0.a' | 0 + '1.a.0_0' | 1 + '1.6' | 6 + '1.6.0_45' | 6 + '1.7' | 7 + '1.7.0' | 7 + '1.7.0_221' | 7 + '1.8.a_0' | 8 + '1.8.0_a' | 8 + '1.8' | 8 + '1.8.0' | 8 + '1.8.0_212' | 8 + '1.8.0_292' | 8 + '9-ea' | 9 + '9.0.4' | 9 + '9.1.2' | 9 + '10.0.2' | 10 + '11' | 11 + '11a' | 11 + '11.0.6' | 11 + '11.0.11' | 11 + '12.0.2' | 12 + '13.0.2' | 13 + '14' | 14 + '14.0.2' | 14 + '15' | 15 + '15.0.2' | 15 + '16.0.1' | 16 + '11.0.9.1+1' | 11 + '11.0.6+10' | 11 + '17.0.15' | 17 + '21.0.7' | 21 + } + + def 'log warning message when java is not compatible'() { + setup: + def output = new ByteArrayOutputStream() + def logStream = new PrintStream(output) + + when: + boolean compatible = AgentPreCheck.compatible(javaVersion, logStream) + String log = output.toString() + def logLines = log.isEmpty() ? [] : Arrays.asList(log.split('\n')) + + then: + compatible == expectedCompatible + + if (expectedCompatible) { + assert logLines.isEmpty() + } else { + logLines.size() == 2 + def expectedLogLines = [ + "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java ${javaVersion} and will not be installed.", + "Please upgrade your Java version to 8+" + (AgentPreCheck.parseJavaMajorVersion(javaVersion) == 7 ? " or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0" : "") + ] + assert logLines == expectedLogLines + } + where: + javaVersion | expectedCompatible + null | false + '' | false + '1.6.0_45' | false + '1.7.0_221' | false + '1.8.0_212' | true + '11.0.6' | true + '17.0.15' | true + '21.0.7' | true + } + + def 'send hardcoded bootstrap telemetry for unsupported java'() { + setup: + Path path = Files.createTempFile('test-forwarder', '.sh', PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString('rwxr--r--'))) + File forwarderFile = path.toFile() + forwarderFile.deleteOnExit() + + String forwarderPath = forwarderFile.getAbsolutePath() + + File outputFile = new File(forwarderPath + '.out') + outputFile.deleteOnExit() + + def script = [ + '#!/usr/bin/env bash', + 'echo "$1 $(cat -)" >>' + outputFile.getAbsolutePath(), + '' + ] + + forwarderFile << script.join('\n') + + when: + AgentPreCheck.sendTelemetry(forwarderPath, '1.6.0_45', '1.50') + + then: + new PollingConditions().within(5) { + assert outputFile.exists() + } + String payload = outputFile.text + String expectedPayload = ''' +{ + "metadata": { + "runtime_name": "jvm", + "language_name": "jvm", + "runtime_version": "1.6.0_45", + "language_version": "1.6.0_45", + "tracer_version": "1.50" + }, + "points": [ + { + "name": "library_entrypoint.abort", + "tags": [ + "reason:incompatible_runtime" + ] + } + ] +'''.replaceAll(/\s+/, '') + payload.contains(expectedPayload) + } +} From 99abf9957f8d8351c65a2906649a53ee219e4474 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 23 May 2025 10:58:07 -0400 Subject: [PATCH 04/14] Refactored build.gradle to reuse existing functions. --- dd-java-agent/build.gradle | 25 ++++++++----------- .../trace/bootstrap/AgentPreCheckTest.groovy | 5 +++- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 1c005f0f77b..7d57d72b335 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -17,31 +17,28 @@ configurations { traceShadowInclude } -// The special pre-check should be compiled with Java 6 to detect unsupported Java versions and -// prevent issues for users that still using them. +// The special pre-check should be compiled with Java 6 to detect unsupported Java versions +// and prevent issues for users that still using them. sourceSets { - java6 { - java { - srcDirs = ['src/main/java6'] - } + "main_java6" { + java.srcDirs "${project.projectDir}/src/main/java6" } } -tasks.register('compileJava6', JavaCompile) { - classpath = sourceSets.main.compileClasspath - source = sourceSets.java6.java - destinationDirectory = layout.buildDirectory.dir("classes/java/main") +compileMain_java6Java.configure { + setJavaVersion(it, 8) sourceCompatibility = JavaVersion.VERSION_1_6 targetCompatibility = JavaVersion.VERSION_1_6 + destinationDirectory = layout.buildDirectory.dir("classes/java/main") } +tasks.compileJava.dependsOn compileMain_java6Java + dependencies { - java6CompileOnly 'de.thetaphi:forbiddenapis:3.4' - testImplementation sourceSets.java6.output + main_java6CompileOnly 'de.thetaphi:forbiddenapis:3.4' + testImplementation sourceSets.main_java6.output } -tasks.compileJava.dependsOn compileJava6 - /* * Several shadow jars are created * - The main "dd-java-agent" jar that also has the bootstrap project diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index a8b3c2897c2..191b4788347 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -106,17 +106,18 @@ class AgentPreCheckTest extends Specification { 'echo "$1 $(cat -)" >>' + outputFile.getAbsolutePath(), '' ] - forwarderFile << script.join('\n') when: AgentPreCheck.sendTelemetry(forwarderPath, '1.6.0_45', '1.50') then: + // Await completion of the external process handling the payload. new PollingConditions().within(5) { assert outputFile.exists() } String payload = outputFile.text + String expectedPayload = ''' { "metadata": { @@ -135,6 +136,8 @@ class AgentPreCheckTest extends Specification { } ] '''.replaceAll(/\s+/, '') + + // Assert that the actual payload contains the expected data. payload.contains(expectedPayload) } } From 2eb2753eef16d425bb41e8171c9b74ff279adbf7 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 23 May 2025 11:11:10 -0400 Subject: [PATCH 05/14] Minor cleanup. --- .../trace/bootstrap/AgentPreCheck.java | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index 64fd8644af7..931679e04f7 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -11,8 +11,6 @@ /** Special lightweight pre-main class that skips installation on incompatible JVMs. */ public class AgentPreCheck { - public static final String AGENT_BOOTSTRAP_CLASS = "datadog.trace.bootstrap.AgentBootstrap"; - public static void premain(final String agentArgs, final Instrumentation inst) { agentmain(agentArgs, inst); } @@ -20,7 +18,7 @@ public static void premain(final String agentArgs, final Instrumentation inst) { public static void agentmain(final String agentArgs, final Instrumentation inst) { try { if (compatible()) { - agentBootstrapPreMain(agentArgs, inst); + continueBootstrap(agentArgs, inst); } } catch (Throwable e) { // If agent failed we should not fail the application. @@ -146,16 +144,11 @@ private static String getAgentVersion() { } } - @SuppressForbidden - private static void agentBootstrapPreMain(final String agentArgs, final Instrumentation inst) { - try { - Class clazz = Class.forName(AGENT_BOOTSTRAP_CLASS); - Method agentMain = clazz.getMethod("agentmain", String.class, Instrumentation.class); - agentMain.invoke(null, agentArgs, inst); - } catch (Throwable e) { - System.err.printf( - "Failed to execute %s.agentmain(): %s%n", AGENT_BOOTSTRAP_CLASS, e.getMessage()); - } + private static void continueBootstrap(final String agentArgs, final Instrumentation inst) + throws Exception { + Class clazz = Class.forName("datadog.trace.bootstrap.AgentBootstrap"); + Method agentMain = clazz.getMethod("agentmain", String.class, Instrumentation.class); + agentMain.invoke(null, agentArgs, inst); } public static final class ForwarderJsonSenderThread extends Thread { From 0c2e81720999b66e0a6465a41e03f85237ef1753 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 23 May 2025 11:28:06 -0400 Subject: [PATCH 06/14] Added missing `@SuppressForbidden`. --- .../src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index 931679e04f7..c2c8b971c2c 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -15,6 +15,7 @@ public static void premain(final String agentArgs, final Instrumentation inst) { agentmain(agentArgs, inst); } + @SuppressForbidden public static void agentmain(final String agentArgs, final Instrumentation inst) { try { if (compatible()) { @@ -144,6 +145,7 @@ private static String getAgentVersion() { } } + @SuppressForbidden private static void continueBootstrap(final String agentArgs, final Instrumentation inst) throws Exception { Class clazz = Class.forName("datadog.trace.bootstrap.AgentBootstrap"); @@ -162,6 +164,7 @@ public ForwarderJsonSenderThread(String forwarderPath, String payload) { this.payload = payload; } + @SuppressForbidden @Override public void run() { ProcessBuilder builder = new ProcessBuilder(forwarderPath, "library_entrypoint"); From ea5bea7f5ede575c999aa06050443dbb97e5bf9e Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Fri, 23 May 2025 16:56:30 -0400 Subject: [PATCH 07/14] Added 'java.home' to warning. That would help to identify problematic JVM. --- dd-java-agent/build.gradle | 2 +- .../trace/bootstrap/AgentPreCheck.java | 27 +++++++++++++++---- .../trace/bootstrap/AgentPreCheckTest.groovy | 4 +-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/dd-java-agent/build.gradle b/dd-java-agent/build.gradle index 7d57d72b335..84a0ec81bd6 100644 --- a/dd-java-agent/build.gradle +++ b/dd-java-agent/build.gradle @@ -35,7 +35,7 @@ compileMain_java6Java.configure { tasks.compileJava.dependsOn compileMain_java6Java dependencies { - main_java6CompileOnly 'de.thetaphi:forbiddenapis:3.4' + main_java6CompileOnly 'de.thetaphi:forbiddenapis:3.8' testImplementation sourceSets.main_java6.output } diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index c2c8b971c2c..a027b75d50f 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -29,13 +29,19 @@ public static void agentmain(final String agentArgs, final Instrumentation inst) } private static void reportIncompatibleJava( - String javaVersion, int majorJavaVersion, String agentVersion, PrintStream output) { + String javaVersion, + int majorJavaVersion, + String javaHome, + String agentVersion, + PrintStream output) { output.println( "Warning: " + (agentVersion == null ? "This version" : "Version " + agentVersion) + " of dd-java-agent is not compatible with Java " + javaVersion - + " and will not be installed."); + + " in '" + + javaHome + + "' and will not be installed."); String msg = "Please upgrade your Java version to 8+"; if (majorJavaVersion == 7) { @@ -71,13 +77,24 @@ static void sendTelemetry(String forwarderPath, String javaVersion, String agent t.start(); } + private static String tryGetProperty(String property) { + try { + return System.getProperty(property); + } catch (SecurityException e) { + return null; + } + } + @SuppressForbidden private static boolean compatible() { - return compatible(System.getProperty("java.version"), System.err); + String javaVersion = tryGetProperty("java.version"); + String javaHome = tryGetProperty("java.home"); + + return compatible(javaVersion, javaHome, System.err); } // Reachable for testing - static boolean compatible(String javaVersion, PrintStream output) { + static boolean compatible(String javaVersion, String javaHome, PrintStream output) { int majorJavaVersion = parseJavaMajorVersion(javaVersion); if (majorJavaVersion >= 8) { @@ -86,7 +103,7 @@ static boolean compatible(String javaVersion, PrintStream output) { String agentVersion = getAgentVersion(); - reportIncompatibleJava(javaVersion, majorJavaVersion, agentVersion, output); + reportIncompatibleJava(javaVersion, majorJavaVersion, javaHome, agentVersion, output); String forwarderPath = System.getenv("DD_TELEMETRY_FORWARDER_PATH"); if (forwarderPath != null) { diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index 191b4788347..7e97c8b20d9 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -61,7 +61,7 @@ class AgentPreCheckTest extends Specification { def logStream = new PrintStream(output) when: - boolean compatible = AgentPreCheck.compatible(javaVersion, logStream) + boolean compatible = AgentPreCheck.compatible(javaVersion, "/Library/$javaVersion", logStream) String log = output.toString() def logLines = log.isEmpty() ? [] : Arrays.asList(log.split('\n')) @@ -73,7 +73,7 @@ class AgentPreCheckTest extends Specification { } else { logLines.size() == 2 def expectedLogLines = [ - "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java ${javaVersion} and will not be installed.", + "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java $javaVersion in '/Library/$javaVersion' and will not be installed.", "Please upgrade your Java version to 8+" + (AgentPreCheck.parseJavaMajorVersion(javaVersion) == 7 ? " or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0" : "") ] assert logLines == expectedLogLines From 9238f7da418220c5dcb826c66c1c144c1ac92e48 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Sat, 24 May 2025 10:44:04 -0400 Subject: [PATCH 08/14] Added test to ensure Java 6 & 8 compilation. --- .../trace/bootstrap/AgentPreCheck.java | 2 +- .../trace/bootstrap/AgentPreCheckTest.groovy | 25 ++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index a027b75d50f..926778e9647 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -39,7 +39,7 @@ private static void reportIncompatibleJava( + (agentVersion == null ? "This version" : "Version " + agentVersion) + " of dd-java-agent is not compatible with Java " + javaVersion - + " in '" + + " found at '" + javaHome + "' and will not be installed."); diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index 7e97c8b20d9..6acb4bf2d57 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -73,7 +73,7 @@ class AgentPreCheckTest extends Specification { } else { logLines.size() == 2 def expectedLogLines = [ - "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java $javaVersion in '/Library/$javaVersion' and will not be installed.", + "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java $javaVersion found at '/Library/$javaVersion' and will not be installed.", "Please upgrade your Java version to 8+" + (AgentPreCheck.parseJavaMajorVersion(javaVersion) == 7 ? " or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0" : "") ] assert logLines == expectedLogLines @@ -140,4 +140,27 @@ class AgentPreCheckTest extends Specification { // Assert that the actual payload contains the expected data. payload.contains(expectedPayload) } + + private DataInputStream classStream(Class clazz) { + String resource = clazz.getName().replace('.', '/') + '.class' + new DataInputStream(this.getClass().getClassLoader().getResourceAsStream(resource)) + } + + def 'check #clazz compiled with Java #javaVersion'() { + expect: + classStream(clazz).withCloseable { stream -> + def magic = Integer.toUnsignedLong(stream.readInt()) + def minor = (int) stream.readShort() + def major = (int) stream.readShort() + + magic == 0xCAFEBABEL + minor == 0 + major == expectedMajor + } + + where: + clazz | javaVersion | expectedMajor + AgentPreCheck | 6 | 50 + AgentBootstrap | 8 | 52 + } } From 5f61b621e070192f00900500e4991b7b2c93deb6 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Sat, 24 May 2025 12:02:35 -0400 Subject: [PATCH 09/14] Fixed test. --- .../trace/bootstrap/AgentPreCheckTest.groovy | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index 6acb4bf2d57..1828eb40e74 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -141,22 +141,21 @@ class AgentPreCheckTest extends Specification { payload.contains(expectedPayload) } - private DataInputStream classStream(Class clazz) { - String resource = clazz.getName().replace('.', '/') + '.class' - new DataInputStream(this.getClass().getClassLoader().getResourceAsStream(resource)) - } - def 'check #clazz compiled with Java #javaVersion'() { + setup: + def resource = clazz.getName().replace('.', '/') + '.class' + def stream = new DataInputStream(this.getClass().getClassLoader().getResourceAsStream(resource)) + expect: - classStream(clazz).withCloseable { stream -> - def magic = Integer.toUnsignedLong(stream.readInt()) - def minor = (int) stream.readShort() - def major = (int) stream.readShort() - - magic == 0xCAFEBABEL - minor == 0 - major == expectedMajor - } + stream.withCloseable { + def magic = Integer.toUnsignedLong(it.readInt()) + def minor = (int) it.readShort() + def major = (int) it.readShort() + + assert magic == 0xCAFEBABE + assert minor == 0 + assert major == expectedMajor + } == null where: clazz | javaVersion | expectedMajor From 5fa1bb6beca605e70c7c23978bc3d3714ab4d1fb Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Tue, 27 May 2025 13:26:35 -0400 Subject: [PATCH 10/14] Drop support for 0.x version. --- .../datadog/trace/bootstrap/AgentPreCheck.java | 16 +++------------- .../trace/bootstrap/AgentPreCheckTest.groovy | 4 ++-- .../src/test/java/StartWithAgentTest.java | 2 +- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index 926778e9647..f4d57338311 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -29,11 +29,7 @@ public static void agentmain(final String agentArgs, final Instrumentation inst) } private static void reportIncompatibleJava( - String javaVersion, - int majorJavaVersion, - String javaHome, - String agentVersion, - PrintStream output) { + String javaVersion, String javaHome, String agentVersion, PrintStream output) { output.println( "Warning: " + (agentVersion == null ? "This version" : "Version " + agentVersion) @@ -42,13 +38,7 @@ private static void reportIncompatibleJava( + " found at '" + javaHome + "' and will not be installed."); - - String msg = "Please upgrade your Java version to 8+"; - if (majorJavaVersion == 7) { - msg += - " or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0"; - } - output.println(msg); + output.println("Please upgrade your Java version to 8+"); } static void sendTelemetry(String forwarderPath, String javaVersion, String agentVersion) { @@ -103,7 +93,7 @@ static boolean compatible(String javaVersion, String javaHome, PrintStream outpu String agentVersion = getAgentVersion(); - reportIncompatibleJava(javaVersion, majorJavaVersion, javaHome, agentVersion, output); + reportIncompatibleJava(javaVersion, javaHome, agentVersion, output); String forwarderPath = System.getenv("DD_TELEMETRY_FORWARDER_PATH"); if (forwarderPath != null) { diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index 1828eb40e74..01c8d73b9e2 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -74,7 +74,7 @@ class AgentPreCheckTest extends Specification { logLines.size() == 2 def expectedLogLines = [ "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java $javaVersion found at '/Library/$javaVersion' and will not be installed.", - "Please upgrade your Java version to 8+" + (AgentPreCheck.parseJavaMajorVersion(javaVersion) == 7 ? " or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0" : "") + "Please upgrade your Java version to 8+" ] assert logLines == expectedLogLines } @@ -152,7 +152,7 @@ class AgentPreCheckTest extends Specification { def minor = (int) it.readShort() def major = (int) it.readShort() - assert magic == 0xCAFEBABE + assert magic == 0xCAFEBABEL assert minor == 0 assert major == expectedMajor } == null diff --git a/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java b/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java index b9acd13cb51..9b07e20ba97 100644 --- a/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java +++ b/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java @@ -15,7 +15,7 @@ public class StartWithAgentTest { private static final Pattern WARNING_PATTERN = Pattern.compile("^Warning: Version [^ ]+ of dd-java-agent is not compatible with Java [^ ]+ and will not be installed\\.$"); - private static final String UPGRADE_MESSAGE = "Please upgrade your Java version to 8+ or use the 0.x version of dd-java-agent in your build tool or download it from https://dtdg.co/java-tracer-v0"; + private static final String UPGRADE_MESSAGE = "Please upgrade your Java version to 8+"; @Test void ensureThatApplicationStartsWithAgentOnJava7() throws InterruptedException, IOException { From be58d6bcd91015a4aacb308de74ecb7110538754 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Tue, 27 May 2025 15:24:06 -0400 Subject: [PATCH 11/14] Fixed small typo. --- .../groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index 01c8d73b9e2..ea726ece99b 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -8,7 +8,7 @@ import java.nio.file.Path import java.nio.file.attribute.PosixFilePermissions class AgentPreCheckTest extends Specification { - def 'parse java.version of #versionÆ’ as #expected'() { + def 'parse java.version of #version as #expected'() { when: def major = AgentPreCheck.parseJavaMajorVersion(version) From 7c2a597f88229970f68085c8347565e23fcb2af0 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Tue, 27 May 2025 17:10:35 -0400 Subject: [PATCH 12/14] Fixed test. --- .../agent-logs-on-java-7/src/test/java/StartWithAgentTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java b/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java index 9b07e20ba97..7b54e50c233 100644 --- a/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java +++ b/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java @@ -14,7 +14,7 @@ public class StartWithAgentTest { - private static final Pattern WARNING_PATTERN = Pattern.compile("^Warning: Version [^ ]+ of dd-java-agent is not compatible with Java [^ ]+ and will not be installed\\.$"); + private static final Pattern WARNING_PATTERN = Pattern.compile("^Warning: Version [^ ]+ of dd-java-agent is not compatible with Java [^ ]+ found at [^ ]+ and will not be installed\\.$"); private static final String UPGRADE_MESSAGE = "Please upgrade your Java version to 8+"; @Test From 8192ac413aee60b614a2d4c0bd939f9a0c7de9ec Mon Sep 17 00:00:00 2001 From: Alexey Date: Wed, 28 May 2025 10:30:24 -0400 Subject: [PATCH 13/14] Update dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java Co-authored-by: Brice Dutheil --- .../src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java index f4d57338311..a2919226eb5 100644 --- a/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java +++ b/dd-java-agent/src/main/java6/datadog/trace/bootstrap/AgentPreCheck.java @@ -37,7 +37,7 @@ private static void reportIncompatibleJava( + javaVersion + " found at '" + javaHome - + "' and will not be installed."); + + "' and is effectively disabled."); output.println("Please upgrade your Java version to 8+"); } From e1df6fe273fbbcc9c7d772280d03ce89789dbde4 Mon Sep 17 00:00:00 2001 From: Alexey Kuznetsov Date: Wed, 28 May 2025 10:37:23 -0400 Subject: [PATCH 14/14] Fixed test. --- .../groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy | 2 +- .../agent-logs-on-java-7/src/test/java/StartWithAgentTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy index ea726ece99b..e67614813b5 100644 --- a/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy +++ b/dd-java-agent/src/test/groovy/datadog/trace/bootstrap/AgentPreCheckTest.groovy @@ -73,7 +73,7 @@ class AgentPreCheckTest extends Specification { } else { logLines.size() == 2 def expectedLogLines = [ - "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java $javaVersion found at '/Library/$javaVersion' and will not be installed.", + "Warning: Version ${AgentJar.getAgentVersion()} of dd-java-agent is not compatible with Java $javaVersion found at '/Library/$javaVersion' and is effectively disabled.", "Please upgrade your Java version to 8+" ] assert logLines == expectedLogLines diff --git a/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java b/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java index 7b54e50c233..b354b5e30e0 100644 --- a/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java +++ b/test-published-dependencies/agent-logs-on-java-7/src/test/java/StartWithAgentTest.java @@ -14,7 +14,7 @@ public class StartWithAgentTest { - private static final Pattern WARNING_PATTERN = Pattern.compile("^Warning: Version [^ ]+ of dd-java-agent is not compatible with Java [^ ]+ found at [^ ]+ and will not be installed\\.$"); + private static final Pattern WARNING_PATTERN = Pattern.compile("^Warning: Version [^ ]+ of dd-java-agent is not compatible with Java [^ ]+ found at [^ ]+ and is effectively disabled\\.$"); private static final String UPGRADE_MESSAGE = "Please upgrade your Java version to 8+"; @Test