1*a24ffb47SSadaf Ebrahimiplugins { 2*a24ffb47SSadaf Ebrahimi id 'com.github.johnrengelman.shadow' version '2.0.2' 3*a24ffb47SSadaf Ebrahimi} 4*a24ffb47SSadaf Ebrahimi 5*a24ffb47SSadaf Ebrahimidescription = 'OpenCensus Agent' 6*a24ffb47SSadaf Ebrahimi 7*a24ffb47SSadaf Ebrahimidef agentPackage = 'io.opencensus.contrib.agent' 8*a24ffb47SSadaf Ebrahimidef agentMainClass = "${agentPackage}.AgentMain" 9*a24ffb47SSadaf Ebrahimi 10*a24ffb47SSadaf Ebrahimi// The package containing the classes that need to be loaded by the bootstrap classloader because 11*a24ffb47SSadaf Ebrahimi// they are used from classes loaded by the bootstrap classloader. 12*a24ffb47SSadaf Ebrahimidef agentBootstrapPackage = "${agentPackage}.bootstrap" 13*a24ffb47SSadaf Ebrahimidef agentBootstrapPackageDir = agentBootstrapPackage.replace('.', '/') + '/' 14*a24ffb47SSadaf Ebrahimidef agentBootstrapClasses = agentBootstrapPackageDir + '**' 15*a24ffb47SSadaf Ebrahimi 16*a24ffb47SSadaf Ebrahimi// The package to which we relocate all third party packages. This avoids any conflicts of the 17*a24ffb47SSadaf Ebrahimi// agent's classes with the app's classes, which are loaded by the same classloader (the system 18*a24ffb47SSadaf Ebrahimi// classloader). 19*a24ffb47SSadaf Ebrahimidef agentRepackaged = "${agentPackage}.deps" 20*a24ffb47SSadaf Ebrahimi 21*a24ffb47SSadaf Ebrahimidependencies { 22*a24ffb47SSadaf Ebrahimi compileOnly libraries.auto_service 23*a24ffb47SSadaf Ebrahimi compileOnly libraries.findbugs_annotations 24*a24ffb47SSadaf Ebrahimi compileOnly libraries.grpc_context 25*a24ffb47SSadaf Ebrahimi compileOnly project(':opencensus-api') 26*a24ffb47SSadaf Ebrahimi compile libraries.byte_buddy 27*a24ffb47SSadaf Ebrahimi compile libraries.config 28*a24ffb47SSadaf Ebrahimi compile libraries.guava 29*a24ffb47SSadaf Ebrahimi 30*a24ffb47SSadaf Ebrahimi signature 'org.codehaus.mojo.signature:java17:1.0@signature' 31*a24ffb47SSadaf Ebrahimi} 32*a24ffb47SSadaf Ebrahimi 33*a24ffb47SSadaf Ebrahimijar { 34*a24ffb47SSadaf Ebrahimi manifest { 35*a24ffb47SSadaf Ebrahimi // Set the required manifest attributes for the Java agent, cf. 36*a24ffb47SSadaf Ebrahimi // https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html. 37*a24ffb47SSadaf Ebrahimi attributes 'Premain-Class': agentMainClass 38*a24ffb47SSadaf Ebrahimi attributes 'Can-Retransform-Classes': true 39*a24ffb47SSadaf Ebrahimi } 40*a24ffb47SSadaf Ebrahimi} 41*a24ffb47SSadaf Ebrahimi 42*a24ffb47SSadaf Ebrahimi// Create bootstrap.jar containing the classes that need to be loaded by the bootstrap 43*a24ffb47SSadaf Ebrahimi// classloader. 44*a24ffb47SSadaf Ebrahimitask bootstrapJar(type: Jar) { 45*a24ffb47SSadaf Ebrahimi // Output to 'bootstrap.jar'. 46*a24ffb47SSadaf Ebrahimi baseName = 'bootstrap' 47*a24ffb47SSadaf Ebrahimi version = null 48*a24ffb47SSadaf Ebrahimi 49*a24ffb47SSadaf Ebrahimi from sourceSets.main.output 50*a24ffb47SSadaf Ebrahimi include agentBootstrapClasses 51*a24ffb47SSadaf Ebrahimi} 52*a24ffb47SSadaf Ebrahimi 53*a24ffb47SSadaf EbrahimishadowJar.dependsOn bootstrapJar 54*a24ffb47SSadaf Ebrahimi 55*a24ffb47SSadaf Ebrahimi// Bundle the agent's classes and dependencies into a single, self-contained JAR file. 56*a24ffb47SSadaf EbrahimishadowJar { 57*a24ffb47SSadaf Ebrahimi // Output to opencensus-contrib-agent-VERSION.jar. 58*a24ffb47SSadaf Ebrahimi classifier = null 59*a24ffb47SSadaf Ebrahimi 60*a24ffb47SSadaf Ebrahimi // Include only the following dependencies (excluding transitive dependencies). 61*a24ffb47SSadaf Ebrahimi dependencies { 62*a24ffb47SSadaf Ebrahimi include(dependency(libraries.byte_buddy)) 63*a24ffb47SSadaf Ebrahimi include(dependency(libraries.config)) 64*a24ffb47SSadaf Ebrahimi include(dependency(libraries.guava)) 65*a24ffb47SSadaf Ebrahimi } 66*a24ffb47SSadaf Ebrahimi 67*a24ffb47SSadaf Ebrahimi // Exclude cruft which still snuck in. 68*a24ffb47SSadaf Ebrahimi exclude 'META-INF/maven/**' 69*a24ffb47SSadaf Ebrahimi exclude agentBootstrapClasses 70*a24ffb47SSadaf Ebrahimi 71*a24ffb47SSadaf Ebrahimi // Relocate third party packages to avoid any conflicts of the agent's classes with the app's 72*a24ffb47SSadaf Ebrahimi // classes, which are loaded by the same classloader (the system classloader). 73*a24ffb47SSadaf Ebrahimi // Byte Buddy: 74*a24ffb47SSadaf Ebrahimi relocate 'net.bytebuddy', agentRepackaged + '.bytebuddy' 75*a24ffb47SSadaf Ebrahimi // Config: 76*a24ffb47SSadaf Ebrahimi relocate 'com.typesafe.config', agentRepackaged + '.config' 77*a24ffb47SSadaf Ebrahimi // Guava: 78*a24ffb47SSadaf Ebrahimi relocate 'com.google.common', agentRepackaged + '.guava' 79*a24ffb47SSadaf Ebrahimi relocate 'com.google.thirdparty.publicsuffix', agentRepackaged + '.publicsuffix' 80*a24ffb47SSadaf Ebrahimi 81*a24ffb47SSadaf Ebrahimi doLast { 82*a24ffb47SSadaf Ebrahimi def agentPackageDir = agentPackage.replace('.', '/') + '/' 83*a24ffb47SSadaf Ebrahimi def agentBootstrapJar = agentPackageDir + 'bootstrap.jar' 84*a24ffb47SSadaf Ebrahimi 85*a24ffb47SSadaf Ebrahimi // Bundle bootstrap.jar. 86*a24ffb47SSadaf Ebrahimi ant.jar(update: 'true', destfile: shadowJar.archivePath) { 87*a24ffb47SSadaf Ebrahimi mappedresources { 88*a24ffb47SSadaf Ebrahimi fileset(file: bootstrapJar.archivePath) 89*a24ffb47SSadaf Ebrahimi globmapper(from: '*', to: agentBootstrapJar) 90*a24ffb47SSadaf Ebrahimi } 91*a24ffb47SSadaf Ebrahimi } 92*a24ffb47SSadaf Ebrahimi 93*a24ffb47SSadaf Ebrahimi // Assert that there's nothing obviously wrong with the JAR's contents. 94*a24ffb47SSadaf Ebrahimi new java.util.zip.ZipFile(shadowJar.archivePath).withCloseable { 95*a24ffb47SSadaf Ebrahimi // Must have bundled the bootstrap.jar. 96*a24ffb47SSadaf Ebrahimi assert it.entries().any { it.name == agentBootstrapJar } 97*a24ffb47SSadaf Ebrahimi 98*a24ffb47SSadaf Ebrahimi it.entries().each { entry -> 99*a24ffb47SSadaf Ebrahimi // Must not contain anything outside of ${agentPackage}, ... 100*a24ffb47SSadaf Ebrahimi assert entry.name.startsWith(agentPackageDir) || 101*a24ffb47SSadaf Ebrahimi // ... except for the expected entries. 102*a24ffb47SSadaf Ebrahimi [ agentPackageDir, 103*a24ffb47SSadaf Ebrahimi 'META-INF/MANIFEST.MF', 104*a24ffb47SSadaf Ebrahimi 'META-INF/services/io.opencensus.contrib.agent.instrumentation.Instrumenter', 105*a24ffb47SSadaf Ebrahimi 'reference.conf', 106*a24ffb47SSadaf Ebrahimi ].any { entry.isDirectory() ? it.startsWith(entry.name) : it == entry.name } 107*a24ffb47SSadaf Ebrahimi // Also, should not have the bootstrap classes. 108*a24ffb47SSadaf Ebrahimi assert !entry.name.startsWith(agentBootstrapPackageDir) 109*a24ffb47SSadaf Ebrahimi } 110*a24ffb47SSadaf Ebrahimi } 111*a24ffb47SSadaf Ebrahimi } 112*a24ffb47SSadaf Ebrahimi} 113*a24ffb47SSadaf Ebrahimi 114*a24ffb47SSadaf Ebrahimijar.finalizedBy shadowJar 115*a24ffb47SSadaf Ebrahimi 116*a24ffb47SSadaf Ebrahimi// TODO(stschmidt): Proguard-shrink the agent JAR. 117*a24ffb47SSadaf Ebrahimi 118*a24ffb47SSadaf Ebrahimi// Integration tests. The setup was initially based on 119*a24ffb47SSadaf Ebrahimi// https://www.petrikainulainen.net/programming/gradle/getting-started-with-gradle-integration-testing/. 120*a24ffb47SSadaf Ebrahimi// We run the same suite of integration tests on different Java versions with the agent enabled. 121*a24ffb47SSadaf Ebrahimi// The JAVA_HOMES environment variable lists the home directories of the Java installations used 122*a24ffb47SSadaf Ebrahimi// for integration testing. 123*a24ffb47SSadaf Ebrahimi 124*a24ffb47SSadaf Ebrahimi// The default JAR has been replaced with a self-contained JAR by the shadowJar task. Therefore, 125*a24ffb47SSadaf Ebrahimi// remove all declared dependencies from the generated Maven POM for said JAR. 126*a24ffb47SSadaf EbrahimiuploadArchives { 127*a24ffb47SSadaf Ebrahimi repositories { 128*a24ffb47SSadaf Ebrahimi mavenDeployer { 129*a24ffb47SSadaf Ebrahimi pom.whenConfigured { 130*a24ffb47SSadaf Ebrahimi dependencies = [] 131*a24ffb47SSadaf Ebrahimi } 132*a24ffb47SSadaf Ebrahimi } 133*a24ffb47SSadaf Ebrahimi } 134*a24ffb47SSadaf Ebrahimi} 135*a24ffb47SSadaf Ebrahimi 136*a24ffb47SSadaf EbrahimisourceSets { 137*a24ffb47SSadaf Ebrahimi integrationTest { 138*a24ffb47SSadaf Ebrahimi java { 139*a24ffb47SSadaf Ebrahimi compileClasspath += main.output + test.output 140*a24ffb47SSadaf Ebrahimi runtimeClasspath += main.output + test.output 141*a24ffb47SSadaf Ebrahimi srcDir file('src/integration-test/java') 142*a24ffb47SSadaf Ebrahimi } 143*a24ffb47SSadaf Ebrahimi resources.srcDir file('src/integration-test/resources') 144*a24ffb47SSadaf Ebrahimi } 145*a24ffb47SSadaf Ebrahimi} 146*a24ffb47SSadaf Ebrahimi 147*a24ffb47SSadaf Ebrahimiconfigurations { 148*a24ffb47SSadaf Ebrahimi integrationTestCompile.extendsFrom testCompile 149*a24ffb47SSadaf Ebrahimi integrationTestRuntime.extendsFrom testRuntime 150*a24ffb47SSadaf Ebrahimi} 151*a24ffb47SSadaf Ebrahimi 152*a24ffb47SSadaf Ebrahimidependencies { 153*a24ffb47SSadaf Ebrahimi integrationTestCompile project(':opencensus-api') 154*a24ffb47SSadaf Ebrahimi integrationTestCompile project(':opencensus-testing') 155*a24ffb47SSadaf Ebrahimi integrationTestRuntime libraries.grpc_context 156*a24ffb47SSadaf Ebrahimi integrationTestRuntime project(':opencensus-impl-lite') 157*a24ffb47SSadaf Ebrahimi} 158*a24ffb47SSadaf Ebrahimi 159*a24ffb47SSadaf Ebrahimi// Disable findbugs for integration tests, too. 160*a24ffb47SSadaf EbrahimifindbugsIntegrationTest.enabled = false 161*a24ffb47SSadaf Ebrahimi 162*a24ffb47SSadaf Ebrahimidef javaExecutables = (System.getenv('JAVA_HOMES') ?: '') 163*a24ffb47SSadaf Ebrahimi .tokenize(File.pathSeparator) 164*a24ffb47SSadaf Ebrahimi .plus(System.getProperty('java.home')) 165*a24ffb47SSadaf Ebrahimi .collect { org.apache.tools.ant.taskdefs.condition.Os.isFamily( 166*a24ffb47SSadaf Ebrahimi org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS) 167*a24ffb47SSadaf Ebrahimi ? "${it}/bin/java.exe" 168*a24ffb47SSadaf Ebrahimi : "${it}/bin/java" } 169*a24ffb47SSadaf Ebrahimi .collect { new File(it).getCanonicalPath() } 170*a24ffb47SSadaf Ebrahimi .unique() 171*a24ffb47SSadaf Ebrahimi 172*a24ffb47SSadaf Ebrahimiassert javaExecutables.size > 0 : 173*a24ffb47SSadaf Ebrahimi 'No Java executables found for running integration tests' 174*a24ffb47SSadaf Ebrahimi 175*a24ffb47SSadaf Ebrahimitask integrationTest 176*a24ffb47SSadaf Ebrahimi 177*a24ffb47SSadaf EbrahimijavaExecutables.eachWithIndex { javaExecutable, index -> 178*a24ffb47SSadaf Ebrahimi def perVersionIntegrationTest = task("integrationTest_${index}", type: Test) { 179*a24ffb47SSadaf Ebrahimi testLogging { 180*a24ffb47SSadaf Ebrahimi // Let Gradle output the stdout and stderr from tests, too. This is useful for investigating 181*a24ffb47SSadaf Ebrahimi // test failures on Travis, where we can't view Gradle's test reports. 182*a24ffb47SSadaf Ebrahimi showStandardStreams = true 183*a24ffb47SSadaf Ebrahimi 184*a24ffb47SSadaf Ebrahimi // Include the exception message and full stacktrace for failed tests. 185*a24ffb47SSadaf Ebrahimi exceptionFormat 'full' 186*a24ffb47SSadaf Ebrahimi } 187*a24ffb47SSadaf Ebrahimi 188*a24ffb47SSadaf Ebrahimi dependsOn shadowJar 189*a24ffb47SSadaf Ebrahimi 190*a24ffb47SSadaf Ebrahimi testClassesDirs = sourceSets.integrationTest.output.classesDirs 191*a24ffb47SSadaf Ebrahimi classpath = sourceSets.integrationTest.runtimeClasspath 192*a24ffb47SSadaf Ebrahimi 193*a24ffb47SSadaf Ebrahimi executable = javaExecutable 194*a24ffb47SSadaf Ebrahimi 195*a24ffb47SSadaf Ebrahimi // The JaCoCo agent must be specified first so that it can instrument our agent. 196*a24ffb47SSadaf Ebrahimi // This is a work around for the issue that the JaCoCo agent is added last, cf. 197*a24ffb47SSadaf Ebrahimi // https://discuss.gradle.org/t/jacoco-gradle-adds-the-agent-last-to-jvm-args/7124. 198*a24ffb47SSadaf Ebrahimi doFirst { 199*a24ffb47SSadaf Ebrahimi jvmArgs jacoco.asJvmArg // JaCoCo agent first. 200*a24ffb47SSadaf Ebrahimi jvmArgs "-javaagent:${shadowJar.archivePath}" // Our agent second. 201*a24ffb47SSadaf Ebrahimi jacoco.enabled = false // Don't add the JaCoCo agent again. 202*a24ffb47SSadaf Ebrahimi } 203*a24ffb47SSadaf Ebrahimi 204*a24ffb47SSadaf Ebrahimi doFirst { logger.lifecycle("Running integration tests using ${javaExecutable}.") } 205*a24ffb47SSadaf Ebrahimi } 206*a24ffb47SSadaf Ebrahimi 207*a24ffb47SSadaf Ebrahimi integrationTest.dependsOn perVersionIntegrationTest 208*a24ffb47SSadaf Ebrahimi} 209*a24ffb47SSadaf Ebrahimi 210*a24ffb47SSadaf Ebrahimicheck.dependsOn integrationTest 211*a24ffb47SSadaf EbrahimiintegrationTest.mustRunAfter test 212*a24ffb47SSadaf Ebrahimi 213*a24ffb47SSadaf Ebrahimi// Merge JaCoCo's execution data from all tests into the main test's execution data file. 214*a24ffb47SSadaf Ebrahimitask jacocoMerge(type: JacocoMerge) { 215*a24ffb47SSadaf Ebrahimi tasks.withType(Test).each { testTask -> 216*a24ffb47SSadaf Ebrahimi dependsOn testTask 217*a24ffb47SSadaf Ebrahimi executionData testTask.jacoco.destinationFile 218*a24ffb47SSadaf Ebrahimi } 219*a24ffb47SSadaf Ebrahimi doLast { 220*a24ffb47SSadaf Ebrahimi destinationFile.renameTo test.jacoco.destinationFile 221*a24ffb47SSadaf Ebrahimi } 222*a24ffb47SSadaf Ebrahimi} 223*a24ffb47SSadaf Ebrahimi 224*a24ffb47SSadaf EbrahimijacocoTestReport.dependsOn jacocoMerge 225*a24ffb47SSadaf Ebrahimi 226*a24ffb47SSadaf Ebrahimi// JMH benchmarks 227*a24ffb47SSadaf Ebrahimi 228*a24ffb47SSadaf Ebrahimidependencies { 229*a24ffb47SSadaf Ebrahimi jmh libraries.grpc_context 230*a24ffb47SSadaf Ebrahimi} 231*a24ffb47SSadaf Ebrahimi 232*a24ffb47SSadaf Ebrahimi// Make the agent JAR available using a fixed file name so that we don't have to modify the JMH 233*a24ffb47SSadaf Ebrahimi// benchmarks whenever the version changes. 234*a24ffb47SSadaf Ebrahimitask agentJar(type: Copy) { 235*a24ffb47SSadaf Ebrahimi dependsOn shadowJar 236*a24ffb47SSadaf Ebrahimi 237*a24ffb47SSadaf Ebrahimi from shadowJar.archivePath 238*a24ffb47SSadaf Ebrahimi into libsDir 239*a24ffb47SSadaf Ebrahimi rename { 'agent.jar' } 240*a24ffb47SSadaf Ebrahimi} 241*a24ffb47SSadaf Ebrahimi 242*a24ffb47SSadaf EbrahimijmhJar.dependsOn agentJar 243*a24ffb47SSadaf EbrahimijmhJar.dependsOn integrationTest 244