Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it feasible to create a Java Agent similar to Reactor's Debug Agent? #153

Open
dano opened this issue May 18, 2022 · 2 comments
Open
Labels

Comments

@dano
Copy link
Contributor

dano commented May 18, 2022

I discovered that Project Reactor provides a Java Agent that does bytecode manipulation to do its equivalent of RxJava's assembly tracking (called "debug mode"), but without any runtime performance penalty. Naturally, this made me curious if RxJava could use a similar technique to get the benefit assembly tracking without high cost of generating stack traces. Does it seem possible, or are there differences in the underlying implementations of each that would make it infeasible/impossible for RxJava?

@akarnokd
Copy link
Owner

akarnokd commented May 18, 2022

I don't know Project Reactor's Java Agent and I lack the experience to do one for RxJava. Feel free to implement one in your own library.

@dano
Copy link
Contributor Author

dano commented May 18, 2022

Thanks, @akarnokd. It seems their Java Agent does two manipulations. One is to add call site info to every operator:

/**
 * Adds callSite info to every operator call (except "checkpoint").
 * Before:
 * <pre>
 *     Flux.just(1)
 *         .map(it -> it)
 * </pre>
 * After:
 * <pre>
 *     Flux flux = Hooks.addCallSiteInfo(Flux.just(1), "Flux.just -> MyClass.myMethod(MyClass.java:12)");
 *     flux = Hooks.addCallSiteInfo(flux.map(it -> it), "Flux.map -> MyClass.myMethod(MyClass.java:13)");
 * </pre>
 *
 */

The other is to "checkpoint" methods that return Reactor types but don't call operators:

/**
 * Checkpoints every method returning Mono/Flux/ParallelFlux,
 * unless there were operator calls in the method body.
 * Before:
 * <pre>
 *     public Mono<String> request() {
 *         return MyWebClient.get("/foo").bodyToMono(String.class);
 *     }
 * </pre>
 * After:
 * <pre>
 *     public Mono<String> request() {
 *         return MyWebClient.get("/foo").bodyToMono(String.class).checkpoint("MyClass.request(MyClass.java:123)");
 *     }
 * </pre>
 *
 */

I'm definitely way out of my comfort zone with both the RxJava/Reactor internals and with byte code manipulation, but it appears (though I could absolutely be missing something) like an RxJava equivalent could be made if the RxJava assembly tracking code was modified to replace RxJavaAssemblyException with a class that could generate its own stacktrace (as it does now), but could also take a String that specified a hard-coded stack location like in the code above. It'd then have to be injected into the *OnAssembly wrappers instead of being created in their constructors.

Anyway, not sure if I will get the time to dig into this further, but it does seem like it holds some promise as a way to debug RxJava code much more easily in production. If I get around to investigating more I will let you know what I find...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants