| plugins { |
| id 'com.github.johnrengelman.shadow' version '2.0.2' |
| } |
| |
| description = 'OpenCensus Agent' |
| |
| def agentPackage = 'io.opencensus.contrib.agent' |
| def agentMainClass = "${agentPackage}.AgentMain" |
| |
| // The package containing the classes that need to be loaded by the bootstrap classloader because |
| // they are used from classes loaded by the bootstrap classloader. |
| def agentBootstrapPackage = "${agentPackage}.bootstrap" |
| def agentBootstrapPackageDir = agentBootstrapPackage.replace('.', '/') + '/' |
| def agentBootstrapClasses = agentBootstrapPackageDir + '**' |
| |
| // The package to which we relocate all third party packages. This avoids any conflicts of the |
| // agent's classes with the app's classes, which are loaded by the same classloader (the system |
| // classloader). |
| def agentRepackaged = "${agentPackage}.deps" |
| |
| dependencies { |
| compileOnly libraries.auto_service |
| compileOnly libraries.grpc_context |
| compileOnly project(':opencensus-api') |
| compile libraries.byte_buddy |
| compile libraries.config |
| compile libraries.findbugs_annotations |
| compile libraries.guava |
| |
| signature 'org.codehaus.mojo.signature:java17:1.0@signature' |
| } |
| |
| jar { |
| manifest { |
| // Set the required manifest attributes for the Java agent, cf. |
| // https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package-summary.html. |
| attributes 'Premain-Class': agentMainClass |
| attributes 'Can-Retransform-Classes': true |
| } |
| } |
| |
| // Create bootstrap.jar containing the classes that need to be loaded by the bootstrap |
| // classloader. |
| task bootstrapJar(type: Jar) { |
| // Output to 'bootstrap.jar'. |
| baseName = 'bootstrap' |
| version = null |
| |
| from sourceSets.main.output |
| include agentBootstrapClasses |
| } |
| |
| shadowJar.dependsOn bootstrapJar |
| |
| // Bundle the agent's classes and dependencies into a single, self-contained JAR file. |
| shadowJar { |
| // Output to opencensus-contrib-agent-VERSION.jar. |
| classifier = null |
| |
| // Include only the following dependencies (excluding transitive dependencies). |
| dependencies { |
| include(dependency(libraries.byte_buddy)) |
| include(dependency(libraries.config)) |
| include(dependency(libraries.guava)) |
| } |
| |
| // Exclude cruft which still snuck in. |
| exclude 'META-INF/maven/**' |
| exclude agentBootstrapClasses |
| |
| // Relocate third party packages to avoid any conflicts of the agent's classes with the app's |
| // classes, which are loaded by the same classloader (the system classloader). |
| // Byte Buddy: |
| relocate 'net.bytebuddy', agentRepackaged + '.bytebuddy' |
| // Config: |
| relocate 'com.typesafe.config', agentRepackaged + '.config' |
| // Guava: |
| relocate 'com.google.common', agentRepackaged + '.guava' |
| relocate 'com.google.thirdparty.publicsuffix', agentRepackaged + '.publicsuffix' |
| |
| doLast { |
| def agentPackageDir = agentPackage.replace('.', '/') + '/' |
| def agentBootstrapJar = agentPackageDir + 'bootstrap.jar' |
| |
| // Bundle bootstrap.jar. |
| ant.jar(update: 'true', destfile: shadowJar.archivePath) { |
| mappedresources { |
| fileset(file: bootstrapJar.archivePath) |
| globmapper(from: '*', to: agentBootstrapJar) |
| } |
| } |
| |
| // Assert that there's nothing obviously wrong with the JAR's contents. |
| new java.util.zip.ZipFile(shadowJar.archivePath).withCloseable { |
| // Must have bundled the bootstrap.jar. |
| assert it.entries().any { it.name == agentBootstrapJar } |
| |
| it.entries().each { entry -> |
| // Must not contain anything outside of ${agentPackage}, ... |
| assert entry.name.startsWith(agentPackageDir) || |
| // ... except for the expected entries. |
| [ agentPackageDir, |
| 'META-INF/MANIFEST.MF', |
| 'META-INF/services/io.opencensus.contrib.agent.instrumentation.Instrumenter', |
| 'reference.conf', |
| ].any { entry.isDirectory() ? it.startsWith(entry.name) : it == entry.name } |
| // Also, should not have the bootstrap classes. |
| assert !entry.name.startsWith(agentBootstrapPackageDir) |
| } |
| } |
| } |
| } |
| |
| jar.finalizedBy shadowJar |
| |
| // TODO(stschmidt): Proguard-shrink the agent JAR. |
| |
| // Integration tests. The setup was initially based on |
| // https://www.petrikainulainen.net/programming/gradle/getting-started-with-gradle-integration-testing/. |
| // We run the same suite of integration tests on different Java versions with the agent enabled. |
| // The JAVA_HOMES environment variable lists the home directories of the Java installations used |
| // for integration testing. |
| |
| // The default JAR has been replaced with a self-contained JAR by the shadowJar task. Therefore, |
| // remove all declared dependencies from the generated Maven POM for said JAR. |
| uploadArchives { |
| repositories { |
| mavenDeployer { |
| pom.whenConfigured { |
| dependencies = [] |
| } |
| } |
| } |
| } |
| |
| sourceSets { |
| integrationTest { |
| java { |
| compileClasspath += main.output + test.output |
| runtimeClasspath += main.output + test.output |
| srcDir file('src/integration-test/java') |
| } |
| resources.srcDir file('src/integration-test/resources') |
| } |
| } |
| |
| configurations { |
| integrationTestCompile.extendsFrom testCompile |
| integrationTestRuntime.extendsFrom testRuntime |
| } |
| |
| dependencies { |
| integrationTestCompile project(':opencensus-api') |
| integrationTestCompile project(':opencensus-testing') |
| integrationTestRuntime libraries.grpc_context |
| integrationTestRuntime project(':opencensus-impl-lite') |
| } |
| |
| // Disable checkstyle for integration tests if not java8. |
| checkstyleIntegrationTest.enabled = JavaVersion.current().isJava8Compatible() |
| |
| // Disable findbugs for integration tests, too. |
| findbugsIntegrationTest.enabled = false |
| |
| def javaExecutables = (System.getenv('JAVA_HOMES') ?: '') |
| .tokenize(File.pathSeparator) |
| .plus(System.getProperty('java.home')) |
| .collect { org.apache.tools.ant.taskdefs.condition.Os.isFamily( |
| org.apache.tools.ant.taskdefs.condition.Os.FAMILY_WINDOWS) |
| ? "${it}/bin/java.exe" |
| : "${it}/bin/java" } |
| .collect { new File(it).getCanonicalPath() } |
| .unique() |
| |
| assert javaExecutables.size > 0 : |
| 'No Java executables found for running integration tests' |
| |
| task integrationTest |
| |
| javaExecutables.eachWithIndex { javaExecutable, index -> |
| def perVersionIntegrationTest = task("integrationTest_${index}", type: Test) { |
| testLogging { |
| // Let Gradle output the stdout and stderr from tests, too. This is useful for investigating |
| // test failures on Travis, where we can't view Gradle's test reports. |
| showStandardStreams = true |
| |
| // Include the exception message and full stacktrace for failed tests. |
| exceptionFormat 'full' |
| } |
| |
| dependsOn shadowJar |
| |
| testClassesDirs = sourceSets.integrationTest.output.classesDirs |
| classpath = sourceSets.integrationTest.runtimeClasspath |
| |
| executable = javaExecutable |
| |
| // The JaCoCo agent must be specified first so that it can instrument our agent. |
| // This is a work around for the issue that the JaCoCo agent is added last, cf. |
| // https://discuss.gradle.org/t/jacoco-gradle-adds-the-agent-last-to-jvm-args/7124. |
| doFirst { |
| jvmArgs jacoco.asJvmArg // JaCoCo agent first. |
| jvmArgs "-javaagent:${shadowJar.archivePath}" // Our agent second. |
| jacoco.enabled = false // Don't add the JaCoCo agent again. |
| } |
| |
| doFirst { logger.lifecycle("Running integration tests using ${javaExecutable}.") } |
| } |
| |
| integrationTest.dependsOn perVersionIntegrationTest |
| } |
| |
| check.dependsOn integrationTest |
| integrationTest.mustRunAfter test |
| |
| // Merge JaCoCo's execution data from all tests into the main test's execution data file. |
| task jacocoMerge(type: JacocoMerge) { |
| tasks.withType(Test).each { testTask -> |
| dependsOn testTask |
| executionData testTask.jacoco.destinationFile |
| } |
| doLast { |
| destinationFile.renameTo test.jacoco.destinationFile |
| } |
| } |
| |
| jacocoTestReport.dependsOn jacocoMerge |
| |
| // JMH benchmarks |
| |
| dependencies { |
| jmh libraries.grpc_context |
| } |
| |
| // Make the agent JAR available using a fixed file name so that we don't have to modify the JMH |
| // benchmarks whenever the version changes. |
| task agentJar(type: Copy) { |
| dependsOn shadowJar |
| |
| from shadowJar.archivePath |
| into libsDir |
| rename { 'agent.jar' } |
| } |
| |
| jmhJar.dependsOn agentJar |
| jmhJar.dependsOn integrationTest |