From 95b10b4f63805b170c538da5b125cd831f99e767 Mon Sep 17 00:00:00 2001 From: Trask Stalnaker Date: Wed, 29 Apr 2026 15:15:21 -0700 Subject: [PATCH] Migrate examples/distro and examples/extension from Groovy to Kotlin DSL --- .github/renovate.json5 | 2 +- .github/scripts/update-sdk-version.sh | 2 +- .github/scripts/update-version.sh | 9 +- examples/distro/agent/build.gradle | 134 ------------------ examples/distro/agent/build.gradle.kts | 12 ++ examples/distro/bootstrap/build.gradle | 6 - examples/distro/bootstrap/build.gradle.kts | 3 + examples/distro/build.gradle | 87 ------------ examples/distro/build.gradle.kts | 2 + examples/distro/buildSrc/build.gradle.kts | 13 ++ examples/distro/buildSrc/settings.gradle.kts | 5 + .../src/main/kotlin/Relocations.kt} | 4 +- .../buildSrc/src/main/kotlin/Versions.kt | 8 ++ ...tel.instrumentation-conventions.gradle.kts | 72 ++++++++++ .../kotlin/otel.java-conventions.gradle.kts | 47 ++++++ ...el.javaagent-shadow-conventions.gradle.kts | 117 +++++++++++++++ .../custom/{build.gradle => build.gradle.kts} | 2 +- examples/distro/gradle/instrumentation.gradle | 90 ------------ examples/distro/instrumentation/build.gradle | 13 -- .../instrumentation/servlet-3/build.gradle | 34 ----- .../servlet-3/build.gradle.kts | 43 ++++++ examples/distro/settings.gradle | 19 --- examples/distro/settings.gradle.kts | 24 ++++ .../{build.gradle => build.gradle.kts} | 11 +- .../testing/agent-for-testing/build.gradle | 131 ----------------- .../agent-for-testing/build.gradle.kts | 9 ++ .../{settings.gradle => settings.gradle.kts} | 2 +- 27 files changed, 370 insertions(+), 531 deletions(-) delete mode 100644 examples/distro/agent/build.gradle create mode 100644 examples/distro/agent/build.gradle.kts delete mode 100644 examples/distro/bootstrap/build.gradle create mode 100644 examples/distro/bootstrap/build.gradle.kts delete mode 100644 examples/distro/build.gradle create mode 100644 examples/distro/build.gradle.kts create mode 100644 examples/distro/buildSrc/build.gradle.kts create mode 100644 examples/distro/buildSrc/settings.gradle.kts rename examples/distro/{gradle/shadow.gradle => buildSrc/src/main/kotlin/Relocations.kt} (93%) create mode 100644 examples/distro/buildSrc/src/main/kotlin/Versions.kt create mode 100644 examples/distro/buildSrc/src/main/kotlin/otel.instrumentation-conventions.gradle.kts create mode 100644 examples/distro/buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts create mode 100644 examples/distro/buildSrc/src/main/kotlin/otel.javaagent-shadow-conventions.gradle.kts rename examples/distro/custom/{build.gradle => build.gradle.kts} (94%) delete mode 100644 examples/distro/gradle/instrumentation.gradle delete mode 100644 examples/distro/instrumentation/build.gradle delete mode 100644 examples/distro/instrumentation/servlet-3/build.gradle create mode 100644 examples/distro/instrumentation/servlet-3/build.gradle.kts delete mode 100644 examples/distro/settings.gradle create mode 100644 examples/distro/settings.gradle.kts rename examples/distro/smoke-tests/{build.gradle => build.gradle.kts} (78%) delete mode 100644 examples/distro/testing/agent-for-testing/build.gradle create mode 100644 examples/distro/testing/agent-for-testing/build.gradle.kts rename examples/extension/{settings.gradle => settings.gradle.kts} (72%) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 05e0fd0c3693..6a16d5e49efc 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -366,7 +366,7 @@ { // pinned version to Jetty 8 (Servlet 3.0) for compatibility matchFileNames: [ - 'examples/distro/instrumentation/servlet-3/build.gradle', + 'examples/distro/instrumentation/servlet-3/build.gradle.kts', ], matchUpdateTypes: [ 'major', diff --git a/.github/scripts/update-sdk-version.sh b/.github/scripts/update-sdk-version.sh index d7f9eebeb8c3..3deb15da98d9 100755 --- a/.github/scripts/update-sdk-version.sh +++ b/.github/scripts/update-sdk-version.sh @@ -4,6 +4,6 @@ version=$1 sed -Ei "s/val otelSdkVersion = \"[^\"]*\"/val otelSdkVersion = \"$version\"/" dependencyManagement/build.gradle.kts -sed -Ei "s/(opentelemetrySdk *: )\"[^\"]*\"/\1\"$version\"/" examples/distro/build.gradle +sed -Ei "s/(const val opentelemetrySdkVersion = )\"[^\"]*\"/\1\"$version\"/" examples/distro/buildSrc/src/main/kotlin/Versions.kt sed -Ei "s/(\"opentelemetrySdk\" to )\"[^\"]*\"/\1\"$version\"/" examples/extension/build.gradle.kts diff --git a/.github/scripts/update-version.sh b/.github/scripts/update-version.sh index 3e92b61d2362..6a629e86151a 100755 --- a/.github/scripts/update-version.sh +++ b/.github/scripts/update-version.sh @@ -11,15 +11,14 @@ fi sed -Ei "s/val stableVersion = \"[^\"]*\"/val stableVersion = \"$version\"/" version.gradle.kts sed -Ei "s/val alphaVersion = \"[^\"]*\"/val alphaVersion = \"$alpha_version\"/" version.gradle.kts -sed -Ei "s/(opentelemetryJavaagent *: )\"[^\"]*\"/\1\"$version\"/" examples/distro/build.gradle -sed -Ei "s/(opentelemetryJavaagentAlpha *: )\"[^\"]*\"/\1\"$alpha_version\"/" examples/distro/build.gradle +sed -Ei "s/(const val opentelemetryJavaagentVersion = )\"[^\"]*\"/\1\"$version\"/" examples/distro/buildSrc/src/main/kotlin/Versions.kt +sed -Ei "s/(const val opentelemetryJavaagentAlphaVersion = )\"[^\"]*\"/\1\"$alpha_version\"/" examples/distro/buildSrc/src/main/kotlin/Versions.kt -sed -Ei "s/(classpath \"io.opentelemetry.instrumentation:gradle-plugins:)[^\"]*\"/\1$alpha_version\"/" examples/distro/build.gradle +sed -Ei "s/(io.opentelemetry.instrumentation.muzzle-(generation|check)\"\) version )\"[^\"]*\"/\1\"$alpha_version\"/" examples/distro/settings.gradle.kts sed -Ei "s/(\"opentelemetryJavaagent\" to )\"[^\"]*\"/\1\"$version\"/" examples/extension/build.gradle.kts sed -Ei "s/(\"opentelemetryJavaagentAlpha\" to )\"[^\"]*\"/\1\"$alpha_version\"/" examples/extension/build.gradle.kts -sed -Ei "s/(io.opentelemetry.instrumentation.muzzle-generation\"\) version )\"[^\"]*\"/\1\"$alpha_version\"/" examples/extension/build.gradle.kts -sed -Ei "s/(io.opentelemetry.instrumentation.muzzle-check\"\) version )\"[^\"]*\"/\1\"$alpha_version\"/" examples/extension/build.gradle.kts +sed -Ei "s/(io.opentelemetry.instrumentation.muzzle-(generation|check)\"\) version )\"[^\"]*\"/\1\"$alpha_version\"/" examples/extension/build.gradle.kts sed -Ei "1 s/(Comparing source compatibility of [a-z-]+)-[0-9]+\.[0-9]+\.[0-9]+(-SNAPSHOT)?.jar/\1-$version.jar/" docs/apidiffs/current_vs_latest/*.txt diff --git a/examples/distro/agent/build.gradle b/examples/distro/agent/build.gradle deleted file mode 100644 index 4e493f757b81..000000000000 --- a/examples/distro/agent/build.gradle +++ /dev/null @@ -1,134 +0,0 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - -plugins { - id("com.gradleup.shadow") -} - -apply from: "$rootDir/gradle/shadow.gradle" - -def relocatePackages = ext.relocatePackages - -configurations { - // this configuration collects libs that will be placed in the bootstrap classloader - bootstrapLibs { - canBeResolved = true - canBeConsumed = false - } - // this configuration collects libs that will be placed in the agent classloader, isolated from the instrumented application code - javaagentLibs { - canBeResolved = true - canBeConsumed = false - } - // this configuration stores the upstream agent dep that's extended by this project - upstreamAgent { - canBeResolved = true - canBeConsumed = false - } -} - -dependencies { - bootstrapLibs(project(":bootstrap")) - - javaagentLibs(project(":custom")) - javaagentLibs(project(":instrumentation:servlet-3")) - - upstreamAgent("io.opentelemetry.javaagent:opentelemetry-javaagent:${versions.opentelemetryJavaagent}") -} - -CopySpec isolateClasses(Iterable jars) { - return copySpec { - jars.forEach { - from(zipTree(it)) { - into("inst") - rename("^(.*)\\.class\$", "\$1.classdata") - exclude("^LICENSE\$") - exclude("META-INF/INDEX.LIST") - exclude("META-INF/*.DSA") - exclude("META-INF/*.SF") - exclude("META-INF/maven/**") - exclude("META-INF/MANIFEST.MF") - } - } - } -} - -tasks { - jar { - enabled = false - } - - // building the final javaagent jar is done in 3 steps: - - // 1. all distro specific javaagent libs are relocated - task relocateJavaagentLibs(type: ShadowJar) { - configurations = [project.configurations.javaagentLibs] - - archiveFileName.set("javaagentLibs-relocated.jar") - - duplicatesStrategy = DuplicatesStrategy.FAIL - mergeServiceFiles() - // mergeServiceFiles requires that duplicate strategy is set to include - filesMatching("META-INF/services/**") { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - } - exclude("**/module-info.class") - relocatePackages(it) - - // exclude known bootstrap dependencies - they can't appear in the inst/ directory - dependencies { - exclude("io.opentelemetry:opentelemetry-api") - exclude("io.opentelemetry:opentelemetry-common") - exclude("io.opentelemetry:opentelemetry-context") - exclude("io.opentelemetry.semconv:opentelemetry-semconv") - exclude("io.opentelemetry.semconv:opentelemetry-semconv-incubating") - // events API and metrics advice API - exclude("io.opentelemetry:opentelemetry-api-incubator") - } - } - - // 2. the distro javaagent libs are then isolated - moved to the inst/ directory - // having a separate task for isolating javaagent libs is required to avoid duplicates with the upstream javaagent - // duplicatesStrategy in shadowJar won't be applied when adding files with with(CopySpec) because each CopySpec has - // its own duplicatesStrategy - task isolateJavaagentLibs(type: Copy) { - dependsOn(tasks.relocateJavaagentLibs) - with isolateClasses(tasks.relocateJavaagentLibs.outputs.files) - - into(layout.buildDirectory.dir("isolated/javaagentLibs")) - } - - // 3. the relocated and isolated javaagent libs are merged together with the bootstrap libs (which undergo relocation - // in this task) and the upstream javaagent jar; duplicates are removed - shadowJar { - configurations = [project.configurations.bootstrapLibs, project.configurations.upstreamAgent] - - dependsOn(tasks.isolateJavaagentLibs) - from(tasks.isolateJavaagentLibs.outputs) - - archiveClassifier.set("all") - - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - mergeServiceFiles("inst/META-INF/services") - // mergeServiceFiles requires that duplicate strategy is set to include - filesMatching("inst/META-INF/services/**") { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - } - - exclude("**/module-info.class") - relocatePackages(it) - - manifest { - attributes.put("Main-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") - attributes.put("Agent-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") - attributes.put("Premain-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") - attributes.put("Can-Redefine-Classes", "true") - attributes.put("Can-Retransform-Classes", "true") - attributes.put("Implementation-Vendor", "Demo") - attributes.put("Implementation-Version", "demo-${project.version}-otel-${versions.opentelemetryJavaagent}") - } - } - - assemble { - dependsOn(shadowJar) - } -} diff --git a/examples/distro/agent/build.gradle.kts b/examples/distro/agent/build.gradle.kts new file mode 100644 index 000000000000..511d00a625c9 --- /dev/null +++ b/examples/distro/agent/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("otel.javaagent-shadow-conventions") +} + +dependencies { + bootstrapLibs(project(":bootstrap")) + + javaagentLibs(project(":custom")) + javaagentLibs(project(":instrumentation:servlet-3")) + + upstreamAgent("io.opentelemetry.javaagent:opentelemetry-javaagent:$opentelemetryJavaagentVersion") +} diff --git a/examples/distro/bootstrap/build.gradle b/examples/distro/bootstrap/build.gradle deleted file mode 100644 index 1f769508f773..000000000000 --- a/examples/distro/bootstrap/build.gradle +++ /dev/null @@ -1,6 +0,0 @@ -plugins { - id "java" -} - -dependencies { -} diff --git a/examples/distro/bootstrap/build.gradle.kts b/examples/distro/bootstrap/build.gradle.kts new file mode 100644 index 000000000000..0a3932d24293 --- /dev/null +++ b/examples/distro/bootstrap/build.gradle.kts @@ -0,0 +1,3 @@ +plugins { + id("otel.java-conventions") +} diff --git a/examples/distro/build.gradle b/examples/distro/build.gradle deleted file mode 100644 index 785a74b4b56c..000000000000 --- a/examples/distro/build.gradle +++ /dev/null @@ -1,87 +0,0 @@ -group 'io.opentelemetry.example' -version '1.0-SNAPSHOT' - -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - maven { - name = "sonatype" - url = uri("https://central.sonatype.com/repository/maven-snapshots/") - } - } - dependencies { - classpath "com.diffplug.spotless:spotless-plugin-gradle:8.4.0" - classpath "com.gradleup.shadow:shadow-gradle-plugin:9.4.1" - classpath "io.opentelemetry.instrumentation:gradle-plugins:2.28.0-alpha-SNAPSHOT" - } -} - -subprojects { - version = rootProject.version - - apply plugin: "java" - apply plugin: "com.diffplug.spotless" - - ext { - versions = [ - // this line is managed by .github/scripts/update-sdk-version.sh - opentelemetrySdk : "1.61.0", - - // these lines are managed by .github/scripts/update-version.sh - opentelemetryJavaagent : "2.28.0-SNAPSHOT", - opentelemetryJavaagentAlpha: "2.28.0-alpha-SNAPSHOT", - - autoservice : "1.1.1" - ] - - deps = [ - autoservice: [ - "com.google.auto.service:auto-service:${versions.autoservice}", - "com.google.auto.service:auto-service-annotations:${versions.autoservice}", - ] - ] - } - - repositories { - mavenCentral() - maven { - name = "sonatype" - url = uri("https://central.sonatype.com/repository/maven-snapshots/") - } - } - - spotless { - java { - googleJavaFormat() - licenseHeaderFile(rootProject.file("../../buildscripts/spotless.license.java"), "(package|import|public)") - target("src/**/*.java") - } - } - - dependencies { - implementation(platform("io.opentelemetry:opentelemetry-bom:${versions.opentelemetrySdk}")) - - // these serve as a test of the instrumentation boms - implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:${versions.opentelemetryJavaagent}")) - implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:${versions.opentelemetryJavaagentAlpha}")) - - testImplementation("org.mockito:mockito-core:5.23.0") - - testImplementation(enforcedPlatform("org.junit:junit-bom:5.14.4")) - testImplementation("org.junit.jupiter:junit-jupiter-api") - testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") - testRuntimeOnly("org.junit.platform:junit-platform-launcher") - } - - tasks { - test { - useJUnitPlatform() - } - - compileJava { - options.release.set(8) - } - } -} diff --git a/examples/distro/build.gradle.kts b/examples/distro/build.gradle.kts new file mode 100644 index 000000000000..32e4c9cb9f91 --- /dev/null +++ b/examples/distro/build.gradle.kts @@ -0,0 +1,2 @@ +group = "io.opentelemetry.example" +version = "1.0-SNAPSHOT" diff --git a/examples/distro/buildSrc/build.gradle.kts b/examples/distro/buildSrc/build.gradle.kts new file mode 100644 index 000000000000..d1af48f6dccc --- /dev/null +++ b/examples/distro/buildSrc/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() + gradlePluginPortal() +} + +dependencies { + implementation("com.diffplug.spotless:spotless-plugin-gradle:8.4.0") + implementation("com.gradleup.shadow:shadow-gradle-plugin:9.4.1") +} diff --git a/examples/distro/buildSrc/settings.gradle.kts b/examples/distro/buildSrc/settings.gradle.kts new file mode 100644 index 000000000000..7631e58d1132 --- /dev/null +++ b/examples/distro/buildSrc/settings.gradle.kts @@ -0,0 +1,5 @@ +pluginManagement { + repositories { + gradlePluginPortal() + } +} diff --git a/examples/distro/gradle/shadow.gradle b/examples/distro/buildSrc/src/main/kotlin/Relocations.kt similarity index 93% rename from examples/distro/gradle/shadow.gradle rename to examples/distro/buildSrc/src/main/kotlin/Relocations.kt index 11316f1f02a5..bf9ebbdf28d3 100644 --- a/examples/distro/gradle/shadow.gradle +++ b/examples/distro/buildSrc/src/main/kotlin/Relocations.kt @@ -1,4 +1,6 @@ -ext.relocatePackages = { shadowJar -> +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +fun relocatePackages(shadowJar: ShadowJar) { // rewrite dependencies calling Logger.getLogger shadowJar.relocate("java.util.logging.Logger", "io.opentelemetry.javaagent.bootstrap.PatchLogger") diff --git a/examples/distro/buildSrc/src/main/kotlin/Versions.kt b/examples/distro/buildSrc/src/main/kotlin/Versions.kt new file mode 100644 index 000000000000..63ce250aa933 --- /dev/null +++ b/examples/distro/buildSrc/src/main/kotlin/Versions.kt @@ -0,0 +1,8 @@ +// this line is managed by .github/scripts/update-sdk-version.sh +const val opentelemetrySdkVersion = "1.61.0" + +// these lines are managed by .github/scripts/update-version.sh +const val opentelemetryJavaagentVersion = "2.28.0-SNAPSHOT" +const val opentelemetryJavaagentAlphaVersion = "2.28.0-alpha-SNAPSHOT" + +const val autoserviceVersion = "1.1.1" diff --git a/examples/distro/buildSrc/src/main/kotlin/otel.instrumentation-conventions.gradle.kts b/examples/distro/buildSrc/src/main/kotlin/otel.instrumentation-conventions.gradle.kts new file mode 100644 index 000000000000..3d4e98f174db --- /dev/null +++ b/examples/distro/buildSrc/src/main/kotlin/otel.instrumentation-conventions.gradle.kts @@ -0,0 +1,72 @@ +plugins { + id("otel.java-conventions") + id("com.gradleup.shadow") +} + +val testInstrumentation by configurations.creating +val testAgent by configurations.creating + +dependencies { + compileOnly("io.opentelemetry:opentelemetry-sdk") + compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api") + compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api") + + annotationProcessor("com.google.auto.service:auto-service:$autoserviceVersion") + compileOnly("com.google.auto.service:auto-service-annotations:$autoserviceVersion") + + // the javaagent that is going to be used when running instrumentation unit tests + testAgent(project(path = ":testing:agent-for-testing", configuration = "shadow")) + // test dependencies + testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common") + testImplementation("io.opentelemetry:opentelemetry-sdk-testing") + testImplementation("org.assertj:assertj-core:3.27.7") +} + +tasks.shadowJar { + configurations = listOf(project.configurations.runtimeClasspath.get(), testInstrumentation) + + mergeServiceFiles() + // mergeServiceFiles requires that duplicate strategy is set to include + filesMatching("META-INF/services/**") { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + + archiveFileName.set("agent-testing.jar") + + relocatePackages(this) +} + +tasks.withType().configureEach { + val initializerJar = tasks.shadowJar.flatMap { it.archiveFile }.map { it.asFile } + val agentJar = testAgent.elements.map { it.first().asFile } + + jvmArgs("-Dotel.javaagent.debug=true") + jvmArgs("-Dotel.javaagent.testing.additional-library-ignores.enabled=false") + jvmArgs("-Dotel.javaagent.testing.fail-on-context-leak=true") + // prevent sporadic gradle deadlocks, see SafeLogger for more details + jvmArgs("-Dotel.javaagent.testing.transform-safe-logging.enabled=true") + + jvmArgumentProviders.add(JavaagentProvider(agentJar, initializerJar)) + + // The sources are packaged into the testing jar so we need to make sure to exclude from the test + // classpath, which automatically inherits them, to ensure our shaded versions are used. + val resourcesMain = layout.buildDirectory.dir("resources/main").get().asFile + val classesMain = layout.buildDirectory.dir("classes/java/main").get().asFile + classpath = classpath.filter { + it != resourcesMain && it != classesMain + } +} + +class JavaagentProvider( + @get:InputFile + @get:PathSensitive(PathSensitivity.RELATIVE) + val agentJar: Provider, + @get:InputFile + @get:PathSensitive(PathSensitivity.RELATIVE) + val initializerJar: Provider, +) : CommandLineArgumentProvider { + override fun asArguments(): Iterable = listOf( + "-javaagent:${agentJar.get().absolutePath}", + "-Dotel.javaagent.experimental.initializer.jar=${initializerJar.get().absolutePath}", + ) +} diff --git a/examples/distro/buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts b/examples/distro/buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts new file mode 100644 index 000000000000..46350290f75c --- /dev/null +++ b/examples/distro/buildSrc/src/main/kotlin/otel.java-conventions.gradle.kts @@ -0,0 +1,47 @@ +plugins { + java + id("com.diffplug.spotless") +} + +version = rootProject.version + +repositories { + mavenCentral() + maven { + name = "sonatype" + url = uri("https://central.sonatype.com/repository/maven-snapshots/") + } +} + +spotless { + java { + googleJavaFormat() + licenseHeaderFile(rootProject.file("../../buildscripts/spotless.license.java"), "(package|import|public)") + target("src/**/*.java") + } +} + +dependencies { + implementation(platform("io.opentelemetry:opentelemetry-bom:$opentelemetrySdkVersion")) + + // these serve as a test of the instrumentation boms + implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:$opentelemetryJavaagentVersion")) + implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:$opentelemetryJavaagentAlphaVersion")) + + testImplementation("org.mockito:mockito-core:5.23.0") + + testImplementation(enforcedPlatform("org.junit:junit-bom:5.14.4")) + testImplementation("org.junit.jupiter:junit-jupiter-api") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine") + testRuntimeOnly("org.junit.platform:junit-platform-launcher") +} + +tasks { + test { + useJUnitPlatform() + } + + compileJava { + options.release.set(8) + } +} diff --git a/examples/distro/buildSrc/src/main/kotlin/otel.javaagent-shadow-conventions.gradle.kts b/examples/distro/buildSrc/src/main/kotlin/otel.javaagent-shadow-conventions.gradle.kts new file mode 100644 index 000000000000..4a17c202585d --- /dev/null +++ b/examples/distro/buildSrc/src/main/kotlin/otel.javaagent-shadow-conventions.gradle.kts @@ -0,0 +1,117 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("otel.java-conventions") + id("com.gradleup.shadow") +} + +// this configuration collects libs that will be placed in the bootstrap classloader +val bootstrapLibs by configurations.creating { + isCanBeResolved = true + isCanBeConsumed = false +} +// this configuration collects libs that will be placed in the agent classloader, isolated from the instrumented application code +val javaagentLibs by configurations.creating { + isCanBeResolved = true + isCanBeConsumed = false +} +// this configuration stores the upstream agent dep that's extended by this project +val upstreamAgent by configurations.creating { + isCanBeResolved = true + isCanBeConsumed = false +} + +fun isolateClasses(jars: Iterable): CopySpec = copySpec { + jars.forEach { + from(zipTree(it)) { + into("inst") + rename("^(.*)\\.class\$", "\$1.classdata") + exclude("^LICENSE\$") + exclude("META-INF/INDEX.LIST") + exclude("META-INF/*.DSA") + exclude("META-INF/*.SF") + exclude("META-INF/maven/**") + exclude("META-INF/MANIFEST.MF") + } + } +} + +tasks { + jar { + enabled = false + } + + // building the final javaagent jar is done in 3 steps: + + // 1. all distro specific javaagent libs are relocated + val relocateJavaagentLibs by registering(ShadowJar::class) { + configurations = listOf(javaagentLibs) + + archiveFileName.set("javaagentLibs-relocated.jar") + + duplicatesStrategy = DuplicatesStrategy.FAIL + mergeServiceFiles() + // mergeServiceFiles requires that duplicate strategy is set to include + filesMatching("META-INF/services/**") { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + exclude("**/module-info.class") + relocatePackages(this) + + // exclude known bootstrap dependencies - they can't appear in the inst/ directory + dependencies { + exclude(dependency("io.opentelemetry:opentelemetry-api")) + exclude(dependency("io.opentelemetry:opentelemetry-common")) + exclude(dependency("io.opentelemetry:opentelemetry-context")) + exclude(dependency("io.opentelemetry.semconv:opentelemetry-semconv")) + exclude(dependency("io.opentelemetry.semconv:opentelemetry-semconv-incubating")) + // events API and metrics advice API + exclude(dependency("io.opentelemetry:opentelemetry-api-incubator")) + } + } + + // 2. the distro javaagent libs are then isolated - moved to the inst/ directory + // having a separate task for isolating javaagent libs is required to avoid duplicates with the upstream javaagent + // duplicatesStrategy in shadowJar won't be applied when adding files with with(CopySpec) because each CopySpec has + // its own duplicatesStrategy + val isolateJavaagentLibs by registering(Copy::class) { + dependsOn(relocateJavaagentLibs) + with(isolateClasses(relocateJavaagentLibs.get().outputs.files)) + + into(layout.buildDirectory.dir("isolated/javaagentLibs")) + } + + // 3. the relocated and isolated javaagent libs are merged together with the bootstrap libs (which undergo relocation + // in this task) and the upstream javaagent jar; duplicates are removed + shadowJar { + configurations = listOf(bootstrapLibs, upstreamAgent) + + from(isolateJavaagentLibs) + + archiveClassifier.set("") + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + mergeServiceFiles("inst/META-INF/services") + // mergeServiceFiles requires that duplicate strategy is set to include + filesMatching("inst/META-INF/services/**") { + duplicatesStrategy = DuplicatesStrategy.INCLUDE + } + + exclude("**/module-info.class") + relocatePackages(this) + + manifest { + attributes["Main-Class"] = "io.opentelemetry.javaagent.OpenTelemetryAgent" + attributes["Agent-Class"] = "io.opentelemetry.javaagent.OpenTelemetryAgent" + attributes["Premain-Class"] = "io.opentelemetry.javaagent.OpenTelemetryAgent" + attributes["Can-Redefine-Classes"] = "true" + attributes["Can-Retransform-Classes"] = "true" + attributes["Implementation-Vendor"] = "Demo" + attributes["Implementation-Version"] = "demo-${project.version}-otel-$opentelemetryJavaagentVersion" + } + } + + assemble { + dependsOn(shadowJar) + } +} diff --git a/examples/distro/custom/build.gradle b/examples/distro/custom/build.gradle.kts similarity index 94% rename from examples/distro/custom/build.gradle rename to examples/distro/custom/build.gradle.kts index 1b1b20ab764e..e0ccd9d0f2d0 100644 --- a/examples/distro/custom/build.gradle +++ b/examples/distro/custom/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id "java" + id("otel.java-conventions") } dependencies { diff --git a/examples/distro/gradle/instrumentation.gradle b/examples/distro/gradle/instrumentation.gradle deleted file mode 100644 index 49778e10b2d5..000000000000 --- a/examples/distro/gradle/instrumentation.gradle +++ /dev/null @@ -1,90 +0,0 @@ -apply plugin: 'java' -apply plugin: 'com.gradleup.shadow' -apply plugin: 'io.opentelemetry.instrumentation.muzzle-generation' -apply plugin: 'io.opentelemetry.instrumentation.muzzle-check' - -apply from: "$rootDir/gradle/shadow.gradle" - -def relocatePackages = ext.relocatePackages - -configurations { - testInstrumentation - testAgent -} - -dependencies { - compileOnly("io.opentelemetry:opentelemetry-sdk") - compileOnly("io.opentelemetry.instrumentation:opentelemetry-instrumentation-api") - compileOnly("io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api") - - annotationProcessor deps.autoservice - compileOnly deps.autoservice - - // the javaagent that is going to be used when running instrumentation unit tests - testAgent(project(path: ":testing:agent-for-testing", configuration: "shadow")) - // test dependencies - testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common") - testImplementation("io.opentelemetry:opentelemetry-sdk-testing") - testImplementation("org.assertj:assertj-core:3.27.7") - - add("codegen", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${versions.opentelemetryJavaagentAlpha}") - add("muzzleBootstrap", "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations-support:${versions.opentelemetryJavaagentAlpha}") - add("muzzleTooling", "io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:${versions.opentelemetryJavaagentAlpha}") - add("muzzleTooling", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:${versions.opentelemetryJavaagentAlpha}") -} - -shadowJar { - configurations = [project.configurations.runtimeClasspath, project.configurations.testInstrumentation] - - mergeServiceFiles() - // mergeServiceFiles requires that duplicate strategy is set to include - filesMatching("META-INF/services/**") { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - } - - archiveFileName = 'agent-testing.jar' - - relocatePackages(it) -} - -tasks.withType(Test).configureEach { - inputs.file(shadowJar.archiveFile) - - jvmArgs "-Dotel.javaagent.debug=true" - jvmArgs "-Dotel.javaagent.experimental.initializer.jar=${shadowJar.archiveFile.get().asFile.absolutePath}" - jvmArgs "-Dotel.javaagent.testing.additional-library-ignores.enabled=false" - jvmArgs "-Dotel.javaagent.testing.fail-on-context-leak=true" - // prevent sporadic gradle deadlocks, see SafeLogger for more details - jvmArgs "-Dotel.javaagent.testing.transform-safe-logging.enabled=true" - - jvmArgumentProviders.add(new JavaagentProvider(project.providers.provider { - configurations.testAgent.files.first() - })) - - dependsOn shadowJar - dependsOn configurations.testAgent.buildDependencies - - // The sources are packaged into the testing jar so we need to make sure to exclude from the test - // classpath, which automatically inherits them, to ensure our shaded versions are used. - classpath = classpath.filter { - if (it == file(layout.buildDirectory.dir("resources/main")) || it == file(layout.buildDirectory.dir("classes/java/main"))) { - return false - } - return true - } -} - -class JavaagentProvider implements CommandLineArgumentProvider { - @InputFile - @PathSensitive(PathSensitivity.RELATIVE) - Provider agentJar - - JavaagentProvider(Provider agentJar) { - this.agentJar = agentJar - } - - @Override - Iterable asArguments() { - return ["-javaagent:${agentJar.get().absolutePath}"] - } -} diff --git a/examples/distro/instrumentation/build.gradle b/examples/distro/instrumentation/build.gradle deleted file mode 100644 index 9d1a69144a12..000000000000 --- a/examples/distro/instrumentation/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ -Project instr_project = project -subprojects { - afterEvaluate { Project subProj -> - if (subProj.getPlugins().hasPlugin('java')) { - // Make it so all instrumentation subproject tests can be run with a single command. - instr_project.tasks.test.dependsOn(subProj.tasks.test) - - instr_project.dependencies { - implementation(project(subProj.getPath())) - } - } - } -} diff --git a/examples/distro/instrumentation/servlet-3/build.gradle b/examples/distro/instrumentation/servlet-3/build.gradle deleted file mode 100644 index 3df331845575..000000000000 --- a/examples/distro/instrumentation/servlet-3/build.gradle +++ /dev/null @@ -1,34 +0,0 @@ -apply from: "$rootDir/gradle/instrumentation.gradle" - -muzzle { - pass { - group.set("javax.servlet") - module.set("javax.servlet-api") - versions.set("[3.0,)") - assertInverse.set(true) - } - pass { - group.set("javax.servlet") - module.set("servlet-api") - versions.set("[2.2, 3.0)") - assertInverse.set(true) - } -} - -dependencies { - compileOnly project(":bootstrap") - compileOnly "javax.servlet:javax.servlet-api:3.0.1" - - testInstrumentation "io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-common:${versions.opentelemetryJavaagentAlpha}" - testInstrumentation "io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-2.2:${versions.opentelemetryJavaagentAlpha}" - testInstrumentation "io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-3.0:${versions.opentelemetryJavaagentAlpha}" - - testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common") { - exclude group: 'org.eclipse.jetty', module: 'jetty-server' - } - - testImplementation "com.squareup.okhttp3:okhttp:5.3.2" - testImplementation "javax.servlet:javax.servlet-api:3.0.1" - testImplementation "org.eclipse.jetty:jetty-server:8.2.0.v20160908" - testImplementation "org.eclipse.jetty:jetty-servlet:8.2.0.v20160908" -} diff --git a/examples/distro/instrumentation/servlet-3/build.gradle.kts b/examples/distro/instrumentation/servlet-3/build.gradle.kts new file mode 100644 index 000000000000..60c620379585 --- /dev/null +++ b/examples/distro/instrumentation/servlet-3/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + id("otel.instrumentation-conventions") + id("io.opentelemetry.instrumentation.muzzle-generation") + id("io.opentelemetry.instrumentation.muzzle-check") +} + +muzzle { + pass { + group.set("javax.servlet") + module.set("javax.servlet-api") + versions.set("[3.0,)") + assertInverse.set(true) + } + pass { + group.set("javax.servlet") + module.set("servlet-api") + versions.set("[2.2, 3.0)") + assertInverse.set(true) + } +} + +dependencies { + compileOnly(project(":bootstrap")) + compileOnly("javax.servlet:javax.servlet-api:3.0.1") + + add("codegen", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:$opentelemetryJavaagentAlphaVersion") + add("muzzleBootstrap", "io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations-support:$opentelemetryJavaagentAlphaVersion") + add("muzzleTooling", "io.opentelemetry.javaagent:opentelemetry-javaagent-extension-api:$opentelemetryJavaagentAlphaVersion") + add("muzzleTooling", "io.opentelemetry.javaagent:opentelemetry-javaagent-tooling:$opentelemetryJavaagentAlphaVersion") + + testInstrumentation("io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-common:$opentelemetryJavaagentAlphaVersion") + testInstrumentation("io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-2.2:$opentelemetryJavaagentAlphaVersion") + testInstrumentation("io.opentelemetry.javaagent.instrumentation:opentelemetry-javaagent-servlet-3.0:$opentelemetryJavaagentAlphaVersion") + + testImplementation("io.opentelemetry.javaagent:opentelemetry-testing-common") { + exclude(group = "org.eclipse.jetty", module = "jetty-server") + } + + testImplementation("com.squareup.okhttp3:okhttp:5.3.2") + testImplementation("javax.servlet:javax.servlet-api:3.0.1") + testImplementation("org.eclipse.jetty:jetty-server:8.2.0.v20160908") + testImplementation("org.eclipse.jetty:jetty-servlet:8.2.0.v20160908") +} diff --git a/examples/distro/settings.gradle b/examples/distro/settings.gradle deleted file mode 100644 index f1e44d1ed1e9..000000000000 --- a/examples/distro/settings.gradle +++ /dev/null @@ -1,19 +0,0 @@ -pluginManagement { - repositories { - gradlePluginPortal() - maven { - name = "sonatype" - url = uri("https://central.sonatype.com/repository/maven-snapshots/") - } - } -} - -rootProject.name = 'opentelemetry-java-instrumentation-distro-demo' - -include "agent" -include "bootstrap" -include "custom" -include "instrumentation" -include "instrumentation:servlet-3" -include "smoke-tests" -include "testing:agent-for-testing" diff --git a/examples/distro/settings.gradle.kts b/examples/distro/settings.gradle.kts new file mode 100644 index 000000000000..5ef1deaad715 --- /dev/null +++ b/examples/distro/settings.gradle.kts @@ -0,0 +1,24 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = "sonatype" + url = uri("https://central.sonatype.com/repository/maven-snapshots/") + } + } + plugins { + id("com.gradleup.shadow") version "9.4.1" + id("io.opentelemetry.instrumentation.muzzle-generation") version "2.28.0-alpha-SNAPSHOT" + id("io.opentelemetry.instrumentation.muzzle-check") version "2.28.0-alpha-SNAPSHOT" + } +} + +rootProject.name = "opentelemetry-java-instrumentation-distro-demo" + +include("agent") +include("bootstrap") +include("custom") +include("instrumentation") +include("instrumentation:servlet-3") +include("smoke-tests") +include("testing:agent-for-testing") diff --git a/examples/distro/smoke-tests/build.gradle b/examples/distro/smoke-tests/build.gradle.kts similarity index 78% rename from examples/distro/smoke-tests/build.gradle rename to examples/distro/smoke-tests/build.gradle.kts index 983302ffd80b..4a4aef0d641f 100644 --- a/examples/distro/smoke-tests/build.gradle +++ b/examples/distro/smoke-tests/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id "java" + id("otel.java-conventions") } dependencies { @@ -15,15 +15,12 @@ dependencies { } tasks.test { - useJUnitPlatform() - testLogging.showStandardStreams = true - def shadowTask = project(":agent").tasks.shadowJar - dependsOn(shadowTask) - inputs.files(layout.files(shadowTask)) + val agentJar = project(":agent").tasks.named("shadowJar").flatMap { it.archiveFile } + inputs.file(agentJar) doFirst { - jvmArgs("-Dio.opentelemetry.smoketest.agent.shadowJar.path=${shadowTask.archiveFile.get()}") + jvmArgs("-Dio.opentelemetry.smoketest.agent.shadowJar.path=${agentJar.get().asFile}") } } diff --git a/examples/distro/testing/agent-for-testing/build.gradle b/examples/distro/testing/agent-for-testing/build.gradle deleted file mode 100644 index fcf243ef22d5..000000000000 --- a/examples/distro/testing/agent-for-testing/build.gradle +++ /dev/null @@ -1,131 +0,0 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar - -plugins { - id("com.gradleup.shadow") -} - -apply from: "$rootDir/gradle/shadow.gradle" - -def relocatePackages = ext.relocatePackages - -configurations { - // this configuration collects libs that will be placed in the bootstrap classloader - bootstrapLibs { - canBeResolved = true - canBeConsumed = false - } - // this configuration collects libs that will be placed in the agent classloader, isolated from the instrumented application code - javaagentLibs { - canBeResolved = true - canBeConsumed = false - } - // this configuration stores the upstream agent dep that's extended by this project - upstreamAgent { - canBeResolved = true - canBeConsumed = false - } -} - -dependencies { - bootstrapLibs(project(":bootstrap")) - // and finally include everything from otel agent for testing - upstreamAgent("io.opentelemetry.javaagent:opentelemetry-agent-for-testing:${versions.opentelemetryJavaagentAlpha}") -} - -CopySpec isolateClasses(Iterable jars) { - return copySpec { - jars.forEach { - from(zipTree(it)) { - into("inst") - rename("^(.*)\\.class\$", "\$1.classdata") - // Rename LICENSE file since it clashes with license dir on non-case sensitive FSs (i.e. Mac) - rename("^LICENSE\$", "LICENSE.renamed") - exclude("META-INF/INDEX.LIST") - exclude("META-INF/*.DSA") - exclude("META-INF/*.SF") - } - } - } -} - -tasks { - jar { - enabled = false - } - - // building the final javaagent jar is done in 3 steps: - - // 1. all distro specific javaagent libs are relocated - task relocateJavaagentLibs(type: ShadowJar) { - configurations = [project.configurations.javaagentLibs] - - archiveFileName.set("javaagentLibs-relocated.jar") - - duplicatesStrategy = DuplicatesStrategy.FAIL - mergeServiceFiles() - // mergeServiceFiles requires that duplicate strategy is set to include - filesMatching("META-INF/services/**") { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - } - - exclude("**/module-info.class") - relocatePackages(it) - - // exclude known bootstrap dependencies - they can't appear in the inst/ directory - dependencies { - exclude("io.opentelemetry:opentelemetry-api") - exclude("io.opentelemetry:opentelemetry-common") - exclude("io.opentelemetry:opentelemetry-context") - exclude("io.opentelemetry.semconv:opentelemetry-semconv") - exclude("io.opentelemetry.semconv:opentelemetry-semconv-incubating") - // events API and metrics advice API - exclude("io.opentelemetry:opentelemetry-api-incubator") - } - } - - // 2. the distro javaagent libs are then isolated - moved to the inst/ directory - // having a separate task for isolating javaagent libs is required to avoid duplicates with the upstream javaagent - // duplicatesStrategy in shadowJar won't be applied when adding files with with(CopySpec) because each CopySpec has - // its own duplicatesStrategy - task isolateJavaagentLibs(type: Copy) { - dependsOn(tasks.relocateJavaagentLibs) - with isolateClasses(tasks.relocateJavaagentLibs.outputs.files) - - into(layout.buildDirectory.dir("isolated/javaagentLibs")) - } - - // 3. the relocated and isolated javaagent libs are merged together with the bootstrap libs (which undergo relocation - // in this task) and the upstream javaagent jar; duplicates are removed - shadowJar { - configurations = [project.configurations.bootstrapLibs, project.configurations.upstreamAgent] - - dependsOn(tasks.isolateJavaagentLibs) - from(tasks.isolateJavaagentLibs.outputs) - - archiveClassifier.set("") - - duplicatesStrategy = DuplicatesStrategy.EXCLUDE - mergeServiceFiles("inst/META-INF/services") - // mergeServiceFiles requires that duplicate strategy is set to include - filesMatching("inst/META-INF/services/**") { - duplicatesStrategy = DuplicatesStrategy.INCLUDE - } - - exclude("**/module-info.class") - relocatePackages(it) - - manifest { - attributes.put("Main-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") - attributes.put("Agent-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") - attributes.put("Premain-Class", "io.opentelemetry.javaagent.OpenTelemetryAgent") - attributes.put("Can-Redefine-Classes", "true") - attributes.put("Can-Retransform-Classes", "true") - attributes.put("Implementation-Vendor", "Demo") - attributes.put("Implementation-Version", "demo-${project.version}-otel-${versions.opentelemetryJavaagent}") - } - } - - assemble { - dependsOn(shadowJar) - } -} diff --git a/examples/distro/testing/agent-for-testing/build.gradle.kts b/examples/distro/testing/agent-for-testing/build.gradle.kts new file mode 100644 index 000000000000..0d052b6a192c --- /dev/null +++ b/examples/distro/testing/agent-for-testing/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + id("otel.javaagent-shadow-conventions") +} + +dependencies { + bootstrapLibs(project(":bootstrap")) + // and finally include everything from otel agent for testing + upstreamAgent("io.opentelemetry.javaagent:opentelemetry-agent-for-testing:$opentelemetryJavaagentAlphaVersion") +} diff --git a/examples/extension/settings.gradle b/examples/extension/settings.gradle.kts similarity index 72% rename from examples/extension/settings.gradle rename to examples/extension/settings.gradle.kts index ab717f2427bb..b68c31827a83 100644 --- a/examples/extension/settings.gradle +++ b/examples/extension/settings.gradle.kts @@ -8,4 +8,4 @@ pluginManagement { } } -rootProject.name = 'opentelemetry-java-instrumentation-extension-demo' +rootProject.name = "opentelemetry-java-instrumentation-extension-demo"