Skip to content

Commit

Permalink
Merge pull request #1904 from AyushChaubey/replace-byte-buddy-with-ja…
Browse files Browse the repository at this point in the history
…va-proxy

Replace ByteBuddy with Java Proxy
  • Loading branch information
paulbakker authored May 24, 2024
2 parents 8b8d9d6 + 2baa6de commit ed9ab48
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 261 deletions.
8 changes: 0 additions & 8 deletions graphql-dgs-example-java/dependencies.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion graphql-dgs-spring-boot-micrometer/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
dependencies {
api(project(":graphql-dgs"))

implementation("net.bytebuddy:byte-buddy")
implementation("io.micrometer:micrometer-core")
implementation("commons-codec:commons-codec")
implementation("com.netflix.spectator:spectator-api:1.7.+")
Expand Down
12 changes: 0 additions & 12 deletions graphql-dgs-spring-boot-micrometer/dependencies.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,53 @@ package com.netflix.graphql.dgs.metrics.micrometer.dataloader
import com.netflix.graphql.dgs.metrics.DgsMetrics.GqlMetric
import com.netflix.graphql.dgs.metrics.DgsMetrics.GqlTag
import io.micrometer.core.instrument.MeterRegistry
import io.micrometer.core.instrument.Tag
import io.micrometer.core.instrument.Timer
import net.bytebuddy.implementation.bind.annotation.Pipe
import org.dataloader.BatchLoaderWithContext
import org.slf4j.LoggerFactory
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.util.concurrent.CompletionStage

internal class BatchLoaderWithContextInterceptor(
private val batchLoader: BatchLoaderWithContext<*, *>,
private val batchLoaderWithContext: Any,
private val name: String,
private val registry: MeterRegistry
) {
) : InvocationHandler {

fun load(@Pipe pipe: Forwarder<CompletionStage<List<*>>, BatchLoaderWithContext<*, *>>): CompletionStage<List<*>> {
logger.debug("Starting metered timer[{}] for {}.", ID, javaClass.simpleName)
val timerSampler = Timer.start(registry)
return try {
pipe.to(batchLoader).whenComplete { result, _ ->
logger.debug("Stopping timer[{}] for {}", ID, javaClass.simpleName)
timerSampler.stop(
Timer.builder(ID)
.tags(GqlTag.LOADER_BATCH_SIZE.key, result.size.toString(), GqlTag.LOADER_NAME.key, name)
.register(registry)
)
override fun invoke(proxy: Any, method: Method, args: Array<out Any>): CompletionStage<*> {
if (method.name == "load") {
logger.debug("Starting metered timer[{}] for {}.", ID, javaClass.simpleName)
val timerSampler = Timer.start(registry)
return try {
val future = method.invoke(batchLoaderWithContext, *(args)) as CompletionStage<*>
future.whenComplete { result, _ ->
logger.debug("Stopping timer[{}] for {}", ID, javaClass.simpleName)

val resultSize = if (result is List<*>) {
result.size
} else if (result is Map<*, *>) {
result.size
} else {
throw IllegalStateException("BatchLoader or MappedBatchLoader should always return a List/Map. A ${result.javaClass.name} was found.")
}

timerSampler.stop(
Timer.builder(ID)
.tags(
listOf(
Tag.of(GqlTag.LOADER_NAME.key, name),
Tag.of(GqlTag.LOADER_BATCH_SIZE.key, resultSize.toString())
)
).register(registry)
)
}
} catch (exception: Exception) {
logger.warn("Error creating timer interceptor '{}' for {} with exception {}", ID, javaClass.simpleName, exception.message)
@Suppress("UNCHECKED_CAST")
method.invoke(batchLoaderWithContext, *(args)) as CompletionStage<List<*>>
}
} catch (exception: Exception) {
logger.warn("Error creating timer interceptor '{}' for {} with exception {}", ID, javaClass.simpleName, exception.message)
pipe.to(batchLoader)
}
throw UnsupportedOperationException("Unsupported method: ${method.name}")
}

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,94 +2,61 @@ package com.netflix.graphql.dgs.metrics.micrometer.dataloader

import com.netflix.graphql.dgs.DataLoaderInstrumentationExtensionProvider
import com.netflix.graphql.dgs.metrics.micrometer.DgsMeterRegistrySupplier
import net.bytebuddy.ByteBuddy
import net.bytebuddy.implementation.MethodDelegation
import net.bytebuddy.implementation.bind.annotation.Pipe
import net.bytebuddy.matcher.ElementMatchers
import org.dataloader.BatchLoader
import org.dataloader.BatchLoaderWithContext
import org.dataloader.MappedBatchLoader
import org.dataloader.MappedBatchLoaderWithContext
import java.lang.reflect.Constructor
import java.lang.reflect.Proxy

class DgsDataLoaderInstrumentationProvider(
private val meterRegistrySupplier: DgsMeterRegistrySupplier
) : DataLoaderInstrumentationExtensionProvider {

private val batchLoaderClasses = mutableMapOf<String, Constructor<out BatchLoader<*, *>>>()
private val batchLoaderWithContextClasses = mutableMapOf<String, Constructor<out BatchLoaderWithContext<*, *>>>()
private val mappedBatchLoaderClasses = mutableMapOf<String, Constructor<out MappedBatchLoader<*, *>>>()
private val mappedBatchLoaderWithContextClasses = mutableMapOf<String, Constructor<out MappedBatchLoaderWithContext<*, *>>>()

override fun provide(original: BatchLoader<*, *>, name: String): BatchLoader<*, *> {
return batchLoaderClasses.getOrPut(name) {
val withBinders =
MethodDelegation
.withDefaultConfiguration()
.withBinders(Pipe.Binder.install(Forwarder::class.java))
.to(BatchLoaderInterceptor(original, name, meterRegistrySupplier.get()))
ByteBuddy()
.subclass(BatchLoader::class.java)
.method(ElementMatchers.named("load"))
.intercept(withBinders)
.make()
.load(javaClass.classLoader)
.loaded
.getDeclaredConstructor()
}.newInstance()
}

override fun provide(original: BatchLoaderWithContext<*, *>, name: String): BatchLoaderWithContext<*, *> {
return batchLoaderWithContextClasses.getOrPut(name) {
val withBinders = MethodDelegation.withDefaultConfiguration()
.withBinders(Pipe.Binder.install(Forwarder::class.java))
.to(BatchLoaderWithContextInterceptor(original, name, meterRegistrySupplier.get()))

ByteBuddy()
.subclass(BatchLoaderWithContext::class.java)
.method(ElementMatchers.named("load"))
.intercept(withBinders)
.make()
.load(javaClass.classLoader)
.loaded
.getDeclaredConstructor()
}.newInstance()
}

override fun provide(original: MappedBatchLoader<*, *>, name: String): MappedBatchLoader<*, *> {
return mappedBatchLoaderClasses.getOrPut(name) {
val withBinders = MethodDelegation.withDefaultConfiguration()
.withBinders(Pipe.Binder.install(Forwarder::class.java)).to(
MappedBatchLoaderInterceptor(original, name, meterRegistrySupplier.get())
)

ByteBuddy()
.subclass(MappedBatchLoader::class.java)
.method(ElementMatchers.named("load"))
.intercept(withBinders)
.make()
.load(javaClass.classLoader)
.loaded
.getDeclaredConstructor()
}.newInstance()
}
private val batchLoaderClasses = mutableMapOf<String, BatchLoader<*, *>>()
private val batchLoaderWithContextClasses = mutableMapOf<String, BatchLoaderWithContext<*, *>>()
private val mappedBatchLoaderClasses = mutableMapOf<String, MappedBatchLoader<*, *>>()
private val mappedBatchLoaderWithContextClasses = mutableMapOf<String, MappedBatchLoaderWithContext<*, *>>()

override fun provide(original: BatchLoader<*, *>, name: String): BatchLoader<*, *> =
batchLoaderClasses.getOrPut(name) {
val handler = BatchLoaderWithContextInterceptor(original, name, meterRegistrySupplier.get())
Proxy.newProxyInstance(
javaClass.classLoader,
arrayOf(BatchLoader::class.java),
handler
) as BatchLoader<*, *>
}

override fun provide(original: BatchLoaderWithContext<*, *>, name: String): BatchLoaderWithContext<*, *> =
batchLoaderWithContextClasses.getOrPut(name) {
val handler = BatchLoaderWithContextInterceptor(original, name, meterRegistrySupplier.get())
Proxy.newProxyInstance(
javaClass.classLoader,
arrayOf(BatchLoaderWithContext::class.java),
handler
) as BatchLoaderWithContext<*, *>
}

override fun provide(original: MappedBatchLoader<*, *>, name: String): MappedBatchLoader<*, *> =
mappedBatchLoaderClasses.getOrPut(name) {
val handler = BatchLoaderWithContextInterceptor(original, name, meterRegistrySupplier.get())
Proxy.newProxyInstance(
javaClass.classLoader,
arrayOf(MappedBatchLoader::class.java),
handler
) as MappedBatchLoader<*, *>
}

override fun provide(
original: MappedBatchLoaderWithContext<*, *>,
name: String
): MappedBatchLoaderWithContext<*, *> {
return mappedBatchLoaderWithContextClasses.getOrPut(name) {
val withBinders = MethodDelegation.withDefaultConfiguration()
.withBinders(Pipe.Binder.install(Forwarder::class.java))
.to(MappedBatchLoaderWithContextInterceptor(original, name, meterRegistrySupplier.get()))
ByteBuddy()
.subclass(MappedBatchLoaderWithContext::class.java)
.method(ElementMatchers.named("load"))
.intercept(withBinders)
.make()
.load(javaClass.classLoader)
.loaded
.getDeclaredConstructor()
}.newInstance()
}
): MappedBatchLoaderWithContext<*, *> =
mappedBatchLoaderWithContextClasses.getOrPut(name) {
val handler = BatchLoaderWithContextInterceptor(original, name, meterRegistrySupplier.get())
Proxy.newProxyInstance(
javaClass.classLoader,
arrayOf(MappedBatchLoaderWithContext::class.java),
handler
) as MappedBatchLoaderWithContext<*, *>
}
}

This file was deleted.

This file was deleted.

Loading

0 comments on commit ed9ab48

Please sign in to comment.