Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import io.opentelemetry.javaagent.muzzle.generation.ClasspathByteBuddyPlugin
import io.opentelemetry.javaagent.muzzle.generation.ClasspathTransformation
import net.bytebuddy.ClassFileVersion
import net.bytebuddy.build.gradle.ByteBuddySimpleTask
import io.opentelemetry.javaagent.muzzle.generation.ConfigurationCacheFriendlyByteBuddyTask
import net.bytebuddy.build.gradle.Transformation

plugins {
Expand Down Expand Up @@ -50,7 +49,7 @@ val languageTasks = LANGUAGES.map { language ->
return@map null
}
val compileTask = tasks.named(compileTaskName)
createLanguageTask(compileTask, "byteBuddy${language.replaceFirstChar(Char::titlecase)}")
createLanguageTask(compileTask, language)
}.filterNotNull()

tasks {
Expand All @@ -60,29 +59,43 @@ tasks {
}

fun createLanguageTask(
compileTaskProvider: TaskProvider<*>, name: String): TaskProvider<*> {
return tasks.register<ByteBuddySimpleTask>(name) {
setGroup("Byte Buddy")
outputs.cacheIf { true }
classFileVersion = ClassFileVersion.JAVA_V8
var transformationClassPath = inputClasspath
compileTaskProvider: TaskProvider<*>, language: String): TaskProvider<*> {
val taskName = "byteBuddy${language.replaceFirstChar { it.uppercase() }}"
val mainSourceSet = sourceSets.main.get()

// Create the input classpath from the existing logic in the main part
val inputClasspath = (mainSourceSet.output.resourcesDir?.let { codegen.plus(project.files(it)) }
?: codegen)
.plus(mainSourceSet.output.dirs) // needed to support embedding shadowed modules into instrumentation
.plus(configurations.runtimeClasspath.get())

val byteBuddyTask = tasks.register(taskName, ConfigurationCacheFriendlyByteBuddyTask::class.java) {
dependsOn(compileTaskProvider, mainSourceSet.processResourcesTaskName)

transformations.add(createTransformation(inputClasspath, pluginName))

// Configure the ByteBuddy task properties directly during task creation
val compileTask = compileTaskProvider.get()
// this does not work for kotlin as compile task does not extend AbstractCompile
if (compileTask is AbstractCompile) {
val classesDirectory = compileTask.destinationDirectory.asFile.get()
val rawClassesDirectory: File = File(classesDirectory.parent, "${classesDirectory.name}raw")
.absoluteFile
dependsOn(compileTask)
val rawClassesDirectory = File(classesDirectory.parent, "${classesDirectory.name}raw").absoluteFile

// Configure the compile task to write to rawClassesDirectory
compileTask.destinationDirectory.set(rawClassesDirectory)

// Configure ByteBuddy task properties
source = rawClassesDirectory
target = classesDirectory
classPath = compileTask.classpath.plus(rawClassesDirectory)
transformationClassPath = transformationClassPath.plus(files(rawClassesDirectory))
dependsOn(compileTask, sourceSet.processResourcesTaskName)
}

transformations.add(createTransformation(transformationClassPath, pluginName))
// Clear and set transformations with correct classpath
transformations.clear()
transformations.add(createTransformation(inputClasspath.plus(files(rawClassesDirectory)), pluginName))
}
}

return byteBuddyTask
}

fun createTransformation(classPath: FileCollection, pluginClassName: String): Transformation {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.opentelemetry.javaagent.muzzle.generation

import net.bytebuddy.build.Plugin
import net.bytebuddy.build.gradle.ByteBuddySimpleTask
import org.gradle.api.tasks.TaskAction
import java.io.IOException

/**
* Byte Buddy task variant that avoids touching Gradle's Project API from the task action so the
* task remains compatible with Gradle configuration cache.
*/
open class ConfigurationCacheFriendlyByteBuddyTask : ByteBuddySimpleTask() {

@TaskAction
@Throws(IOException::class)
override fun apply() {
val sourceDir = source
val targetDir = target

if (sourceDir != targetDir && deleteRecursively(targetDir)) {
logger.debug("Deleted all target files in {}", targetDir)
}

doApply(
Plugin.Engine.Source.ForFolder(sourceDir),
Plugin.Engine.Target.ForFolder(targetDir)
)
}
}
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true

org.gradle.priority=low

Expand Down
53 changes: 50 additions & 3 deletions instrumentation-api-incubator/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
plugins {
id("org.xbib.gradle.plugin.jflex")

id("otel.java-conventions")
id("otel.animalsniffer-conventions")
id("otel.jacoco-conventions")
Expand All @@ -10,7 +8,17 @@ plugins {

group = "io.opentelemetry.instrumentation"

// JFlex configuration - manual integration for configuration cache compatibility
configurations {
val jflex by creating {
isTransitive = true
}
}

dependencies {
"jflex"("de.jflex:jflex:1.9.1")
"jflex"("com.github.vbmacher:java-cup-runtime:11b-20160615")

api("io.opentelemetry.semconv:opentelemetry-semconv")
api(project(":instrumentation-api"))
api("io.opentelemetry:opentelemetry-api-incubator")
Expand All @@ -24,6 +32,41 @@ dependencies {
testImplementation("io.opentelemetry.semconv:opentelemetry-semconv-incubating")
}

// Manual JFlex task - configuration cache compatible
val generateJflex by tasks.registering(JavaExec::class) {
description = "Generate Java code from JFlex files"
group = "build"

classpath = configurations.getByName("jflex")
mainClass.set("jflex.Main")

val jflexSourceDir = file("src/main/jflex")
val jflexOutputDir = file("build/generated/sources/jflex")

inputs.dir(jflexSourceDir)
outputs.dir(jflexOutputDir)

doFirst {
jflexOutputDir.mkdirs()
}

args(
"-d", jflexOutputDir,
"--nobak",
"$jflexSourceDir/SqlSanitizer.jflex"
)
}

sourceSets {
main {
java.srcDir(generateJflex.map { it.outputs.files.singleFile })
}
}

tasks.compileJava {
dependsOn(generateJflex)
}

tasks {
// exclude auto-generated code
named<Checkstyle>("checkstyleMain") {
Expand All @@ -38,7 +81,11 @@ tasks {
}

sourcesJar {
dependsOn("generateJflex")
dependsOn(generateJflex)
// Avoid configuration cache issue by not capturing task reference
from("src/main/jflex") {
include("**/*.java")
}
}

val testStableSemconv by registering(Test::class) {
Expand Down
1 change: 0 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pluginManagement {
id("com.gradle.plugin-publish") version "2.0.0"
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
id("org.jetbrains.kotlin.jvm") version "2.2.21"
id("org.xbib.gradle.plugin.jflex") version "3.0.2"
id("com.github.bjornvester.xjc") version "1.8.2"
id("org.graalvm.buildtools.native") version "0.11.2"
id("com.google.osdetector") version "1.7.3"
Expand Down
20 changes: 12 additions & 8 deletions testing/agent-for-testing/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import java.io.File

plugins {
id("otel.java-conventions")
id("otel.publish-conventions")
Expand All @@ -16,6 +18,14 @@ val extensionLibs by configurations.creating {
isCanBeConsumed = false
}

val agentJarFile = providers.provider { agent.singleFile }

val agentManifestFile = agentJarFile.map { jarFile: File ->
zipTree(jarFile).matching {
include("META-INF/MANIFEST.MF")
}.singleFile
}

dependencies {
extensionLibs(project(":testing:agent-exporter", configuration = "shadow"))
agent(project(":javaagent", configuration = "baseJar"))
Expand All @@ -27,18 +37,12 @@ dependencies {
tasks {
jar {
dependsOn(agent)
from(zipTree(agent.singleFile))
from(agentJarFile.map { jarFile: File -> zipTree(jarFile) })
from(extensionLibs) {
into("extensions")
}

doFirst {
manifest.from(
zipTree(agent.singleFile).matching {
include("META-INF/MANIFEST.MF")
}.singleFile,
)
}
manifest.from(agentManifestFile)
}

afterEvaluate {
Expand Down
Loading