Rewrite build-time instrumentation as compilation post-processor (using Gradle lazy APIs)#9475
Rewrite build-time instrumentation as compilation post-processor (using Gradle lazy APIs)#9475
Conversation
|
Hi! 👋 Thanks for your pull request! 🎉 To help us review it, please make sure to:
If you need help, please check our contributing guidelines. |
AlexeyKuznetsov-DD
left a comment
There was a problem hiding this comment.
Just curious, what would be the benefit? Faster build?
248b4eb to
3094d50
Compare
|
Status report The new approach of the instrument post-processing works in almost all simple projects, e.g. Important The diff was made by this custom tool https://github.com/bric3/jardiff
|
aa6d660 to
0067ada
Compare
|
Just a minor comment. Probably it make sense to refactor this plugin to Kotlin. |
0067ada to
210d17c
Compare
d3a2cd2 to
899f804
Compare
The current implementation was using bad practices in various ways, `project.afterEvaluate`, task creation, explicit `dependsOn` # Conflicts: # buildSrc/src/main/groovy/InstrumentPlugin.groovy # buildSrc/src/main/groovy/MuzzlePlugin.groovy # dd-java-agent/instrumentation/jetty-9/build.gradle # Conflicts: # buildSrc/src/main/groovy/InstrumentPlugin.groovy # buildSrc/src/test/groovy/InstrumentPluginTest.groovy # dd-java-agent/instrumentation/play/play-2.4/build.gradle # dd-java-agent/instrumentation/play/play-2.6/build.gradle
…utions to instrument plugin
…and configuration
InstrumentPlugin as compilation post-processor and lazy83aa2a4 to
5311fd3
Compare
AlexeyKuznetsov-DD
left a comment
There was a problem hiding this comment.
LGTM, left minor notes and questions.
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/BuildTimeInstrumentationPlugin.groovy
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/BuildTimeInstrumentationPlugin.groovy
Outdated
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/BuildTimeInstrumentationPlugin.groovy
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/BuildTimeInstrumentationPlugin.groovy
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/ByteBuddyInstrumenter.groovy
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/InstrumentPostProcessingAction.groovy
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/BuildTimeInstrumentationPlugin.groovy
Outdated
Show resolved
Hide resolved
buildSrc/src/main/groovy/datadog/gradle/plugin/instrument/BuildTimeInstrumentationPlugin.groovy
Show resolved
Hide resolved
| it.dependencies.add(subProj.dependencies.project(path: ':dd-java-agent:agent-tooling', configuration: 'instrumentPluginClasspath')) | ||
| it.dependencies.add(subProj.dependencies.project( | ||
| path: ':dd-java-agent:agent-tooling', | ||
| configuration: 'buildTimeInstrumentationPlugin' |
There was a problem hiding this comment.
note: Maybe I'll rename this configuration to avoid confusion with the instrumentation plugin.
Something like
configuration: 'buildTimeInstrumentationPlugin'
configuration: 'buildTimeInstrumentationToolingPlugins'| import org.gradle.api.artifacts.Configuration | ||
| import org.gradle.api.tasks.SourceSetContainer | ||
| import org.gradle.api.tasks.TaskProvider | ||
| import org.gradle.api.tasks.compile.AbstractCompile |
There was a problem hiding this comment.
I don't see these new imports used in the code below...
There was a problem hiding this comment.
You're right thanks, it's something that I missed during the multiple rebase. I started this during the summer 2025.
buildSrc/src/main/kotlin/datadog/gradle/plugin/csi/CallSiteInstrumentationPlugin.kt
Show resolved
Hide resolved
mcculls
left a comment
There was a problem hiding this comment.
Just a couple of clarifying questions - otherwise looks good
…gins Also, use proper configuration factory methods for these configs
13e2583 to
8abc7a0
Compare
…ng Gradle lazy APIs) (#9475) * chore(build): Rewrite InstrumentPlugin as compile post processing action The current implementation was using bad practices in various ways, `project.afterEvaluate`, task creation, explicit `dependsOn` # Conflicts: # buildSrc/src/main/groovy/InstrumentPlugin.groovy # buildSrc/src/main/groovy/MuzzlePlugin.groovy # dd-java-agent/instrumentation/jetty-9/build.gradle # Conflicts: # buildSrc/src/main/groovy/InstrumentPlugin.groovy # buildSrc/src/test/groovy/InstrumentPluginTest.groovy # dd-java-agent/instrumentation/play/play-2.4/build.gradle # dd-java-agent/instrumentation/play/play-2.6/build.gradle * chore(build): replace dependency on instrument task to source cet output * chore: Properly react on instrumentPluginClasspath configuration * chore: Rework additional classpath and instrumenter classpath contributions to instrument plugin * fix: Remove eager whenObjectAdded in InstrumentPlugin * fix: Fix bad java version comparison * chore: Rework INSTRUMENT_PLUGIN_CLASSPATH_CONFIGURATION registration and configuration * chore: Remove CallSiteInstrumentationPlugin dependencies on instrumentJava Since instrument plugin do post-processing within compileTask, it not anymore required to depends on instrumentation tasks (as they don't exist anymore) * chore: Removes useless afterEvaluate for forbiddenApi tasks * chore: Split single plugin file to separate types * chore: Now instrumentPluginClasspath configuration is already registered * fix: Incorrect comparison * style: Make spotless happy * chore: Renames plugin to BuildTimeInstrumentationPlugin * chore: PR Review * chore: Rename build-time-instrumentation configuration of tooling plugins Also, use proper configuration factory methods for these configs


What Does This Do
Disclaimer: This only touches the build part (i.e. Gradle).
The current
InstrumentPluginuses eager gradle API and inject a task to run after the compile task, and in doing so, exchanging their output. This approach is uncommon, create as many instrument task as they are compile tasks, and make it harder to predict compilation output.This PR rethink the approach to a compilation post-processor. So instead of injecting a task in the gradle task graph, each compile task have a post-processor action.
Also, the plugin is renamed to
dd-trace-java.build-time-instrumentationfor better expressing intent. (Related configuration points are also renamed),In doing so, it makes the intent of this plug-in easier to grasp.
On another note, the single Groovy file has been spread to distinct types.
Motivation
dd-trace-java.build-time-instrumentationwas chosen to aligndd-trace-java.call-site-instrumentation. Also, searching these string will bring more focused results.Avoid Gradle eager API, avoid messing with compile tasks avoid,
Helps going toward convention plug-ins.
Additional Notes
Related PRs
Related to
MuzzlePlugin#9315CallSiteInstrumentationPlugin#9316Blocked by
afterEvaluate#9752testJvmConstraintsGradle extension to replace extra properties #9892:dd-java-agent:testing#10218jetty-server-9.0project setup to multiple modules #9683What does this plugin
ℹ️ italic word indicate Gradle linguo.
buildTimeInstrumentationname (previouslyinstrument)buildTimeInstrumentationPluginname (previouslyinstrumentPluginClasspath)Currently, this build time instrumentation is applied on instrumentation modules :
datadog.trace.agent.tooling.muzzle.MuzzleGradlePlugin: Creates muzzle-references at compile time for classes extendingInstrumenterModule. This generates metadata about instrumentation compatibility.datadog.trace.agent.tooling.bytebuddy.NewTaskForGradlePlugin: Used fordatadog.trace.instrumentation.java.concurrent.WrapRunnableAsNewTaskInstrumentationinstrumentation, to replacedatadog.trace.bootstrap.instrumentation.java.concurrent.NewTaskForPlaceholder#newTaskForbyjava.util.concurrent.AbstractExecutorService#newTaskFor(java.lang.Runnable, T)(which is protected and not accessible during compilation).datadog.trace.agent.tooling.bytebuddy.reqctx.RewriteRequestContextAdvicePlugin: Transforms classes annotated with @RequiresRequestContext to inject request context handling....and in the otel agent
datadog.opentelemetry.tooling.shim.OtelShimGradlePlugin: Injects Datadog's OpenTelemetry shim into specific OpenTelemetry API classes like DefaultOpenTelemetry, GlobalOpenTelemetry$ObfuscatedOpenTelemetry, ThreadLocalContextStorage, etc. This allows intercepting OpenTelemetry API calls at build-time.Additional checks
As in #9514 I also checked the produced jars between
masterand this branch using myjardifftool I already mentioned there (I crafted it for validating #9514, other tools didn't work or didn't perform what was needed).Note
🔗 https://github.com/bric3/jardiff
Shortcomings:
Ran the following command on this branch (folder
dd-trace-java-copy-2), and onmaster(folderdd-trace-java-copy-1).The following assumes that
jardiffis actually this commandjava -jar jardiff/build/libs/jardiff-0.1.0-SNAPSHOT.jar, and assuming this is a Java 25. Also, while not strictly necessary the following snippets usedeltato render the diff.The following difference have been checked:
dd-java-agentjardiff ../dd-trace-java-copy-{1,2}/dd-java-agent/build/libs/dd-java-agent-1.58.0-SNAPSHOT.jar \ -c classdata \ --exclude "**/*.yaml,**/*.MF,**/*.version,*.version,*.txt" \ | delta --syntax-theme=GitHub --lightNo differences: