Skip to content

Tutorial: Instrumentation and Monitoring

Deepika Tiwari edited this page May 31, 2022 · 6 revisions

A tutorial on instrumentation and monitoring with Glowroot

Instrumentation allows us to add extra instructions on top of our code, without modifying the code itself. We might want to do this for several reasons, such as logging, monitoring, calculating code coverage, etc.

In pankti and rick, we use instrumentation to serialize objects when a method is invoked during the execution of an application. For this tutorial, we use instrumentation to simply count the number of times a specific method gets invoked during the execution of an application.

Step 1: Setting up

pankti

First, build pankti

cd pankti/
mvn clean install

A case study: BroadLeaf

For this tutorial, we work with an open-source Java project called BroadLeafCommerce. Let's start by cloning it.

git clone git@github.com:BroadleafCommerce/BroadleafCommerce.git --branch broadleaf-6.2.0-GA

The developers of BroadLeafCommerce also provide a demo application called DemoSite. Let's clone that as well. We will use DemoSite for our experiments.

git clone git@github.com:BroadleafCommerce/DemoSite.git

You can build and run it, following the steps in its README. Play around with the website (localhost:8443) to get familiar with it.

Glowroot

Glowroot is an open-source APM agent. We use it for instrumentation and monitoring. Follow the instructions on the website to download it. Also, create a directory called plugins within glowroot/.

You can try to attach glowroot as a javaagent to DemoSite, by updating its POM and then running DemoSite.

...
    <properties>
      <debug.args>-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=${debug.port}</debug.args>
      <maven.compiler.source>11</maven.compiler.source>
      <maven.compiler.target>11</maven.compiler.target>
      <boot.jvm.memory>-Xmx1536M</boot.jvm.memory>
-     <boot.jvm.args>${boot.jvm.memory} ${debug.args}</boot.jvm.args>
+     <glowroot.plugin.jar>-javaagent:/path/to/glowroot/glowroot.jar</glowroot.plugin.jar>
+     <boot.jvm.args>${boot.jvm.memory} ${debug.args} ${glowroot.plugin.jar}</boot.jvm.args>
      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      <project.uri>${project.baseUri}</project.uri>
    </properties>
...

Step 2: Instrumenting a method

Let's instrument the method getPriceForQuantity(long) defined within the class org.broadleafcommerce.core.catalog.service.dynamic.DynamicSkuPrices, and count the number of times it gets invoked as DemoSite executes.

First,

cd pankti-instrument/

Find the class se.kth.castor.pankti.instrument.plugins.CounterAspect. The nested TargetMethodAdvice within CounterAspect has the @Pointcut annotation. This is where we specify the className, the methodName, the methodParameterTypes, and a descriptive timerName for the method we want to instrument. Let's replace the placeholder values with the details of getPriceForQuantity(long).

public class CounterAspect {
  private static int INVOCATION_COUNT;

- @Pointcut(className = "fully.qualified.path.to.class",
-           methodName = "methodToInstrument",
-           methodParameterTypes = {"param1", "param2"},
-           timerName = "Timer - name")
+ @Pointcut(className = "org.broadleafcommerce.core.catalog.service.dynamic.DynamicSkuPrices",
+           methodName = "getPriceForQuantity",
+           methodParameterTypes = {"long"},
+           timerName = "Timer - DynamicSkuPrices.getPriceForQuantity")
  public static class TargetMethodAdvice implements AdviceTemplate {
    ...

    @OnBefore
    ...

    @OnReturn
    ...
  }
}

The methods annotated with @OnBefore and @OnReturn within TargetMethodAdvice tell Glowroot to increment a counter whenever getPriceForQuantity(long) gets invoked, and update a file with this value.

Next, let's modify ./src/main/resources/META-INF/glowroot.plugin.json to add our aspect class:

{
  "name": "pankti/rick plugin to serialize objects",
  "id": "pankti-rick-plugin",
  "properties": [
    {
      "name": "stackTraceThresholdMillis",
      "type": "double",
      "default": 0.0,
      "label": "Stack trace threshold (millis)",
      "checkboxLabel": "",
      "description": "Any query that exceeds this threshold will have a stack trace captured and attached to it. An empty value will not collect any stack traces, a zero value will collect a stack trace for every query."
    }
  ],
  "aspects": [
+   "se.kth.castor.pankti.instrument.plugins.CounterAspect"
  ]
}

That's it! We can now package this into a plugin with

mvn clean install

This produces pankti-instrument/target/pankti-instrument-<version>-jar-with-dependencies.jar. Copy this jar and paste it in the glowroot/plugins/ directory we created in Step 1.


Step 3: Executing DemoSite

Now that we've added the plugin with the instructions to monitor the invocations of getPriceForQuantity, run DemoSite (make sure you've modified the DemoSite POM as presented in Step 1). Click around the website and interact with the products, add them to the cart, etc. You'll find that /tmp/pankti-object-data/ now has two files. The first one, org.broadleafcommerce.core.catalog.service.dynamic.DynamicSkuPrices.getPriceForQuantity_long-count.txt has the invocation counter that gets updated with each invocation of getPriceForQuantity. The second file is called invoked-methods.csv, which in our case would have org.broadleafcommerce.core.catalog.service.dynamic.DynamicSkuPrices.getPriceForQuantity_long. You can stop the DemoSite server when you're done interacting with the site.


Conclusion

With this tutorial, we learned how to instrument a method with Glowroot, and how to see this instrumentation in action. You can now head over to the pankti and rick tutorials, to see how we use instrumentation to serialize objects, and use them to generate tests.