build.gradle.kts 11 KB

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