Instrumenting the code

The immediate question is how do you instrument the code you want to measure without having to modify it? The first goal is to avoid being too intrusive in the code and, also, to avoid affecting the entire application just for the duration of a benchmark. The second goal is to be able to toggle the instrumentation and to be able to deactivate it in order to measure the application without monitoring (particularly, if you put it everywhere) and ignore the associated overhead on the metrics you take.

Nowadays, in Java and Java EE state, you have several options to instrument the code. We will browse through most of them, but here is an overview of the choices you have:

  • Choice 1 – manual: In this solution, you wrap the instance you use with a Factory of the monitoring framework you rely on, and the returned instance is wrapped in a monitored proxy (new instance delegating to the original one). Concretely, it can look like the following:
@ApplicationScoped
public class QuoteResource {
@Inject
private QuoteService service;

@PostConstruct
private void monitorOn() {
service = MonitoringFactory.monitor(service);
}
}

From what we talked about earlier, this has a drawback of impacting the code and limiting the instrumentation to the code you own (or can modify). However, the big advantage is that it is simple to integrate and works with any kind of code (managed by the EE container or not). Concretely, most of the monitoring libraries will have such a utility and often just use it internally in other kinds of integrations.

  • Choice 2 – through CDI (or the interceptor API): The Java EE standard way to inject logic into a service is to use an interceptor. We will detail how it works in a dedicated part but the overall idea is to flag a method as being monitored. Here again, the limitation will be to have access to the code you want to monitor through the CDI container. However, it is less impacting than the previous solution in terms of coding.
If your application relies on Spring, the Spring framework has the same kind of tooling (referenced as AOP in their documentation). So, the same concept applies even if it is activated a bit differently.
  • Choice 3 – through a javaagent: The javaagent is the most powerful way to instrument the code. The drawback is that you need to configure it directly on the JVM, while the good point is that you can monitor almost every class (except for a few of the JVM itself).
Some containers (such as Tomcat/TomEE for instance) allow you to configure java.lang.instrument.ClassFileTransformerThis will basically enable you to perform bytecode instrumentation at load time (dynamically). This allows you to benefit from almost the same power as that of a javaagent, except that you will not be able to instrument the container—and potentially, a part of the JVM—but only the classes of the application. However, it is still more powerful than CDI instrumentation as it sees all the classes of the application, not only the ones that the CDI processes.