Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 81 additions & 2 deletions dd-java-agent/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ tasks.register('verifyAgentJarContents') {

// Sanity check on the minimum number of classes; update as needed. Set to about 98% of that number.
def classCount = entries.keySet().count { it.endsWith('.class') || it.endsWith('.classdata') }
def classFloor = 17_000 // a bit moe than 98% of 17,279 at time of writing
def classFloor = 17_000 // a bit more than 98% of 17,279 at time of writing
if (classCount < classFloor) {
failures << "Class count ${classCount} is below floor ${classFloor}"
}
Expand Down Expand Up @@ -577,6 +577,85 @@ tasks.register('verifyAgentJarContents') {
}
}

def integrationsGoldenFile = project.file('expected-integrations.txt')

tasks.register('verifyAgentJarIntegrations', JavaExec) {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = 'Verify the agent jar lists exactly the integrations in expected-integrations.txt'

def jarProvider = tasks.named('shadowJar', ShadowJar).flatMap { it.archiveFile }
inputs.file(jarProvider)
inputs.file(integrationsGoldenFile)
outputs.file(project.layout.buildDirectory.file("tmp/${it.name}/.verified"))

// Run the assembled agent jar directly — this exercises dd-java-agent.index,
// inst/instrumenter.index, and instrumentation class loading end-to-end.
mainClass = 'datadog.trace.bootstrap.AgentBootstrap'
classpath = objects.fileCollection().from(jarProvider)
args = ['--list-integrations']

// Capture both stdout and stderr: InstrumenterIndex.buildModule() logs ERROR and returns null when a module
// fails to load, while the process exits with status 0.
def capturedOutput = new ByteArrayOutputStream()
def capturedError = new ByteArrayOutputStream()
standardOutput = capturedOutput
errorOutput = capturedError

doLast {
def stderr = capturedError.toString()
if (!stderr.isBlank()) {
throw new GradleException(
"--list-integrations produced unexpected stderr output " +
"(likely a module load failure; see InstrumenterIndex.buildModule):\n${stderr}")
}

if (!integrationsGoldenFile.exists()) {
throw new GradleException(
"${integrationsGoldenFile.name} not found. " +
"Run './gradlew :dd-java-agent:updateAgentJarIntegrationsGolden' to create it.")
}

def actual = capturedOutput.toString().readLines().findAll { !it.isBlank() }.toSorted()
def expected = integrationsGoldenFile.readLines().findAll { !it.isBlank() }.toSorted()
def added = actual - expected
def removed = expected - actual
Comment thread
bric3 marked this conversation as resolved.

if (added || removed) {
def msg = new StringBuilder("Integration list differs from ${integrationsGoldenFile.name}.")
msg.append(" Run './gradlew :dd-java-agent:updateAgentJarIntegrationsGolden' to update it.\n")
added.each { msg.append(" + ${it}\n") }
removed.each { msg.append(" - ${it}\n") }
throw new GradleException(msg.toString())
}

def marker = outputs.files.singleFile
marker.parentFile.mkdirs()
marker.text = 'verified'
}
}

// Manual run after adding/removing integrations to update expected-integrations.txt, then add with the new integration.
tasks.register('updateAgentJarIntegrationsGolden', JavaExec) {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = 'Regenerate expected-integrations.txt from the current agent jar'

def jarProvider = tasks.named('shadowJar', ShadowJar).flatMap { it.archiveFile }
inputs.file(jarProvider)

mainClass = 'datadog.trace.bootstrap.AgentBootstrap'
classpath = objects.fileCollection().from(jarProvider)
args = ['--list-integrations']

def capturedOutput = new ByteArrayOutputStream()
standardOutput = capturedOutput

doLast {
def integrations = capturedOutput.toString().readLines().findAll { !it.isBlank() }.toSorted()
integrationsGoldenFile.text = integrations.join('\n') + '\n'
logger.lifecycle("Updated ${integrationsGoldenFile.name} with ${integrations.size()} integrations")
}
}

tasks.named('check') {
dependsOn 'verifyAgentJarContents'
dependsOn 'verifyAgentJarContents', 'verifyAgentJarIntegrations'
}
208 changes: 208 additions & 0 deletions dd-java-agent/expected-integrations.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
IastInstrumentation
aerospike
akka-http
akka-http2
Comment thread
bric3 marked this conversation as resolved.
akka_actor_mailbox
akka_actor_receive
akka_actor_send
akka_concurrent
allocatedirect
amqp
apache-httpclient
armeria-grpc-client
armeria-grpc-server
armeria-jetty
avro
aws-lambda
aws-sdk
axis2
axway-api
azure-functions
caffeine
cassandra
ci-visibility
cics
classloading
commons-fileupload
commons-http-client
confluent-schema-registry
couchbase
cucumber
cxf
datanucleus
defineclass
dropwizard
dynamodb
elasticsearch
emr-aws-sdk
eventbridge
ffm-native-tracing
finatra
freemarker
gax
glassfish
google-http-client
google-pubsub
gradle
graphql-java
grizzly
grizzly-client
grizzly-filterchain
grpc
gson
guava
hazelcast
hazelcast_legacy
hibernate
httpasyncclient
httpasyncclient5
httpclient
httpclient5
httpcore
httpcore-5
httpurlconnection
hystrix
ignite
inputStream
jackson
jackson-core
jacoco
jakarta-jms
jakarta-mail
jakarta-rs
jakarta-websocket
jakarta-ws
java-http-client
java-lang
java-lang-appsec
java-lang-management
java-module
java-net
java_completablefuture
java_concurrent
java_timer
javax-mail
javax-websocket
jax-rs
jax-ws
jboss-logmanager
jdbc
jdbc-datasource
jedis
jersey
jetty
jetty-client
jetty-concurrent
jms
jni
jsp
jwt
kafka
kotlin_coroutine
lettuce
liberty
log4j
logback
maven
micronaut
mmap
mongo
mule
native-image
netty
netty-concurrent
netty-promise
not-not-trace
ognl
okhttp
openai-java
opensearch
opentelemetry-annotations
opentelemetry-beta
opentelemetry-logs
opentelemetry-metrics
opentelemetry.experimental
opentracing
org-json
pekko-http
pekko-http2
pekko_actor_mailbox
pekko_actor_receive
pekko_actor_send
play
play-ws
protobuf
quartz
ratpack
ratpack-request-body
reactive-streams
reactor-core
reactor-netty
rediscala
redisson
renaissance
resilience4j
resilience4j-reactor
resteasy
restlet-http
rmi
rxjava
s3
scala_concurrent
servicetalk
servlet
servlet-filter
servlet-request-body
servlet-service
sfn
shutdown
slick
snakeyaml
sns
socket
sofarpc
spark
spark-executor
spark-exit
spark-launcher
spark-openlineage
sparkjava
spray-http
spring-async
spring-beans
spring-boot
spring-boot-span-origin
spring-cloud-zuul
spring-core
spring-data
spring-jms
spring-messaging
spring-rabbit
spring-scheduling
spring-security
spring-web
spring-web-code-origin
spring-webflux
spring-ws
spymemcached
sqs
sslsocket
synapse3-client
synapse3-server
testng
throwables
thymeleaf
tibco
tinylog
tomcat
trace
twilio-sdk
undertow
urlconnection
valkey
velocity
vertx
wallclock
websphere-jmx
wildfly
zio.experimental