Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ByteBuddy: how to add local variable across enter/exit when transforming a method

I am trying to use ByteBuddy within a Java Agent to instrument some older libraries using OpenTracing. This is associated with the OpenTracing Contrib Java Special Agent project. I had this successfully working when using a private class member to pass the active span, but unfortunately there are instances where this is not feasible (error handling clears out the member field).

So I am trying to use ByteBuddy's ability to create local variables that can be retained from the @Advice.OnMethodEnter to the @Advice.OnMethodExit. This will allow me to create the OpenTracing Span on method enter, and finish it on method exit. I'm not sure my use case is valid, though, since I am using a transformer, which doesn't exactly match the test case for the @Advice.Local annotation.

I tried to follow the syntax used in this test case.

However, the span and scope variables are always null in the exit method. I'm a novice with ByteBuddy, so I'm sure I'm missing something basic.

public class SimpleFrameworkDispatcherAgentRule extends AgentRule {
    @Override
    public Iterable<? extends AgentBuilder> buildAgent(AgentBuilder agentBuilder) {
        return Arrays.asList(agentBuilder
                .type(named("org.simpleframework.http.core.Dispatcher"))
                .transform((builder, typeDescription, classLoader, module) -> {
                    return builder.visit(Advice.to(SimpleFrameworkDispatcherAgentRule.class)
                            .on(named("dispatch")));
                }));
    }

    @Advice.OnMethodEnter
    public static void enter(final @Advice.Origin String origin, 
            final @FieldValue(value = "request", typing = Typing.DYNAMIC) Object request, 
            final @Advice.Local("span") Object span, 
            final @Advice.Local("scope") Object scope) {
        if (isEnabled(origin)) {
            SimpleFrameworkAgentIntercept.enter(request, span, scope);
        }
    }

    @Advice.OnMethodExit
    public static void exit(final @Advice.Origin String origin, 
            final @FieldValue(value = "response", typing = Typing.DYNAMIC) Object response, 
            final @Advice.Local("span") Object span, 
            final @Advice.Local("scope") Object scope) {
        if (isEnabled(origin)) {
            SimpleFrameworkAgentIntercept.exit(response, span, scope);
        }
    }
}

I instrumented the SimpleFrameworkAgentIntercept enter and exit methods and confirmed that the variables are assigned in enter, but they are null in exit.

like image 234
Randall T. Avatar asked Sep 01 '25 10:09

Randall T.


1 Answers

You have to assign the variables, it does not help if you do this in a delegate method.

Byte Buddy uses the advice code as a template where any assignment of the local variable in a specific method is translated into an access of a local variable of the instrumented in the inlined byte code.

Java does not have pointer semantics in the sense of C or other languages. If you wanted to assign span or scope you have to do so in the annotated method itself.

like image 111
Rafael Winterhalter Avatar answered Sep 03 '25 01:09

Rafael Winterhalter