Search code examples
javabyte-buddyjavaagents

Bytebuddy: Method not being called in agent


I'm creating an agent and using bytebuddy. I'd like to measure the time it takes to execute the java.net.http.HttpClient's send method.

// premain
public static void premain(String arguments, Instrumentation instrumentation) {
    new AgentBuilder.Default()
        .ignore(ElementMatchers.none())
        .with(Listener.StreamWriting.toSystemOut().withErrorsOnly())
        .type(hasSuperType(named("java.net.http.HttpClient")))
        .transform((builder, typeDescription, classLoader,
            module, protectionDomain) -> {
          return builder
              .visit(Advice.to(SendAdvice.class)
                  .on(hasMethodName("send")
                      .and(returns(named("java.net.http.HttpResponse")))));
        })
        .asTerminalTransformation()
        .installOn(instrumentation);
  }

// Transport
public class Transport {
    public static void send() {
        System.out.println("hello static");
  }
}

// Advice
class SendAdvice {
  @Advice.OnMethodEnter()
  public static long start() {
    return System.nanoTime();
  }

  @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
  public static void exit(
      @Advice.Enter long startTime) throws MalformedURLException {
    Transport.send(System.nanoTime() - startTime);
  }
}

For some reason, the Transport.send is not being invoked. I only have a logging statement in there but it doesn't log. If i just inline the log statement in the exit method, it works.


Solution

  • The Transport class is invoked from the HTTP agent, which is part of the JDK and on the platform class loader. The platform class loader cannot see your agent which lives on the system loader.

    You would need to inject your "general infrastructure" into the boot loader via the Instrumentation instance that is presented to your agent. Byte Buddy offers convenience for this by the ClassInjector hierarchy.