From 0ebc011639e0c1f3e8b9895374da6e4c6eb706ac Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Fri, 14 Nov 2025 15:21:31 +0100 Subject: [PATCH 01/20] chore: Move CSI plugin to it's own package --- buildSrc/build.gradle.kts | 2 +- .../csi/CallSiteInstrumentationExtension.kt | 69 +++++++++++++++++++ .../CallSiteInstrumentationPlugin.kt | 52 +------------- 3 files changed, 71 insertions(+), 52 deletions(-) create mode 100644 buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt rename buildSrc/src/main/kotlin/datadog/gradle/plugin/{ => csi}/CallSiteInstrumentationPlugin.kt (76%) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 16e46b0f700..563339e915d 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -24,7 +24,7 @@ gradlePlugin { } create("call-site-instrumentation-plugin") { id = "call-site-instrumentation" - implementationClass = "datadog.gradle.plugin.CallSiteInstrumentationPlugin" + implementationClass = "datadog.gradle.plugin.csi.CallSiteInstrumentationPlugin" } create("tracer-version-plugin") { id = "datadog.tracer-version" diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt new file mode 100644 index 00000000000..737f51001a9 --- /dev/null +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -0,0 +1,69 @@ +package datadog.gradle.plugin.csi + +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.ProjectLayout +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.jvm.toolchain.JavaLanguageVersion +import java.io.File +import javax.inject.Inject + + +/** + * This extension allows to configure the Call Site Instrumenter plugin execution. + */ +abstract class CallSiteInstrumentationExtension @Inject constructor( + objectFactory: ObjectFactory, + layout: ProjectLayout +) { + companion object { + const val CALL_SITE_CLASS_SUFFIX = "CallSite" + const val CALL_SITE_CONSOLE_REPORTER = "CONSOLE" + const val CALL_SITE_ERROR_CONSOLE_REPORTER = "ERROR_CONSOLE" + } + + /** + * The location of the source code to generate call site ({@code /src/main/java} by default). + */ + val srcFolder: DirectoryProperty = objectFactory.directoryProperty().convention( + layout.projectDirectory.dir("src").dir("main").dir("java") + ) + + /** + * The location to generate call site source code ({@code /build/generated/sources/csi} by default). + */ + val targetFolder: DirectoryProperty = objectFactory.directoryProperty().convention( + layout.buildDirectory.dir("generated${File.separatorChar}sources${File.separatorChar}csi") + ) + + /** + * The generated call site source file suffix (#CALL_SITE_CLASS_SUFFIX by default). + */ + val suffix: Property = objectFactory.property(String::class.java).convention(CALL_SITE_CLASS_SUFFIX) + + /** + * The reporters to use after call site instrumenter run (only #CALL_SITE_CONSOLE_REPORTER and #CALL_SITE_ERROR_CONSOLE_REPORTER supported for now). + */ + val reporters: ListProperty = objectFactory.listProperty(String::class.java).convention( + listOf( + CALL_SITE_ERROR_CONSOLE_REPORTER + ) + ) + + /** + * The location of the dd-trace-java project to look for the call site instrumenter (optional, current project root folder used if not set). + */ + abstract val rootFolder: Property + + /** + * The JVM to use to run the call site instrumenter (optional, default JVM used if not set). + */ + abstract val javaVersion: Property + + /** + * The JVM arguments to run the call site instrumenter. + */ + val jvmArgs: ListProperty = + objectFactory.listProperty(String::class.java).convention(listOf("-Xmx128m", "-Xms64m")) +} diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt similarity index 76% rename from buildSrc/src/main/kotlin/datadog/gradle/plugin/CallSiteInstrumentationPlugin.kt rename to buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index ad1d97f1240..8b7bc9785e7 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -1,15 +1,10 @@ -package datadog.gradle.plugin +package datadog.gradle.plugin.csi import org.gradle.api.GradleException import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.ProjectLayout -import org.gradle.api.model.ObjectFactory import org.gradle.api.plugins.JavaPluginExtension -import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.Property import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.SourceSetContainer @@ -24,51 +19,6 @@ import java.nio.file.Paths import javax.inject.Inject private const val CALL_SITE_INSTRUMENTER_MAIN_CLASS = "datadog.trace.plugin.csi.PluginApplication" -private const val CALL_SITE_CLASS_SUFFIX = "CallSite" -private const val CALL_SITE_CONSOLE_REPORTER = "CONSOLE" -private const val CALL_SITE_ERROR_CONSOLE_REPORTER = "ERROR_CONSOLE" - -/** - * This extension allows to configure the Call Site Instrumenter plugin execution. - */ -abstract class CallSiteInstrumentationExtension @Inject constructor(objectFactory: ObjectFactory, layout: ProjectLayout) { - /** - * The location of the source code to generate call site ({@code /src/main/java} by default). - */ - val srcFolder: DirectoryProperty = objectFactory.directoryProperty().convention( - layout.projectDirectory.dir("src").dir("main").dir("java") - ) - /** - * The location to generate call site source code ({@code /build/generated/sources/csi} by default). - */ - val targetFolder: DirectoryProperty = objectFactory.directoryProperty().convention( - layout.buildDirectory.dir("generated${File.separatorChar}sources${File.separatorChar}csi") - ) - /** - * The generated call site source file suffix (#CALL_SITE_CLASS_SUFFIX by default). - */ - val suffix: Property = objectFactory.property(String::class.java).convention(CALL_SITE_CLASS_SUFFIX) - /** - * The reporters to use after call site instrumenter run (only #CALL_SITE_CONSOLE_REPORTER and #CALL_SITE_ERROR_CONSOLE_REPORTER supported for now). - */ - val reporters: ListProperty = objectFactory.listProperty(String::class.java).convention(listOf( - CALL_SITE_ERROR_CONSOLE_REPORTER - )) - /** - * The location of the dd-trace-java project to look for the call site instrumenter (optional, current project root folder used if not set). - */ - abstract val rootFolder: Property - - /** - * The JVM to use to run the call site instrumenter (optional, default JVM used if not set). - */ - abstract val javaVersion: Property - - /** - * The JVM arguments to run the call site instrumenter. - */ - val jvmArgs: ListProperty = objectFactory.listProperty(String::class.java).convention(listOf("-Xmx128m", "-Xms64m")) -} abstract class CallSiteInstrumentationPlugin : Plugin{ @get:Inject From 6cedb81d54d7aab35bc1654bc9045481a98e3faa Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Fri, 14 Nov 2025 15:30:27 +0100 Subject: [PATCH 02/20] chore: Tweak some API to use kotlin friendly functions --- .../csi/CallSiteInstrumentationExtension.kt | 6 ++-- .../csi/CallSiteInstrumentationPlugin.kt | 32 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 737f51001a9..c68fdbe57d3 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -40,12 +40,12 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( /** * The generated call site source file suffix (#CALL_SITE_CLASS_SUFFIX by default). */ - val suffix: Property = objectFactory.property(String::class.java).convention(CALL_SITE_CLASS_SUFFIX) + val suffix: Property = objectFactory.property().convention(CALL_SITE_CLASS_SUFFIX) /** * The reporters to use after call site instrumenter run (only #CALL_SITE_CONSOLE_REPORTER and #CALL_SITE_ERROR_CONSOLE_REPORTER supported for now). */ - val reporters: ListProperty = objectFactory.listProperty(String::class.java).convention( + val reporters: ListProperty = objectFactory.listProperty().convention( listOf( CALL_SITE_ERROR_CONSOLE_REPORTER ) @@ -65,5 +65,5 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( * The JVM arguments to run the call site instrumenter. */ val jvmArgs: ListProperty = - objectFactory.listProperty(String::class.java).convention(listOf("-Xmx128m", "-Xms64m")) + objectFactory.listProperty().convention(listOf("-Xmx128m", "-Xms64m")) } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 8b7bc9785e7..7d8f10060c4 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -4,6 +4,7 @@ import org.gradle.api.GradleException import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.file.FileSystemOperations import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSet @@ -13,6 +14,11 @@ import org.gradle.api.tasks.testing.Test import org.gradle.jvm.tasks.Jar import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaToolchainService +import org.gradle.kotlin.dsl.create +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.named +import org.gradle.kotlin.dsl.register +import org.gradle.kotlin.dsl.withType import java.io.File import java.nio.file.Files import java.nio.file.Paths @@ -26,7 +32,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ override fun apply(project: Project) { // Create plugin extension - val extension = project.extensions.create("csi", CallSiteInstrumentationExtension::class.java) + val extension = project.extensions.create("csi") project.afterEvaluate { configureSourceSets(project, extension) createTasks(project, extension) @@ -48,7 +54,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ extendsFrom(project.configurations.named(mainSourceSet.compileClasspathConfigurationName).get()) } - project.tasks.named(csiSourceSet.getCompileTaskName("java"), AbstractCompile::class.java) { + project.tasks.named(csiSourceSet.getCompileTaskName("java")) { sourceCompatibility = JavaVersion.VERSION_1_8.toString() targetCompatibility = JavaVersion.VERSION_1_8.toString() } @@ -61,7 +67,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ project.dependencies.add("testImplementation", csiSourceSet.output) // include classes in final JAR - project.tasks.named("jar", Jar::class.java) { + project.tasks.named("jar") { from(csiSourceSet.output.classesDirs) } } @@ -86,19 +92,21 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } private fun getSourceSets(project: Project): SourceSetContainer { - return project.extensions.getByType(JavaPluginExtension::class.java).sourceSets + return project.extensions.getByType().sourceSets } private fun createTasks(project: Project, extension: CallSiteInstrumentationExtension) { registerGenerateCallSiteTask(project, extension, "compileJava") val targetFolder = extension.targetFolder.get().asFile - project.tasks.withType(AbstractCompile::class.java).matching { + + project.tasks.withType().matching { task -> task.name.startsWith("compileTest") }.configureEach { inputs.dir(extension.targetFolder) classpath += project.files(targetFolder) } - project.tasks.withType(Test::class.java).configureEach { + + project.tasks.withType().configureEach { inputs.dir(extension.targetFolder) classpath += project.files(targetFolder) } @@ -123,16 +131,17 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ "libs", "call-site-instrumentation-plugin-all.jar" ).toFile() - val compileTask = project.tasks.named(compileTaskName, AbstractCompile::class.java) - val callSiteGeneratorTask = project.tasks.register(taskName, JavaExec::class.java) { + val compileTask = project.tasks.named(compileTaskName) + val callSiteGeneratorTask = project.tasks.register(taskName) { // Task description group = "call site instrumentation" - description = "Generates call sites from ${compileTaskName}" + description = "Generates call sites from $compileTaskName" // Task input & output val output = extension.targetFolder val inputProvider = compileTask.map { it.destinationDirectory.get() } inputs.dir(inputProvider) outputs.dir(output) + // JavaExec configuration if (extension.javaVersion.isPresent) { configureLanguage(this, extension.javaVersion.get()) @@ -140,6 +149,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ jvmArgumentProviders.add({ extension.jvmArgs.get() }) classpath(pluginJarFile) mainClass.set(CALL_SITE_INSTRUMENTER_MAIN_CLASS) + // Write the call site instrumenter arguments into a temporary file doFirst { val programClassPath = getProgramClasspath(project).map { it.toString() } @@ -179,12 +189,12 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ private fun getProgramClasspath(project: Project): List { val classpath = ArrayList() // 1. Compilation outputs - exclude latestDep and forked test variants - project.tasks.withType(AbstractCompile::class.java) + project.tasks.withType() .filter { task -> !task.name.contains("LatestDep", ignoreCase = true) && !task.name.contains("Forked", ignoreCase = true) } .map { it.destinationDirectory.asFile.get() } .forEach(classpath::add) // 2. Compile time dependencies - exclude latestDep and forked test variants - project.tasks.withType(AbstractCompile::class.java) + project.tasks.withType() .filter { task -> !task.name.contains("LatestDep", ignoreCase = true) && !task.name.contains("Forked", ignoreCase = true) } .flatMap { it.classpath } .forEach(classpath::add) From 8ebb5110f260c4793e21ef1310f9e82d4e54163f Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Fri, 14 Nov 2025 15:58:30 +0100 Subject: [PATCH 03/20] fix: Restrict default CSI classpath to main and test, compile and runtime configurations. --- .../csi/CallSiteInstrumentationExtension.kt | 26 ++++++++++++++++ .../csi/CallSiteInstrumentationPlugin.kt | 30 ++++++------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index c68fdbe57d3..2b2cd53baea 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -1,11 +1,20 @@ package datadog.gradle.plugin.csi +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory +import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.plugins.JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME +import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property +import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME +import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.kotlin.dsl.listProperty +import org.gradle.kotlin.dsl.property import java.io.File import javax.inject.Inject @@ -14,6 +23,7 @@ import javax.inject.Inject * This extension allows to configure the Call Site Instrumenter plugin execution. */ abstract class CallSiteInstrumentationExtension @Inject constructor( + project: Project, objectFactory: ObjectFactory, layout: ProjectLayout ) { @@ -66,4 +76,20 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( */ val jvmArgs: ListProperty = objectFactory.listProperty().convention(listOf("-Xmx128m", "-Xms64m")) + + /** + * The configurations to use to look for the call site instrumenter dependencies. + * + * By default, includes all `main*` source sets, but only the `test` + * (as wee don't want other test configurations by default). + */ + val configurations = objectFactory.listProperty().convention( + project.provider { + project.configurations.matching { + // Includes all main* source sets, but only the test (as wee don;t want other ) + (it.name.startsWith(MAIN_SOURCE_SET_NAME) || it.name == TEST_SOURCE_SET_NAME) + && (it.name.endsWith(RUNTIME_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true) || it.name.endsWith(COMPILE_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true)) + } + } + ) } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 7d8f10060c4..ae162fdf840 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -4,10 +4,10 @@ import org.gradle.api.GradleException import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.file.FileSystemOperations import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.JavaExec -import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME +import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.testing.Test @@ -43,7 +43,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ // create a new source set for the csi files val targetFolder = newBuildFolder(project, extension.targetFolder.get().asFile.toString()) val sourceSets = getSourceSets(project) - val mainSourceSet = sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME).get() + val mainSourceSet = sourceSets.named(MAIN_SOURCE_SET_NAME).get() val csiSourceSet = sourceSets.create("csi") { compileClasspath += mainSourceSet.output // mainly needed for the plugin tests annotationProcessorPath += mainSourceSet.annotationProcessorPath @@ -60,7 +60,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } // add csi classes to test classpath - sourceSets.named(SourceSet.TEST_SOURCE_SET_NAME) { + sourceSets.named(TEST_SOURCE_SET_NAME) { compileClasspath += csiSourceSet.output.classesDirs runtimeClasspath += csiSourceSet.output.classesDirs } @@ -152,7 +152,10 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ // Write the call site instrumenter arguments into a temporary file doFirst { - val programClassPath = getProgramClasspath(project).map { it.toString() } + val programClassPath = extension.configurations.get().flatMap { + it.files + }.map { it.toString() } + val arguments = listOf( extension.srcFolder.get().asFile.toString(), inputProvider.get().asFile.toString(), @@ -172,7 +175,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ // make all sourcesets' class tasks depend on call site generator val sourceSets = getSourceSets(project) - sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME) { + sourceSets.named(MAIN_SOURCE_SET_NAME) { project.tasks.named(classesTaskName) { dependsOn(callSiteGeneratorTask) } @@ -185,19 +188,4 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } } } - - private fun getProgramClasspath(project: Project): List { - val classpath = ArrayList() - // 1. Compilation outputs - exclude latestDep and forked test variants - project.tasks.withType() - .filter { task -> !task.name.contains("LatestDep", ignoreCase = true) && !task.name.contains("Forked", ignoreCase = true) } - .map { it.destinationDirectory.asFile.get() } - .forEach(classpath::add) - // 2. Compile time dependencies - exclude latestDep and forked test variants - project.tasks.withType() - .filter { task -> !task.name.contains("LatestDep", ignoreCase = true) && !task.name.contains("Forked", ignoreCase = true) } - .flatMap { it.classpath } - .forEach(classpath::add) - return classpath - } } From aa35af4752cbad1ef6c256d04274afe6519328af Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Fri, 14 Nov 2025 15:59:11 +0100 Subject: [PATCH 04/20] chore: arg name rename --- .../csi/CallSiteInstrumentationPlugin.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index ae162fdf840..31119f7218f 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -48,8 +48,8 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ compileClasspath += mainSourceSet.output // mainly needed for the plugin tests annotationProcessorPath += mainSourceSet.annotationProcessorPath java.srcDir(targetFolder) - } + project.configurations.named(csiSourceSet.compileClasspathConfigurationName) { extendsFrom(project.configurations.named(mainSourceSet.compileClasspathConfigurationName).get()) } @@ -119,10 +119,10 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } private fun registerGenerateCallSiteTask(project: Project, - extension: CallSiteInstrumentationExtension, + csiExtension: CallSiteInstrumentationExtension, compileTaskName: String) { val taskName = compileTaskName.replace("compile", "generateCallSite") - val rootFolder = extension.rootFolder.getOrElse(project.rootDir) + val rootFolder = csiExtension.rootFolder.getOrElse(project.rootDir) val pluginJarFile = Paths.get( rootFolder.toString(), "buildSrc", @@ -137,31 +137,31 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ group = "call site instrumentation" description = "Generates call sites from $compileTaskName" // Task input & output - val output = extension.targetFolder + val output = csiExtension.targetFolder val inputProvider = compileTask.map { it.destinationDirectory.get() } inputs.dir(inputProvider) outputs.dir(output) // JavaExec configuration - if (extension.javaVersion.isPresent) { - configureLanguage(this, extension.javaVersion.get()) + if (csiExtension.javaVersion.isPresent) { + configureLanguage(this, csiExtension.javaVersion.get()) } - jvmArgumentProviders.add({ extension.jvmArgs.get() }) + jvmArgumentProviders.add({ csiExtension.jvmArgs.get() }) classpath(pluginJarFile) mainClass.set(CALL_SITE_INSTRUMENTER_MAIN_CLASS) // Write the call site instrumenter arguments into a temporary file doFirst { - val programClassPath = extension.configurations.get().flatMap { + val programClassPath = csiExtension.configurations.get().flatMap { it.files }.map { it.toString() } val arguments = listOf( - extension.srcFolder.get().asFile.toString(), + csiExtension.srcFolder.get().asFile.toString(), inputProvider.get().asFile.toString(), output.get().asFile.toString(), - extension.suffix.get(), - extension.reporters.get().joinToString(",") + csiExtension.suffix.get(), + csiExtension.reporters.get().joinToString(",") ) + programClassPath val argumentFile = newTempFile(temporaryDir, "call-site-arguments") From d472a9ef6de78b6d1d3112fd57170e9418243ed3 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Sun, 16 Nov 2025 14:21:08 +0100 Subject: [PATCH 05/20] fix: Include the main source set output --- .../csi/CallSiteInstrumentationExtension.kt | 30 ++++++++++++++++--- .../csi/CallSiteInstrumentationPlugin.kt | 18 ++++++----- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 2b2cd53baea..d70a54f4637 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -5,7 +5,6 @@ import org.gradle.api.artifacts.Configuration import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory -import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.provider.ListProperty @@ -16,6 +15,7 @@ import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.kotlin.dsl.listProperty import org.gradle.kotlin.dsl.property import java.io.File +import java.util.Locale import javax.inject.Inject @@ -83,13 +83,35 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( * By default, includes all `main*` source sets, but only the `test` * (as wee don't want other test configurations by default). */ - val configurations = objectFactory.listProperty().convention( + val configurations: ListProperty = objectFactory.listProperty().convention( project.provider { project.configurations.matching { // Includes all main* source sets, but only the test (as wee don;t want other ) - (it.name.startsWith(MAIN_SOURCE_SET_NAME) || it.name == TEST_SOURCE_SET_NAME) - && (it.name.endsWith(RUNTIME_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true) || it.name.endsWith(COMPILE_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true)) + // * For main => runtimeClasspath, compileClasspath + // * For test => testRuntimeClasspath, testCompileClasspath + // * For other main* => "main_javaXXRuntimeClasspath", "main_javaXXCompileClasspath" + + when (it.name) { + // Regular main and test source sets + RUNTIME_CLASSPATH_CONFIGURATION_NAME, + COMPILE_CLASSPATH_CONFIGURATION_NAME, + TEST_SOURCE_SET_NAME + RUNTIME_CLASSPATH_CONFIGURATION_NAME.capitalize(), + TEST_SOURCE_SET_NAME + COMPILE_CLASSPATH_CONFIGURATION_NAME.capitalize() -> true + + // Other main_javaXX source sets + else -> { + it.name.startsWith(MAIN_SOURCE_SET_NAME) && + (it.name.endsWith(RUNTIME_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true) || + it.name.endsWith(COMPILE_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true)) + } + } } } ) + + private fun String.capitalize(): String = replaceFirstChar { + if (it.isLowerCase()) it.titlecase( + Locale.getDefault() + ) else it.toString() + } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 31119f7218f..34264416801 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -42,7 +42,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ private fun configureSourceSets(project: Project, extension: CallSiteInstrumentationExtension) { // create a new source set for the csi files val targetFolder = newBuildFolder(project, extension.targetFolder.get().asFile.toString()) - val sourceSets = getSourceSets(project) + val sourceSets = project.sourceSets val mainSourceSet = sourceSets.named(MAIN_SOURCE_SET_NAME).get() val csiSourceSet = sourceSets.create("csi") { compileClasspath += mainSourceSet.output // mainly needed for the plugin tests @@ -91,10 +91,6 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ return file } - private fun getSourceSets(project: Project): SourceSetContainer { - return project.extensions.getByType().sourceSets - } - private fun createTasks(project: Project, extension: CallSiteInstrumentationExtension) { registerGenerateCallSiteTask(project, extension, "compileJava") val targetFolder = extension.targetFolder.get().asFile @@ -152,9 +148,12 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ // Write the call site instrumenter arguments into a temporary file doFirst { + val sourceSetOutput = project.sourceSets.matching { it.name.startsWith(MAIN_SOURCE_SET_NAME) }.flatMap { + it.output.classesDirs.files + } val programClassPath = csiExtension.configurations.get().flatMap { it.files - }.map { it.toString() } + } val arguments = listOf( csiExtension.srcFolder.get().asFile.toString(), @@ -162,7 +161,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ output.get().asFile.toString(), csiExtension.suffix.get(), csiExtension.reporters.get().joinToString(",") - ) + programClassPath + ) + (sourceSetOutput + programClassPath).map { it.toString() } val argumentFile = newTempFile(temporaryDir, "call-site-arguments") Files.write(argumentFile.toPath(), arguments) @@ -174,7 +173,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } // make all sourcesets' class tasks depend on call site generator - val sourceSets = getSourceSets(project) + val sourceSets = project.sourceSets sourceSets.named(MAIN_SOURCE_SET_NAME) { project.tasks.named(classesTaskName) { dependsOn(callSiteGeneratorTask) @@ -188,4 +187,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } } } + + private val Project.sourceSets: SourceSetContainer + get() = project.extensions.getByType().sourceSets } From e1ec9b5072bca91474a71f36fb49bae788f27040 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 10:12:24 +0100 Subject: [PATCH 06/20] fix: Always make sure java plugin is applied --- .../gradle/plugin/csi/CallSiteInstrumentationPlugin.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 34264416801..41b52b2ad8e 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -4,6 +4,7 @@ import org.gradle.api.GradleException import org.gradle.api.JavaVersion import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME @@ -14,6 +15,7 @@ import org.gradle.api.tasks.testing.Test import org.gradle.jvm.tasks.Jar import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaToolchainService +import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.create import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.named @@ -31,6 +33,8 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ abstract val javaToolchains: JavaToolchainService override fun apply(project: Project) { + project.pluginManager.apply(JavaPlugin::class) + // Create plugin extension val extension = project.extensions.create("csi") project.afterEvaluate { From f11ea1768561a6e63ca96729e31b1e27b33c173e Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 15:54:27 +0100 Subject: [PATCH 07/20] chore: Make csi plugin not running in project.afterEvaluate --- .../csi/CallSiteInstrumentationExtension.kt | 8 +- .../csi/CallSiteInstrumentationPlugin.kt | 73 +++++++++++-------- 2 files changed, 44 insertions(+), 37 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index d70a54f4637..8f7b4cce3ce 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -9,7 +9,6 @@ import org.gradle.api.plugins.JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property -import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.kotlin.dsl.listProperty @@ -98,12 +97,7 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( TEST_SOURCE_SET_NAME + RUNTIME_CLASSPATH_CONFIGURATION_NAME.capitalize(), TEST_SOURCE_SET_NAME + COMPILE_CLASSPATH_CONFIGURATION_NAME.capitalize() -> true - // Other main_javaXX source sets - else -> { - it.name.startsWith(MAIN_SOURCE_SET_NAME) && - (it.name.endsWith(RUNTIME_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true) || - it.name.endsWith(COMPILE_CLASSPATH_CONFIGURATION_NAME, ignoreCase = true)) - } + else -> false } } } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 41b52b2ad8e..ede2bf1323b 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -10,6 +10,7 @@ import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.testing.Test import org.gradle.jvm.tasks.Jar @@ -27,6 +28,8 @@ import java.nio.file.Paths import javax.inject.Inject private const val CALL_SITE_INSTRUMENTER_MAIN_CLASS = "datadog.trace.plugin.csi.PluginApplication" +private const val CSI = "csi" +private const val CSI_SOURCE_SET = CSI abstract class CallSiteInstrumentationPlugin : Plugin{ @get:Inject @@ -36,11 +39,9 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ project.pluginManager.apply(JavaPlugin::class) // Create plugin extension - val extension = project.extensions.create("csi") - project.afterEvaluate { - configureSourceSets(project, extension) - createTasks(project, extension) - } + val extension = project.extensions.create(CSI) + configureSourceSets(project, extension) + createTasks(project, extension) } private fun configureSourceSets(project: Project, extension: CallSiteInstrumentationExtension) { @@ -48,7 +49,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ val targetFolder = newBuildFolder(project, extension.targetFolder.get().asFile.toString()) val sourceSets = project.sourceSets val mainSourceSet = sourceSets.named(MAIN_SOURCE_SET_NAME).get() - val csiSourceSet = sourceSets.create("csi") { + val csiSourceSet = sourceSets.create(CSI_SOURCE_SET) { compileClasspath += mainSourceSet.output // mainly needed for the plugin tests annotationProcessorPath += mainSourceSet.annotationProcessorPath java.srcDir(targetFolder) @@ -96,9 +97,9 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } private fun createTasks(project: Project, extension: CallSiteInstrumentationExtension) { - registerGenerateCallSiteTask(project, extension, "compileJava") - val targetFolder = extension.targetFolder.get().asFile + registerGenerateCallSiteTask(project, extension, project.tasks.named("compileJava")) + val targetFolder = extension.targetFolder.get().asFile project.tasks.withType().matching { task -> task.name.startsWith("compileTest") }.configureEach { @@ -120,25 +121,28 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ private fun registerGenerateCallSiteTask(project: Project, csiExtension: CallSiteInstrumentationExtension, - compileTaskName: String) { - val taskName = compileTaskName.replace("compile", "generateCallSite") - val rootFolder = csiExtension.rootFolder.getOrElse(project.rootDir) + mainCompileTask: TaskProvider) { + val genTaskName = mainCompileTask.name.replace("compile", "generateCallSite") val pluginJarFile = Paths.get( - rootFolder.toString(), + csiExtension.rootFolder.getOrElse(project.rootDir).toString(), "buildSrc", "call-site-instrumentation-plugin", "build", "libs", "call-site-instrumentation-plugin-all.jar" ).toFile() - val compileTask = project.tasks.named(compileTaskName) - val callSiteGeneratorTask = project.tasks.register(taskName) { + + val callSiteGeneratorTask = project.tasks.register(genTaskName) { // Task description group = "call site instrumentation" - description = "Generates call sites from $compileTaskName" + description = "Generates call sites from ${mainCompileTask.name}" + + // Remote Debug + // jvmArgs("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005") + // Task input & output val output = csiExtension.targetFolder - val inputProvider = compileTask.map { it.destinationDirectory.get() } + val inputProvider = mainCompileTask.flatMap { it.destinationDirectory } inputs.dir(inputProvider) outputs.dir(output) @@ -152,20 +156,29 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ // Write the call site instrumenter arguments into a temporary file doFirst { - val sourceSetOutput = project.sourceSets.matching { it.name.startsWith(MAIN_SOURCE_SET_NAME) }.flatMap { - it.output.classesDirs.files - } - val programClassPath = csiExtension.configurations.get().flatMap { - it.files + val callsitesClassPath = project.objects.fileCollection() + .from( + project.sourceSets.named(MAIN_SOURCE_SET_NAME).map { it.output }, + csiExtension.configurations + ) + + if (project.logger.isInfoEnabled) { + project.logger.info( + "Aggregated CSI classpath:\n{}", + callsitesClassPath.toSet().sorted().joinToString("\n") { it.toString() } + ) } - val arguments = listOf( - csiExtension.srcFolder.get().asFile.toString(), - inputProvider.get().asFile.toString(), - output.get().asFile.toString(), - csiExtension.suffix.get(), - csiExtension.reporters.get().joinToString(",") - ) + (sourceSetOutput + programClassPath).map { it.toString() } + val arguments = buildList { + add(csiExtension.srcFolder.get().asFile.toString()) + add(inputProvider.get().asFile.toString()) + add(output.get().asFile.toString()) + add(csiExtension.suffix.get()) + add(csiExtension.reporters.get().joinToString(",")) + + // module program classpath + addAll(callsitesClassPath.map { it.toString() }) + } val argumentFile = newTempFile(temporaryDir, "call-site-arguments") Files.write(argumentFile.toPath(), arguments) @@ -173,7 +186,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } // make task depends on compile - dependsOn(compileTask) + dependsOn(mainCompileTask) } // make all sourcesets' class tasks depend on call site generator @@ -185,7 +198,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } // compile generated sources - sourceSets.named("csi") { + sourceSets.named(CSI_SOURCE_SET) { project.tasks.named(compileJavaTaskName) { dependsOn(callSiteGeneratorTask) } From b0b8121524c2d23fcbed70eddacd64129194eb4a Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 15:54:56 +0100 Subject: [PATCH 08/20] fix: Incorrect URLClassLoader initialization when url is a directory --- .../datadog/trace/plugin/csi/util/CallSiteUtils.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java b/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java index 5f2e2fa8d75..11e12823541 100644 --- a/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java +++ b/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java @@ -47,7 +47,16 @@ public static String repeat(final char value, int count) { public static URL toURL(final Path path) { try { - return path.toUri().toURL(); + URL url = path.toUri().toURL(); + // There's a subtle detail where `URLClassLoader` requires directory URLs to end with '/', + // otherwise they are assimilated to jar file, and vice versa. + if (path.toFile().isDirectory() || !path.toString().endsWith(".jar")) { + String urlString = url.toString(); + if (!urlString.endsWith("/")) { + url = new URL(urlString + "/"); + } + } + return url; } catch (MalformedURLException e) { throw new RuntimeException(e); } From 79c95265c29bd4762c5f3fd1ba49fb475e8ece34 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 15:57:58 +0100 Subject: [PATCH 09/20] fix: Make depends on instrument task The 'instrument' plugin changes destination around for now, it needs to be depended on for the time being. --- .../gradle/plugin/csi/CallSiteInstrumentationPlugin.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index ede2bf1323b..3ed56d4ad91 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -187,6 +187,10 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ // make task depends on compile dependsOn(mainCompileTask) + // Workaround for instrument plugin modifying compile tasks + if (project.pluginManager.hasPlugin("instrument")) { + dependsOn("instrumentJava") + } } // make all sourcesets' class tasks depend on call site generator From 6a373c9a0cf2ccf5935d9577cdfa88821a3c2336 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 16:18:37 +0100 Subject: [PATCH 10/20] chore: Refactor additional configurations to a `ConfigurableFileCollection` --- .../csi/CallSiteInstrumentationExtension.kt | 40 ++++--------------- .../csi/CallSiteInstrumentationPlugin.kt | 32 ++++++++++++++- .../instrumentation/scala/build.gradle | 4 ++ 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 8f7b4cce3ce..022fd051472 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -2,19 +2,16 @@ package datadog.gradle.plugin.csi import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory -import org.gradle.api.plugins.JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME -import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property -import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.kotlin.dsl.listProperty import org.gradle.kotlin.dsl.property import java.io.File -import java.util.Locale import javax.inject.Inject @@ -77,35 +74,12 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( objectFactory.listProperty().convention(listOf("-Xmx128m", "-Xms64m")) /** - * The configurations to use to look for the call site instrumenter dependencies. + * The paths used to look for the call site instrumenter dependencies. * - * By default, includes all `main*` source sets, but only the `test` - * (as wee don't want other test configurations by default). + * The plugin includes by default **only** the `main` and `test` source sets, and their + * related compilation classpath. As we don't want other test configurations by default. + * + * However, it's possible to contribute additional paths to look for dependencies. */ - val configurations: ListProperty = objectFactory.listProperty().convention( - project.provider { - project.configurations.matching { - // Includes all main* source sets, but only the test (as wee don;t want other ) - // * For main => runtimeClasspath, compileClasspath - // * For test => testRuntimeClasspath, testCompileClasspath - // * For other main* => "main_javaXXRuntimeClasspath", "main_javaXXCompileClasspath" - - when (it.name) { - // Regular main and test source sets - RUNTIME_CLASSPATH_CONFIGURATION_NAME, - COMPILE_CLASSPATH_CONFIGURATION_NAME, - TEST_SOURCE_SET_NAME + RUNTIME_CLASSPATH_CONFIGURATION_NAME.capitalize(), - TEST_SOURCE_SET_NAME + COMPILE_CLASSPATH_CONFIGURATION_NAME.capitalize() -> true - - else -> false - } - } - } - ) - - private fun String.capitalize(): String = replaceFirstChar { - if (it.isLowerCase()) it.titlecase( - Locale.getDefault() - ) else it.toString() - } + val additionalPaths: ConfigurableFileCollection = objectFactory.fileCollection() } diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 3ed56d4ad91..da24c8f7a5e 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -2,9 +2,13 @@ package datadog.gradle.plugin.csi import org.gradle.api.GradleException import org.gradle.api.JavaVersion +import org.gradle.api.NamedDomainObjectSet import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration import org.gradle.api.plugins.JavaPlugin +import org.gradle.api.plugins.JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME +import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME @@ -25,6 +29,7 @@ import org.gradle.kotlin.dsl.withType import java.io.File import java.nio.file.Files import java.nio.file.Paths +import java.util.Locale import javax.inject.Inject private const val CALL_SITE_INSTRUMENTER_MAIN_CLASS = "datadog.trace.plugin.csi.PluginApplication" @@ -159,7 +164,8 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ val callsitesClassPath = project.objects.fileCollection() .from( project.sourceSets.named(MAIN_SOURCE_SET_NAME).map { it.output }, - csiExtension.configurations + project.defaultConfigurations, + csiExtension.additionalPaths ) if (project.logger.isInfoEnabled) { @@ -209,6 +215,30 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ } } + private val Project.defaultConfigurations: NamedDomainObjectSet + get() = project.configurations.matching { + // Includes all main* source sets, but only the test (as wee don;t want other ) + // * For main => runtimeClasspath, compileClasspath + // * For test => testRuntimeClasspath, testCompileClasspath + // * For other main* => "main_javaXXRuntimeClasspath", "main_javaXXCompileClasspath" + + when (it.name) { + // Regular main and test source sets + RUNTIME_CLASSPATH_CONFIGURATION_NAME, + COMPILE_CLASSPATH_CONFIGURATION_NAME, + TEST_SOURCE_SET_NAME + RUNTIME_CLASSPATH_CONFIGURATION_NAME.capitalize(), + TEST_SOURCE_SET_NAME + COMPILE_CLASSPATH_CONFIGURATION_NAME.capitalize() -> true + + else -> false + } + } + + private fun String.capitalize(): String = replaceFirstChar { + if (it.isLowerCase()) it.titlecase( + Locale.getDefault() + ) else it.toString() + } + private val Project.sourceSets: SourceSetContainer get() = project.extensions.getByType().sourceSets } diff --git a/dd-java-agent/instrumentation/scala/build.gradle b/dd-java-agent/instrumentation/scala/build.gradle index f2f65b6e316..9d34895f960 100644 --- a/dd-java-agent/instrumentation/scala/build.gradle +++ b/dd-java-agent/instrumentation/scala/build.gradle @@ -63,6 +63,10 @@ final testTasks = scalaVersions.collect { scalaLibrary -> } } + csi { + additionalPaths.from(classPathConfiguration) + } + return tasks.register("test$version", Test) { classpath = classpath .filter { !it.toString().contains('scala-library') } // exclude default scala-library From 9bddc7fc810a9fa059e22131585b74b43f3748e2 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 17:53:36 +0100 Subject: [PATCH 11/20] fix: extension property should not be queried at configuration time --- .../csi/CallSiteInstrumentationExtension.kt | 3 ++- .../plugin/csi/CallSiteInstrumentationPlugin.kt | 15 +++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 022fd051472..23607767732 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -65,7 +65,8 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( /** * The JVM to use to run the call site instrumenter (optional, default JVM used if not set). */ - abstract val javaVersion: Property + val javaVersion: Property = + objectFactory.property().convention(JavaLanguageVersion.current()) /** * The JVM arguments to run the call site instrumenter. diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index da24c8f7a5e..602ba106721 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -143,7 +143,9 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ description = "Generates call sites from ${mainCompileTask.name}" // Remote Debug - // jvmArgs("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005") + if (project.providers.gradleProperty("debugCsiJar").isPresent) { + jvmArgs("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=localhost:5005") + } // Task input & output val output = csiExtension.targetFolder @@ -152,9 +154,10 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ outputs.dir(output) // JavaExec configuration - if (csiExtension.javaVersion.isPresent) { - configureLanguage(this, csiExtension.javaVersion.get()) - } + javaLauncher.set(javaToolchains.launcherFor { + languageVersion.set(csiExtension.javaVersion) + }) + jvmArgumentProviders.add({ csiExtension.jvmArgs.get() }) classpath(pluginJarFile) mainClass.set(CALL_SITE_INSTRUMENTER_MAIN_CLASS) @@ -168,8 +171,8 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ csiExtension.additionalPaths ) - if (project.logger.isInfoEnabled) { - project.logger.info( + if (logger.isInfoEnabled) { + logger.info( "Aggregated CSI classpath:\n{}", callsitesClassPath.toSet().sorted().joinToString("\n") { it.toString() } ) From 207d8494210c6d86747f856520b87ea99d6f7c6d Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Mon, 17 Nov 2025 17:55:48 +0100 Subject: [PATCH 12/20] style: Reformat --- .../csi/CallSiteInstrumentationPlugin.kt | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 602ba106721..55ba7d60403 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -18,7 +18,6 @@ import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.testing.Test import org.gradle.jvm.tasks.Jar -import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.create @@ -36,13 +35,13 @@ private const val CALL_SITE_INSTRUMENTER_MAIN_CLASS = "datadog.trace.plugin.csi. private const val CSI = "csi" private const val CSI_SOURCE_SET = CSI -abstract class CallSiteInstrumentationPlugin : Plugin{ +abstract class CallSiteInstrumentationPlugin : Plugin { @get:Inject abstract val javaToolchains: JavaToolchainService override fun apply(project: Project) { project.pluginManager.apply(JavaPlugin::class) - + // Create plugin extension val extension = project.extensions.create(CSI) configureSourceSets(project, extension) @@ -101,32 +100,27 @@ abstract class CallSiteInstrumentationPlugin : Plugin{ return file } - private fun createTasks(project: Project, extension: CallSiteInstrumentationExtension) { - registerGenerateCallSiteTask(project, extension, project.tasks.named("compileJava")) + private fun createTasks(project: Project, csiExtension: CallSiteInstrumentationExtension) { + registerGenerateCallSiteTask(project, csiExtension, project.tasks.named("compileJava")) - val targetFolder = extension.targetFolder.get().asFile - project.tasks.withType().matching { - task -> task.name.startsWith("compileTest") + project.tasks.withType().matching { task -> + task.name.startsWith("compileTest") }.configureEach { - inputs.dir(extension.targetFolder) - classpath += project.files(targetFolder) + inputs.dir(csiExtension.targetFolder) + classpath += project.files(csiExtension.targetFolder) } project.tasks.withType().configureEach { - inputs.dir(extension.targetFolder) - classpath += project.files(targetFolder) + inputs.dir(csiExtension.targetFolder) + classpath += project.files(csiExtension.targetFolder) } } - private fun configureLanguage(task: JavaExec, version: JavaLanguageVersion) { - task.javaLauncher.set(javaToolchains.launcherFor { - languageVersion.set(version) - }) - } - - private fun registerGenerateCallSiteTask(project: Project, - csiExtension: CallSiteInstrumentationExtension, - mainCompileTask: TaskProvider) { + private fun registerGenerateCallSiteTask( + project: Project, + csiExtension: CallSiteInstrumentationExtension, + mainCompileTask: TaskProvider + ) { val genTaskName = mainCompileTask.name.replace("compile", "generateCallSite") val pluginJarFile = Paths.get( csiExtension.rootFolder.getOrElse(project.rootDir).toString(), From eda1af348901ec40b9d89551a404f4d9d9a977dc Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 19 Nov 2025 12:13:20 +0100 Subject: [PATCH 13/20] fix: call site plugin still has to add entries to classpath after jvm test suite ran --- .../plugin/csi/CallSiteInstrumentationPlugin.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 55ba7d60403..1703c4c6fe8 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -110,9 +110,14 @@ abstract class CallSiteInstrumentationPlugin : Plugin { classpath += project.files(csiExtension.targetFolder) } - project.tasks.withType().configureEach { - inputs.dir(csiExtension.targetFolder) - classpath += project.files(csiExtension.targetFolder) + // This afterEvaluate appear to be needed to ensure the good class classpath + // is appended, otherwise when the configureEach is applied when the plugin is applied, + // it will run before the JVM test suite plugins run and won't capture the correct classpath. + project.afterEvaluate { + project.tasks.withType().configureEach { + inputs.dir(csiExtension.targetFolder) + classpath += project.files(csiExtension.targetFolder) + } } } From c189714d1c9930ef37ae80ca30c53044b64946b7 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 19 Nov 2025 15:16:49 +0100 Subject: [PATCH 14/20] chore: code tweaks --- .../csi/CallSiteInstrumentationPlugin.kt | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 1703c4c6fe8..904d616d3a3 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -134,7 +134,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin { "build", "libs", "call-site-instrumentation-plugin-all.jar" - ).toFile() + ) val callSiteGeneratorTask = project.tasks.register(genTaskName) { // Task description @@ -163,12 +163,11 @@ abstract class CallSiteInstrumentationPlugin : Plugin { // Write the call site instrumenter arguments into a temporary file doFirst { - val callsitesClassPath = project.objects.fileCollection() - .from( - project.sourceSets.named(MAIN_SOURCE_SET_NAME).map { it.output }, - project.defaultConfigurations, - csiExtension.additionalPaths - ) + val callsitesClassPath = project.files( + project.sourceSets.named(MAIN_SOURCE_SET_NAME).map { it.output }, + project.defaultConfigurations, + csiExtension.additionalPaths, + ) if (logger.isInfoEnabled) { logger.info( @@ -177,7 +176,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin { ) } - val arguments = buildList { + val argFile = buildList { add(csiExtension.srcFolder.get().asFile.toString()) add(inputProvider.get().asFile.toString()) add(output.get().asFile.toString()) @@ -189,14 +188,17 @@ abstract class CallSiteInstrumentationPlugin : Plugin { } val argumentFile = newTempFile(temporaryDir, "call-site-arguments") - Files.write(argumentFile.toPath(), arguments) + Files.write(argumentFile.toPath(), argFile) args(argumentFile.toString()) } // make task depends on compile dependsOn(mainCompileTask) - // Workaround for instrument plugin modifying compile tasks - if (project.pluginManager.hasPlugin("instrument")) { + } + + // Workaround for instrument plugin modifying compile tasks + project.pluginManager.withPlugin("instrument") { + callSiteGeneratorTask.configure { dependsOn("instrumentJava") } } From f2f5205f1f864db88d20f7443662400313804d38 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 19 Nov 2025 15:18:51 +0100 Subject: [PATCH 15/20] fix: generateCallSite was missing a few input properties for up-date checks --- .../gradle/plugin/csi/CallSiteInstrumentationPlugin.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 904d616d3a3..a1de354ea71 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -150,6 +150,13 @@ abstract class CallSiteInstrumentationPlugin : Plugin { val output = csiExtension.targetFolder val inputProvider = mainCompileTask.flatMap { it.destinationDirectory } inputs.dir(inputProvider) + inputs.dir(csiExtension.srcFolder) + inputs.dir(csiExtension.rootFolder).optional() + inputs.file(pluginJarFile) + inputs.property("cis.suffix", csiExtension.suffix) + inputs.property("csi.javaVersion", csiExtension.javaVersion) + inputs.property("csi.jvmArgs", csiExtension.jvmArgs) + inputs.property("csi.reporters", csiExtension.reporters) outputs.dir(output) // JavaExec configuration From 3aebe10b14bd385111ab0a9e9de990af8df68429 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 19 Nov 2025 17:04:05 +0100 Subject: [PATCH 16/20] fix: csi plugin was patching test compile and test task classpath This forced to apply patching in afterEvaluate, instead, it's easier and cleaner to add the csi output as dependency in the appropriate configuration. --- .../csi/CallSiteInstrumentationPlugin.kt | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index a1de354ea71..4bbdd6e8646 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -10,13 +10,13 @@ import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.plugins.jvm.JvmTestSuite import org.gradle.api.tasks.JavaExec import org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.AbstractCompile -import org.gradle.api.tasks.testing.Test import org.gradle.jvm.tasks.Jar import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.apply @@ -25,6 +25,7 @@ import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.named import org.gradle.kotlin.dsl.register import org.gradle.kotlin.dsl.withType +import org.gradle.testing.base.TestingExtension import java.io.File import java.nio.file.Files import java.nio.file.Paths @@ -43,9 +44,10 @@ abstract class CallSiteInstrumentationPlugin : Plugin { project.pluginManager.apply(JavaPlugin::class) // Create plugin extension - val extension = project.extensions.create(CSI) - configureSourceSets(project, extension) - createTasks(project, extension) + val csiExtension = project.extensions.create(CSI) + configureSourceSets(project, csiExtension) + registerGenerateCallSiteTask(project, csiExtension, project.tasks.named("compileJava")) + configureTestConfigurations(project, csiExtension) } private fun configureSourceSets(project: Project, extension: CallSiteInstrumentationExtension) { @@ -100,23 +102,14 @@ abstract class CallSiteInstrumentationPlugin : Plugin { return file } - private fun createTasks(project: Project, csiExtension: CallSiteInstrumentationExtension) { - registerGenerateCallSiteTask(project, csiExtension, project.tasks.named("compileJava")) - - project.tasks.withType().matching { task -> - task.name.startsWith("compileTest") - }.configureEach { - inputs.dir(csiExtension.targetFolder) - classpath += project.files(csiExtension.targetFolder) - } - - // This afterEvaluate appear to be needed to ensure the good class classpath - // is appended, otherwise when the configureEach is applied when the plugin is applied, - // it will run before the JVM test suite plugins run and won't capture the correct classpath. - project.afterEvaluate { - project.tasks.withType().configureEach { - inputs.dir(csiExtension.targetFolder) - classpath += project.files(csiExtension.targetFolder) + private fun configureTestConfigurations(project: Project, csiExtension: CallSiteInstrumentationExtension) { + project.pluginManager.withPlugin("jvm-test-suite") { + project.extensions.getByType().suites.withType().configureEach { + project.logger.info("Configuring jvm test suite '{}' to use csiExtension.targetFolder", name) + dependencies { + compileOnly.add(project.files(csiExtension.targetFolder)) + runtimeOnly.add(project.files(csiExtension.targetFolder)) + } } } } From b5ef0ba4dcf0792f185cb98e31d3f14393e0c2fd Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 19 Nov 2025 17:11:40 +0100 Subject: [PATCH 17/20] fix: unnecessary targetFolder directory creation and unnecessary transformation to string --- .../csi/CallSiteInstrumentationExtension.kt | 2 +- .../csi/CallSiteInstrumentationPlugin.kt | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 23607767732..80bd1951aa1 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -40,7 +40,7 @@ abstract class CallSiteInstrumentationExtension @Inject constructor( * The location to generate call site source code ({@code /build/generated/sources/csi} by default). */ val targetFolder: DirectoryProperty = objectFactory.directoryProperty().convention( - layout.buildDirectory.dir("generated${File.separatorChar}sources${File.separatorChar}csi") + layout.buildDirectory.dir("generated/sources/$CSI_SOURCE_SET") ) /** diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 4bbdd6e8646..3fca0ce41e0 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -17,6 +17,7 @@ import org.gradle.api.tasks.SourceSet.TEST_SOURCE_SET_NAME import org.gradle.api.tasks.SourceSetContainer import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.compile.AbstractCompile +import org.gradle.internal.configuration.problems.projectPathFrom import org.gradle.jvm.tasks.Jar import org.gradle.jvm.toolchain.JavaToolchainService import org.gradle.kotlin.dsl.apply @@ -33,8 +34,8 @@ import java.util.Locale import javax.inject.Inject private const val CALL_SITE_INSTRUMENTER_MAIN_CLASS = "datadog.trace.plugin.csi.PluginApplication" -private const val CSI = "csi" -private const val CSI_SOURCE_SET = CSI +const val CSI = "csi" +const val CSI_SOURCE_SET = CSI abstract class CallSiteInstrumentationPlugin : Plugin { @get:Inject @@ -52,13 +53,12 @@ abstract class CallSiteInstrumentationPlugin : Plugin { private fun configureSourceSets(project: Project, extension: CallSiteInstrumentationExtension) { // create a new source set for the csi files - val targetFolder = newBuildFolder(project, extension.targetFolder.get().asFile.toString()) val sourceSets = project.sourceSets val mainSourceSet = sourceSets.named(MAIN_SOURCE_SET_NAME).get() val csiSourceSet = sourceSets.create(CSI_SOURCE_SET) { compileClasspath += mainSourceSet.output // mainly needed for the plugin tests annotationProcessorPath += mainSourceSet.annotationProcessorPath - java.srcDir(targetFolder) + java.srcDir(extension.targetFolder) } project.configurations.named(csiSourceSet.compileClasspathConfigurationName) { @@ -83,16 +83,6 @@ abstract class CallSiteInstrumentationPlugin : Plugin { } } - private fun newBuildFolder(project: Project, name: String): File { - val folder = project.layout.buildDirectory.dir(name).get().asFile - if (!folder.exists()) { - if (!folder.mkdirs()) { - throw GradleException("Cannot create folder $folder") - } - } - return folder - } - private fun newTempFile(folder: File, name: String): File { val file = File(folder, name) if (!file.exists() && !file.createNewFile()) { From dea2a7c0f8853d57812ce43ed4c29e3eb83aadb6 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 19 Nov 2025 17:16:31 +0100 Subject: [PATCH 18/20] chore: Readability of CallSiteUtils::toURL --- .../kotlin-compiler-1497087473482789025.salive | 0 .../datadog/trace/plugin/csi/util/CallSiteUtils.java | 11 ++++++++--- .../plugin/csi/CallSiteInstrumentationExtension.kt | 3 --- 3 files changed, 8 insertions(+), 6 deletions(-) create mode 100644 buildSrc/.kotlin/sessions/kotlin-compiler-1497087473482789025.salive diff --git a/buildSrc/.kotlin/sessions/kotlin-compiler-1497087473482789025.salive b/buildSrc/.kotlin/sessions/kotlin-compiler-1497087473482789025.salive new file mode 100644 index 00000000000..e69de29bb2d diff --git a/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java b/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java index 11e12823541..1f9ecdc5aad 100644 --- a/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java +++ b/buildSrc/call-site-instrumentation-plugin/src/main/java/datadog/trace/plugin/csi/util/CallSiteUtils.java @@ -3,6 +3,7 @@ import java.io.File; import java.net.MalformedURLException; import java.net.URL; +import java.nio.file.Files; import java.nio.file.Path; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -48,9 +49,13 @@ public static String repeat(final char value, int count) { public static URL toURL(final Path path) { try { URL url = path.toUri().toURL(); - // There's a subtle detail where `URLClassLoader` requires directory URLs to end with '/', - // otherwise they are assimilated to jar file, and vice versa. - if (path.toFile().isDirectory() || !path.toString().endsWith(".jar")) { + // URLClassLoader interprets URLs ending with '/' as directories. If the trailing '/' is + // missing, a directory URL is treated as a JAR. If the path does yet exist on disk + // assumes that paths not ending with ".jar" are directories. + boolean shouldAddSlash = + Files.exists(path) ? Files.isDirectory(path) : !path.toString().endsWith(".jar"); + + if (shouldAddSlash) { String urlString = url.toString(); if (!urlString.endsWith("/")) { url = new URL(urlString + "/"); diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt index 80bd1951aa1..989e31caf86 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationExtension.kt @@ -1,7 +1,5 @@ package datadog.gradle.plugin.csi -import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.ProjectLayout @@ -19,7 +17,6 @@ import javax.inject.Inject * This extension allows to configure the Call Site Instrumenter plugin execution. */ abstract class CallSiteInstrumentationExtension @Inject constructor( - project: Project, objectFactory: ObjectFactory, layout: ProjectLayout ) { From 5c32a8c7ee1661bbd99b2d61cb262960585f552e Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 20 Nov 2025 20:55:15 +0100 Subject: [PATCH 19/20] typo: inout property type --- .../datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt index 3fca0ce41e0..b9bfafa2596 100644 --- a/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt +++ b/buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt @@ -136,7 +136,7 @@ abstract class CallSiteInstrumentationPlugin : Plugin { inputs.dir(csiExtension.srcFolder) inputs.dir(csiExtension.rootFolder).optional() inputs.file(pluginJarFile) - inputs.property("cis.suffix", csiExtension.suffix) + inputs.property("csi.suffix", csiExtension.suffix) inputs.property("csi.javaVersion", csiExtension.javaVersion) inputs.property("csi.jvmArgs", csiExtension.jvmArgs) inputs.property("csi.reporters", csiExtension.reporters) From c84d247d7297703ea57130f6f6481dfd053a2c3e Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Thu, 20 Nov 2025 20:59:47 +0100 Subject: [PATCH 20/20] fix: Exclude Kotlin compiler daemon files --- .gitignore | 3 +++ .../sessions/kotlin-compiler-1497087473482789025.salive | 0 2 files changed, 3 insertions(+) delete mode 100644 buildSrc/.kotlin/sessions/kotlin-compiler-1497087473482789025.salive diff --git a/.gitignore b/.gitignore index c0dcdb32d1b..593d2f3c0f3 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,6 @@ mise*.local.toml .config/mise*.toml # asdf .tool-versions + +# Exclude kotlin build files +.kotlin diff --git a/buildSrc/.kotlin/sessions/kotlin-compiler-1497087473482789025.salive b/buildSrc/.kotlin/sessions/kotlin-compiler-1497087473482789025.salive deleted file mode 100644 index e69de29bb2d..00000000000