Skip to content

Instantly share code, notes, and snippets.

@Szer
Last active September 25, 2023 13:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Szer/ebc35629cbc4dd7332c173f92214cfbd to your computer and use it in GitHub Desktop.
Save Szer/ebc35629cbc4dd7332c173f92214cfbd to your computer and use it in GitHub Desktop.
DataDog reflection hack
package com.thriveglobal.tracing.proxy
import ddtrot.dd.trace.bootstrap.instrumentation.api.AgentScope
import ddtrot.dd.trace.bootstrap.instrumentation.api.ScopeState
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.util.concurrent.ConcurrentHashMap
// this class is needed because DataDog relocates classes on purpose, so they are not available through reflection
// to overcome that we are building dynamic proxies for this and all returned objects
// https://github.com/DataDog/dd-trace-java/blob/87c51d2dd841db4cc48a08c7bb3eeea79ecfca04/dd-java-agent/build.gradle#L51-L54
class CoreTracerProxy(private val tracer: Any) : InvocationHandler {
companion object {
private val methodsCache = ConcurrentHashMap<String, Method>()
private lateinit var newScopeState: Method
private lateinit var activeScope: Method
}
init {
if (methodsCache.isEmpty()) {
val methods = tracer.javaClass.methods
methods.forEach { method ->
methodsCache[method.name] = method
}
newScopeState = methodsCache["newScopeState"]!!
activeScope = methodsCache["activeScope"]!!
newScopeState.isAccessible = true
activeScope.isAccessible = true
}
}
override fun invoke(proxy: Any, method: Method, args: Array<out Any>?): Any? =
when (method.name) {
newScopeState.name ->
tracer.invokeWithProxy<ScopeState>(newScopeState, args) {
ScopeStateProxy(it)
}
activeScope.name ->
tracer.invokeWithProxy<AgentScope>(activeScope, args) {
AgentScopeProxy(it)
}
else -> throw IllegalArgumentException("method ${method.name} is not supported")
}
}
package com.thriveglobal.tracing.proxy
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy
internal fun Any.invokeWithArgs(
method: Method,
args: Array<out Any>?,
): Any? =
method.invoke(this, *(args ?: emptyArray<Any>()))
internal inline fun <reified T> Any.invokeWithProxy(
method: Method,
args: Array<out Any>?,
block: (Any) -> InvocationHandler,
): T {
val value = this.invokeWithArgs(method, args)!!
return Proxy.newProxyInstance(
T::class.java.classLoader,
arrayOf(T::class.java),
block(value),
) as T
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment