Our XML instrumentation basically functions as an extension to the list of classes and methods that the agent tracks out of the box. Let’s take a made-up example, just to illustrate what happens when you target a specific class / method with XML instrumentation.
The link above includes an example class called
test.SampleTester, with a method called
checkSample. If I put this in my XML file:
<?xml version="1.0" encoding="UTF-8"?>
xsi:schemaLocation="newrelic-extension extension.xsd "
I’ve just told the agent to wrap this method at runtime. The next time that class is loaded, we interrupt the class-loader and wrap the
checkSample method in a couple of API calls using bytecode injection. We don’t alter the method call at all, but we place an api call to our agent at the point that the method is executed, and when the method returns its response, so that we know how long the method took to run overall.
dispatcher=true flag tells the agent to start an APM Transaction when this method is called, if one isn’t already in progress. The
<nameTransaction/> flag tells the agent to rename whatever transaction is in progress, new or old, based on the class / method name targeted in the pointcut.
Now, consider for a moment how Java works under the hood. Java is object oriented, and encapsulated. Each Java object owns any variables that are held by that object, and said variables aren’t visible to other objects in the JVM. But, because we’re adding API calls to the underlying method, we’re effectively calling out to our agent from inside the method, so we can pick up attributes that are specific to that method that wouldn’t normally be visible from outside. Like method parameters. That’s what the
<parameters> node in the XML example allows you to do – pick up and decorate your Transaction Traces with specific method parameters.
Now, let’s assume for a moment that our
checkSample method places an external request. If it does so using a method we instrument out of the box, like
HttpUrlConnection, we’ll pick up that as well, and we’ll nest the external call underneath the call to
checkSample in the web transaction’s breakdown table. However, if it places the external call using a method that we don’t trace out of the box, we can see that the method is called, but not what it’s doing (Java encapsulation again), so it will appear with a
? next to it in the transaction breakdown table. To remove the
?, we would need to add the method that places the external request to our XML file. Then we would effectively be inside that method as well, and can report on what methods are called from within it, what parameters are passed by it, etc…
Now, here’s where async comes in. Assuming your code is blocking, meaning that each method call waits for subsequent methods to complete their work before returning a response, instrumenting the first method in the chain gives you timing data for the whole request. All subsequent methods just add details to the method timing. But in the async world, you might trigger five tasks on five different threads, and not wait for a response (fire-and-forget) before moving on to the next method in the call stack. Because the async activity is happening on a different thread than the original method trace, the agent can’t link them together easily. It has difficulty telling which thread represents which work from which HTTP request.
Our Async API allows you to pass a token to the method that is executed asynchronously, and then link that token to the activity back on the main thread, so that the two are seen as one transaction. Were you to simply target the method that is executed asynchronously with XML instrumentation (adding
dispatcher=true), you would start a second transaction on the async thread, rather than linking the async thread to the main thread. That would still show you the external request that was placed on the async thread, but it would show up as two separate Transactions in APM, one representing the incoming HTTP request, the other representing the asynchronous work that was part of that HTTP request. And it would not be easy to tell that the two were part of the same underlying task.
Now, there’s a lot that you can do with bytecode injection. Our built-in instrumentation modules are a bit more complex than simple XML point cuts. For recognized frameworks, we can weave in our own Async API calls, or leverage the way the framework tracks async thread context. If we can determine the point where the agent is losing track of the request, we could enter a feature request to improve our async tracking in that framework out of the box. There are a lot of async models out there, and we’re always working to improve our range of support.
All that said, at the end of the day with our current product set, we can probably get all of the segments of your HTTP request (synchronous and asynchronous) to show up in APM as separate Transactions using only XML instrumentation, but we won’t be able to get them to show up as the same Transaction without using the Async API.
Regarding monitoring Java MBeans, that’s a slightly different type of custom instrumentation. Most application servers expose Java mbean values over JMX, and our Custom JMX instrumentation allows you to specify the mbean object / metric name and add it to the list of Java mbeans that the agent tracks out of the box. Our agent accesses JMX remotely, in exactly the same way as say JConsole, making JConsole a very useful tool for surfacing what mbeans are available in a given environment. If it is visible in JConsole, we can probably import it into APM.
Note however that custom JMX metrics require an Insights custom dashboard to view, they don’t appear in the APM UI by default.