/
build.gradle
243 lines (198 loc) · 7.94 KB
/
build.gradle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
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.findbugs_annotations
compileOnly libraries.grpc_context
compileOnly project(':opencensus-api')
compile libraries.byte_buddy
compile libraries.config
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 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