Skip to content

Commit

Permalink
Instrument Gradle Launcher to avoid overwriting org.gradle.jvmargs pr…
Browse files Browse the repository at this point in the history
…operty
  • Loading branch information
nikita-tkachenko-datadog committed Nov 22, 2024
1 parent adf9784 commit 0bff977
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,21 @@ public boolean isChild() {
* not one of the supported build system processes.
*/
public boolean isHeadless() {
return !isChild() && !isParent();
return !isChild() && !isParent() && !isWrapper();
}

private boolean isParent() {
return isMavenParent() || isGradleDaemon();
}

/**
* Determines if current process is a wrapper that starts the build system. In other words a
* process that is not a build system, and not a JVM that runs tests.
*/
private boolean isWrapper() {
return isGradleLauncher();
}

private boolean isMavenParent() {
return System.getProperty("maven.home") != null
&& System.getProperty("classworlds.conf") != null;
Expand All @@ -70,6 +78,12 @@ private boolean isGradleDaemon() {
&& System.getProperties().getProperty("org.gradle.internal.worker.tmpdir") == null;
}

private boolean isGradleLauncher() {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
return contextClassLoader.getResource("org/gradle/launcher/Main.class") != null
|| contextClassLoader.getResource("org/gradle/launcher/GradleMain.class") != null;
}

@Nullable
public InetSocketAddress getSignalServerAddress() {
// System.getProperty is used rather than Config,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@ public TestRetryPolicy retryPolicy(TestIdentifier test) {
public boolean isEarlyFlakeDetectionLimitReached() {
int detectionsUsed = earlyFlakeDetectionsUsed.get();
Collection<TestIdentifier> knownTests = executionSettings.getKnownTests();
int totalTests = knownTests.size() + detectionsUsed;
if (knownTests == null) {
return false;
}

int totalTests = knownTests.size() + detectionsUsed;
EarlyFlakeDetectionSettings earlyFlakeDetectionSettings =
executionSettings.getEarlyFlakeDetectionSettings();
int threshold =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package datadog.trace.instrumentation.gradle;

import static net.bytebuddy.matcher.ElementMatchers.isConstructor;

import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.agent.tooling.InstrumenterModule;
import datadog.trace.api.Config;
import java.io.File;
import java.nio.file.Path;
import java.util.Map;
import java.util.Properties;
import net.bytebuddy.asm.Advice;
import org.gradle.process.internal.JvmOptions;

/**
* This instrumentation targets Gradle Launcher, which is the process that is started with
* `gradle`/`gradlew` commands. The launcher starts Gradle Daemon (if not started yet), which is a
* long-lived process that actually runs builds. The instrumentation injects the tracer and its
* config properties into Gradle Daemon JVM settings when the daemon is started.
*/
@AutoService(InstrumenterModule.class)
public class GradleDaemonJvmOptionsInstrumentation extends InstrumenterModule.CiVisibility
implements Instrumenter.ForSingleType {

public GradleDaemonJvmOptionsInstrumentation() {
super("gradle", "gradle-daemon-jvm-options");
}

@Override
public String instrumentedType() {
return "org.gradle.launcher.daemon.configuration.DaemonJvmOptions";
}

@Override
public void methodAdvice(MethodTransformer transformer) {
transformer.applyAdvice(
isConstructor(),
GradleDaemonJvmOptionsInstrumentation.class.getName() + "$InjectJavaAgent");
}

public static class InjectJavaAgent {
@Advice.OnMethodExit(suppress = Throwable.class)
public static void injectJavaAgent(@Advice.This final JvmOptions daemonJvmOptions) {
File agentJar = Config.get().getCiVisibilityAgentJarFile();
Path agentJarPath = agentJar.toPath();

StringBuilder agentArg = new StringBuilder("-javaagent:").append(agentJarPath).append('=');

Properties systemProperties = System.getProperties();
for (Map.Entry<Object, Object> e : systemProperties.entrySet()) {
String propertyName = (String) e.getKey();
Object propertyValue = e.getValue();
if (propertyName.startsWith(Config.PREFIX)) {
daemonJvmOptions.systemProperty(propertyName, propertyValue);
agentArg.append(propertyName).append('=').append(propertyValue).append(',');
}
}

daemonJvmOptions.jvmArgs(agentArg);
}
}
}

0 comments on commit 0bff977

Please sign in to comment.