build.gradle.kts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
  2. import com.github.jk1.license.filter.LicenseBundleNormalizer
  3. import com.github.jk1.license.render.InventoryMarkdownReportRenderer
  4. import org.spdx.sbom.gradle.SpdxSbomTask
  5. import java.util.UUID
  6. plugins {
  7. id("com.github.jk1.dependency-license-report")
  8. id("otel.java-conventions")
  9. id("otel.publish-conventions")
  10. id("io.opentelemetry.instrumentation.javaagent-shadowing")
  11. id("org.spdx.sbom")
  12. }
  13. description = "OpenTelemetry Javaagent"
  14. group = "io.opentelemetry.javaagent"
  15. // this configuration collects libs that will be placed in the bootstrap classloader
  16. val bootstrapLibs by configurations.creating {
  17. isCanBeResolved = true
  18. isCanBeConsumed = false
  19. }
  20. // this configuration collects only required instrumentations and agent machinery
  21. val baseJavaagentLibs by configurations.creating {
  22. isCanBeResolved = true
  23. isCanBeConsumed = false
  24. }
  25. // this configuration collects libs that will be placed in the agent classloader, isolated from the instrumented application code
  26. val javaagentLibs by configurations.creating {
  27. isCanBeResolved = true
  28. isCanBeConsumed = false
  29. extendsFrom(baseJavaagentLibs)
  30. }
  31. // exclude dependencies that are to be placed in bootstrap from agent libs - they won't be added to inst/
  32. listOf(baseJavaagentLibs, javaagentLibs).forEach {
  33. it.run {
  34. exclude("io.opentelemetry", "opentelemetry-api")
  35. exclude("io.opentelemetry.semconv", "opentelemetry-semconv")
  36. exclude("io.opentelemetry.semconv", "opentelemetry-semconv-incubating")
  37. // events API and metrics advice API
  38. exclude("io.opentelemetry", "opentelemetry-api-incubator")
  39. }
  40. }
  41. val licenseReportDependencies by configurations.creating {
  42. extendsFrom(bootstrapLibs)
  43. extendsFrom(baseJavaagentLibs)
  44. }
  45. dependencies {
  46. bootstrapLibs(project(":instrumentation-api"))
  47. // opentelemetry-api is an api dependency of :instrumentation-api, but opentelemetry-api-incubator is not
  48. bootstrapLibs("io.opentelemetry:opentelemetry-api-incubator")
  49. bootstrapLibs(project(":instrumentation-api-incubator"))
  50. bootstrapLibs(project(":instrumentation-annotations-support"))
  51. bootstrapLibs(project(":javaagent-bootstrap"))
  52. // extension-api contains both bootstrap packages and agent packages
  53. bootstrapLibs(project(":javaagent-extension-api")) {
  54. // exclude javaagent dependencies from the bootstrap classpath
  55. exclude("net.bytebuddy")
  56. exclude("org.ow2.asm")
  57. exclude("io.opentelemetry", "opentelemetry-sdk")
  58. exclude("io.opentelemetry", "opentelemetry-sdk-extension-autoconfigure")
  59. exclude("io.opentelemetry", "opentelemetry-sdk-extension-autoconfigure-spi")
  60. }
  61. baseJavaagentLibs(project(":javaagent-extension-api"))
  62. baseJavaagentLibs(project(":javaagent-tooling"))
  63. baseJavaagentLibs(project(":javaagent-internal-logging-application"))
  64. baseJavaagentLibs(project(":javaagent-internal-logging-simple", configuration = "shadow"))
  65. baseJavaagentLibs(project(":muzzle"))
  66. baseJavaagentLibs(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.0:javaagent"))
  67. baseJavaagentLibs(project(":instrumentation:opentelemetry-api:opentelemetry-api-1.4:javaagent"))
  68. baseJavaagentLibs(project(":instrumentation:opentelemetry-instrumentation-api:javaagent"))
  69. baseJavaagentLibs(project(":instrumentation:opentelemetry-instrumentation-annotations-1.16:javaagent"))
  70. baseJavaagentLibs(project(":instrumentation:executors:javaagent"))
  71. baseJavaagentLibs(project(":instrumentation:internal:internal-application-logger:javaagent"))
  72. baseJavaagentLibs(project(":instrumentation:internal:internal-class-loader:javaagent"))
  73. baseJavaagentLibs(project(":instrumentation:internal:internal-eclipse-osgi-3.6:javaagent"))
  74. baseJavaagentLibs(project(":instrumentation:internal:internal-lambda:javaagent"))
  75. baseJavaagentLibs(project(":instrumentation:internal:internal-reflection:javaagent"))
  76. baseJavaagentLibs(project(":instrumentation:internal:internal-url-class-loader:javaagent"))
  77. // concurrentlinkedhashmap-lru and weak-lock-free are copied in to the instrumentation-api module
  78. licenseReportDependencies("com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:1.4.2")
  79. licenseReportDependencies("com.blogspot.mydailyjava:weak-lock-free:0.18")
  80. licenseReportDependencies(project(":javaagent-internal-logging-simple")) // need the non-shadow versions
  81. testCompileOnly(project(":javaagent-bootstrap"))
  82. testCompileOnly(project(":javaagent-extension-api"))
  83. testImplementation(project(":testing-common"))
  84. testImplementation("io.opentracing.contrib.dropwizard:dropwizard-opentracing:0.2.2")
  85. }
  86. val javaagentDependencies = dependencies
  87. // collect all bootstrap and javaagent instrumentation dependencies
  88. project(":instrumentation").subprojects {
  89. val subProj = this
  90. plugins.withId("otel.javaagent-bootstrap") {
  91. javaagentDependencies.run {
  92. add(bootstrapLibs.name, project(subProj.path))
  93. }
  94. }
  95. plugins.withId("otel.javaagent-instrumentation") {
  96. javaagentDependencies.run {
  97. add(javaagentLibs.name, project(subProj.path))
  98. }
  99. }
  100. plugins.withId("otel.sdk-extension") {
  101. javaagentDependencies.run {
  102. add(javaagentLibs.name, project(subProj.path))
  103. }
  104. }
  105. }
  106. tasks {
  107. processResources {
  108. from(rootProject.file("licenses")) {
  109. into("META-INF/licenses")
  110. }
  111. }
  112. val buildBootstrapLibs by registering(ShadowJar::class) {
  113. configurations = listOf(bootstrapLibs)
  114. // exclude the agent part of the javaagent-extension-api; these classes will be added in relocate tasks
  115. exclude("io/opentelemetry/javaagent/extension/**")
  116. duplicatesStrategy = DuplicatesStrategy.EXCLUDE
  117. archiveFileName.set("bootstrapLibs.jar")
  118. }
  119. val relocateBaseJavaagentLibs by registering(ShadowJar::class) {
  120. configurations = listOf(baseJavaagentLibs)
  121. excludeBootstrapClasses()
  122. duplicatesStrategy = DuplicatesStrategy.FAIL
  123. archiveFileName.set("baseJavaagentLibs-relocated.jar")
  124. }
  125. val relocateJavaagentLibs by registering(ShadowJar::class) {
  126. configurations = listOf(javaagentLibs)
  127. excludeBootstrapClasses()
  128. duplicatesStrategy = DuplicatesStrategy.FAIL
  129. archiveFileName.set("javaagentLibs-relocated.jar")
  130. }
  131. // Includes everything needed for OOTB experience
  132. val shadowJar by existing(ShadowJar::class) {
  133. dependsOn(buildBootstrapLibs)
  134. from(zipTree(buildBootstrapLibs.get().archiveFile))
  135. dependsOn(relocateJavaagentLibs)
  136. isolateClasses(relocateJavaagentLibs.get().archiveFile)
  137. duplicatesStrategy = DuplicatesStrategy.FAIL
  138. archiveClassifier.set("")
  139. manifest {
  140. attributes(jar.get().manifest.attributes)
  141. attributes(
  142. "Main-Class" to "io.opentelemetry.javaagent.OpenTelemetryAgent",
  143. "Agent-Class" to "io.opentelemetry.javaagent.OpenTelemetryAgent",
  144. "Premain-Class" to "io.opentelemetry.javaagent.OpenTelemetryAgent",
  145. "Can-Redefine-Classes" to true,
  146. "Can-Retransform-Classes" to true,
  147. )
  148. }
  149. }
  150. // Includes only the agent machinery and required instrumentations
  151. val baseJavaagentJar by registering(ShadowJar::class) {
  152. dependsOn(buildBootstrapLibs)
  153. from(zipTree(buildBootstrapLibs.get().archiveFile))
  154. dependsOn(relocateBaseJavaagentLibs)
  155. isolateClasses(relocateBaseJavaagentLibs.get().archiveFile)
  156. duplicatesStrategy = DuplicatesStrategy.FAIL
  157. archiveClassifier.set("base")
  158. manifest {
  159. attributes(shadowJar.get().manifest.attributes)
  160. }
  161. }
  162. jar {
  163. // Empty jar that cannot be used for anything and isn't published.
  164. archiveClassifier.set("dontuse")
  165. }
  166. val baseJar by configurations.creating {
  167. isCanBeConsumed = true
  168. isCanBeResolved = false
  169. }
  170. artifacts {
  171. add("baseJar", baseJavaagentJar)
  172. }
  173. assemble {
  174. dependsOn(shadowJar, baseJavaagentJar)
  175. }
  176. if (findProperty("removeJarVersionNumbers") == "true") {
  177. withType<AbstractArchiveTask>().configureEach {
  178. archiveVersion.set("")
  179. }
  180. }
  181. withType<Test>().configureEach {
  182. dependsOn(shadowJar)
  183. jvmArgs("-Dotel.javaagent.debug=true")
  184. jvmArgumentProviders.add(JavaagentProvider(shadowJar.flatMap { it.archiveFile }))
  185. testLogging {
  186. events("started")
  187. }
  188. }
  189. val cleanLicenses by registering(Delete::class) {
  190. delete(rootProject.file("licenses"))
  191. }
  192. val generateLicenseReportEnabled =
  193. gradle.startParameter.taskNames.any { it.equals("generateLicenseReport") }
  194. named("generateLicenseReport").configure {
  195. dependsOn(cleanLicenses)
  196. finalizedBy(":spotlessApply")
  197. // disable licence report generation unless this task is explicitly run
  198. // the files produced by this task are used by other tasks without declaring them as dependency
  199. // which gradle considers an error
  200. enabled = enabled && generateLicenseReportEnabled
  201. }
  202. if (generateLicenseReportEnabled) {
  203. project.parent?.tasks?.getByName("spotlessMisc")?.dependsOn(named("generateLicenseReport"))
  204. }
  205. // Because we reconfigure publishing to only include the shadow jar, the Gradle metadata is not correct.
  206. // Since we are fully bundled and have no dependencies, Gradle metadata wouldn't provide any advantage over
  207. // the POM anyways so in practice we shouldn't be losing anything.
  208. withType<GenerateModuleMetadata>().configureEach {
  209. enabled = false
  210. }
  211. }
  212. // Don't publish non-shadowed jar (shadowJar is in shadowRuntimeElements)
  213. with(components["java"] as AdhocComponentWithVariants) {
  214. configurations.forEach {
  215. withVariantsFromConfiguration(configurations["apiElements"]) {
  216. skip()
  217. }
  218. withVariantsFromConfiguration(configurations["runtimeElements"]) {
  219. skip()
  220. }
  221. }
  222. }
  223. spdxSbom {
  224. targets {
  225. // Create a target to match the published jar name.
  226. // This is used for the task name (spdxSbomFor<SbomName>)
  227. // and output file (<sbomName>.spdx.json).
  228. create("opentelemetry-javaagent") {
  229. configurations.set(listOf("baseJavaagentLibs"))
  230. scm {
  231. uri.set("https://github.com/" + System.getenv("GITHUB_REPOSITORY"))
  232. revision.set(System.getenv("GITHUB_SHA"))
  233. }
  234. document {
  235. name.set("opentelemetry-javaagent")
  236. namespace.set("https://opentelemetry.io/spdx/" + UUID.randomUUID())
  237. }
  238. }
  239. }
  240. }
  241. tasks.withType<AbstractPublishToMaven> {
  242. dependsOn("spdxSbom")
  243. }
  244. project.afterEvaluate {
  245. tasks.withType<Sign>().configureEach {
  246. mustRunAfter(tasks.withType<SpdxSbomTask>())
  247. }
  248. tasks.withType<PublishToMavenLocal>().configureEach {
  249. this.publication.artifact("${layout.buildDirectory.get()}/spdx/opentelemetry-javaagent.spdx.json") {
  250. classifier = "spdx"
  251. extension = "json"
  252. }
  253. }
  254. }
  255. licenseReport {
  256. outputDir = rootProject.file("licenses").absolutePath
  257. renderers = arrayOf(InventoryMarkdownReportRenderer())
  258. configurations = arrayOf(licenseReportDependencies.name)
  259. excludeBoms = true
  260. excludeGroups = arrayOf(
  261. "io\\.opentelemetry\\.instrumentation",
  262. "io\\.opentelemetry\\.javaagent",
  263. "io\\.opentelemetry\\.dummy\\..*",
  264. )
  265. excludes = arrayOf(
  266. "io.opentelemetry:opentelemetry-bom-alpha",
  267. "opentelemetry-java-instrumentation:dependencyManagement",
  268. )
  269. filters = arrayOf(LicenseBundleNormalizer("$projectDir/license-normalizer-bundle.json", true))
  270. }
  271. fun CopySpec.isolateClasses(jar: Provider<RegularFile>) {
  272. from(zipTree(jar)) {
  273. // important to keep prefix "inst" short, as it is prefixed to lots of strings in runtime mem
  274. into("inst")
  275. rename("(^.*)\\.class\$", "\$1.classdata")
  276. // Rename LICENSE file since it clashes with license dir on non-case sensitive FSs (i.e. Mac)
  277. rename("""^LICENSE$""", "LICENSE.renamed")
  278. exclude("META-INF/INDEX.LIST")
  279. exclude("META-INF/*.DSA")
  280. exclude("META-INF/*.SF")
  281. }
  282. }
  283. // exclude bootstrap projects from javaagent libs - they won't be added to inst/
  284. fun ShadowJar.excludeBootstrapClasses() {
  285. dependencies {
  286. exclude(project(":instrumentation-api"))
  287. exclude(project(":instrumentation-api-incubator"))
  288. exclude(project(":instrumentation-annotations-support"))
  289. exclude(project(":javaagent-bootstrap"))
  290. }
  291. // exclude the bootstrap part of the javaagent-extension-api
  292. exclude("io/opentelemetry/javaagent/bootstrap/**")
  293. }
  294. class JavaagentProvider(
  295. @InputFile
  296. @PathSensitive(PathSensitivity.RELATIVE)
  297. val agentJar: Provider<RegularFile>,
  298. ) : CommandLineArgumentProvider {
  299. override fun asArguments(): Iterable<String> = listOf(
  300. "-javaagent:${file(agentJar).absolutePath}",
  301. )
  302. }