Custom Probes

   


1. Introduction

If you want to collect information on a subsystem that is not covered by the built-in probes, JProfiler offers an API to write your own custom probes. There are two ways to develop and deploy a custom probe into the profiled application. You can write your custom probe in your IDE, add the compiled classes to the classpath, and add a special VM parameter to the invocation of the profiled application. Alternatively, you can create the probe directly in the JProfiler GUI by configuring the scripts in the custom probe wizard. In the latter case, no modification of the profiled application is necessary.

For an overview of the basic probe concepts, please see the corresponding help topic. An example of a custom probe is given in the api/samples/probe directory.

2. Probe Configuration

A probe is a Java class that implements one or both of the interfaces com.jprofiler.api.agent.probe.InterceptorProbe and com.jprofiler.api.agent.probe.TelemetryProbe. Both interfaces extend the base com.jprofiler.api.agent.probe.Probe interface which in itself is not sufficient to develop a useful probe.

Each probe is configured at startup when its getMetaData() method is called by the profiling agent. To get a meta data instance, call com.jprofiler.api.agent.probe.ProbeMetaData#create(String name) and continue calling configuration methods on the returned object. ProbeMetaData is a fluent interface, so you can append calls to its methods on the same line. The information you provide at configuration time via the ProbeMetaData is relevant when using the com.jprofiler.api.agent.probe.ProbeContext that is passed to you during data-collection time.

Several configuration methods determine the capabilities of the probe. For example, metaData.payload(true).telemetry(true).events(true).controlObjectsView(true) configures a probe that publishes data for all available views.

An easy way to configure an automatic telemetry is to call ProbeMetaData#addOpenControlObjectTelemetry(String name). Custom telemetries can be configured with ProbeMetaData#addCustomTelemetry(String name, Unit unit, float factor).

Importantly for the time line and events views, you can configure custom event types with ProbeMetaData#customTypeNames(String[] names) and assign custom colors to them with ProbeMetaData#customColors(String[] names).

Events and control objects can receive additional data, which is configured with ProbeMetaData#addAdditionalData(String name, DataType dataType) for events and ProbeMetaData#addAdditionalControlObjectData(String name, DataType dataType, boolean nested) for control objects.

3. Interceptor Probes

An interceptor probe gets the opportunity to intercept selected methods. It is queried at startup for the methods that should be instrumented and notified each time one of those methods is called. To the interception methods an instance of com.jprofiler.api.agent.probe.InterceptorContext is passed which contains methods for publishing payload information and creating events.

Because methods can be intercepted recursively, you should use InterceptorContext#push(PayloadInfo) to save a payload at method entry and InterceptorContext#pop() to retrieve it at method exit. The payload stack is thread-local, so it also works in multi-threaded situations. Finally you can call calculateTime() on the payload info object and publish it with InterceptorContext#addPayloadInfo(PayloadInfo).

Control objects are registered by creating an open event with ProbeContext#createOpenEvent(String description, Object controlObject) and are closed by creating a close event with ProbeContext#createCloseEvent(String description, Object controlObject). If you have configured additional data for control objects, you create the open event with ProbeContext#createOpenEvent(String description, Object controlObject, Object[] controlObjectData) instead.

Custom events for particular control objects are created with ProbeContext#createCustomEvent(String description, int type, Object controlObject). If you do not use control objects, just pass null as the last parameter of this method. The type ID is the index in the array argument that was passed to ProbeMetaData#customTypeNames(String[] names) at configuration time. If you have configured additional data for events, you supply it by calling ProbeEvent#additionalData(Object[] additionalData) on the event.

Note that all created events have to be published by calling ProbeContext#addEvent(ProbeEvent).

4. Telemetry Probes

A telemetry probe is called via its fillTelemetryData(ProbeContext probeContext, int[] data, int duration) method and thus periodically gets a chance to publish its telemetry data. The indices in the data array correspond to the invocations of ProbeMetaData#addCustomTelemetry(String name, Unit unit, float factor) in the meta-data configuration.

Since telemetry information is not related to payloads, to telemetry probes an instance of com.jprofiler.api.agent.probe.ProbeContext is passed rather than an instance of the derived com.jprofiler.api.agent.probe.InterceptorContext that is passed to the interception methods of telemetry probes. A probe can take both roles and implement both the interface for an interceptor probe and the interface for a telemetry probe.

5. Manual Probe Registration

To manually register a probe in the profiled application, you have to create a class that implements com.jprofiler.api.agent.probe.ProbeProvider. Its getProbes() method can return one or several probes. Then, you have to pass the VM parameter -Djprofiler.probeProvider=[fully-qualified-class] to the profiled JVM. The probe provider is instantiated at startup.

6. Custom Probe Wizard

Developing probes in an IDE, compiling them against the JProfiler API and deploying them to the profiled application together with the modification of the java command can be quite inconvenient. JProfiler offers an easier way to quickly develop and deploy custom probes without the need to use an IDE or modify the profiled application. The custom probe wizard leads you step by step through the creation of a custom probe.

First, you define the meta data script, to which an instance of com.jprofiler.api.agent.probe.ProbeMetaData is already passed. The script editor in JProfiler offers code analysis, code completion and context-sensitive Javadoc.

Custom probes defined in the JProfiler GUI are both interceptor and telemetry probes. You can optionally define a telemetry script in the custom probe wizard that will be called every second.

Selecting methods for interception is also much easier in the JProfiler GUI compared to writing probes manually. You just choose the methods from a list of all methods found in the profiled JVM.

There are three interception scripts for method entry, exit and exception exit. You configure them for different groups of methods with the same signature. The method arguments of the intercepted method are passed to the method entry script together with the interceptor context and the current object.

7. Custom Probe Vs. Trigger

If you just want to intercept a method and invoke your own code there without collecting any data, it is recommended to use a method trigger with a "Run interceptor script" action. In this way you do not have to provide the probe meta data. Also, method triggers can be added conveniently via the context menu in the call tree view.