Embedded probe API

A resource document of the JProfiler MCP server. Back to the tool and resource reference.

For agent consumption, this page is also available as raw Markdown.

Content of the MCP resource jprofiler://api/probe-embedded of the JProfiler MCP server, see the tool and resource reference for the full list of tools and resources.

API reference of com.jprofiler.api.probe.embedded for writing embedded custom probes: the probe base classes PayloadProbe and SplitProbe, the measurement entry points Payload and Split and the telemetry annotations. Read jprofiler://probes/custom first for the embedded/injected decision, build setup, deployment and recording.

Types

Flat alphabetical index of every type in the API. Use this when you know the qualified name and want to skip package navigation.

Qualified nameKindFile
com.jprofiler.api.probe.embedded.PayloadclassPayload
com.jprofiler.api.probe.embedded.PayloadProbeclassPayloadProbe
com.jprofiler.api.probe.embedded.SplitclassSplit
com.jprofiler.api.probe.embedded.SplitProbeclassSplitProbe
com.jprofiler.api.probe.embedded.ThreadStateenumThreadState
com.jprofiler.api.probe.embedded.TypeCustomizerinterfaceTypeCustomizer
com.jprofiler.api.probe.embedded.telemetry.TelemetryannotationTelemetry
com.jprofiler.api.probe.embedded.telemetry.TelemetryFormatannotationTelemetryFormat
com.jprofiler.api.probe.embedded.telemetry.TelemetryUnitenumTelemetryUnit

Package com.jprofiler.api.probe.embedded

Contains the classes for creating an embedded probe.

Purpose of embedded probes

Please read the "Probe concepts" chapter in the documentation (directory $JPROFILER_HOME/doc) for an overview on the different types of custom probes in JProfiler and the "Embedded probes" chapter for an extended discussion of embedded probes.

Embedded probes allow you to add functionality similar to the built-in probes in JProfiler. In contrast to the "injected" probe API, the "embedded" probe API is called directly from the monitored software. If you want to monitor software components whose source code is not under your control, use the injected probe API instead.

Getting started

There are two types of embedded probes, split probes and payload probes. Please see Split and Payload for further information.

To get started with writing embedded probes, have a look at the $JPROFILER_HOME/api/samples/simple-embedded-probe example project. Open the gradle build file build.gradle in an editor for instructions on how to run it.

JAR file and dependency

All classes in this package are contained in $JPROFILER_HOME/api/jprofiler-probe-embedded.jar. The embedded probe API is also available as a dependency. In the snippets below, "VERSION" should be replaced with the corresponding JProfiler version.

Maven

<dependency>
  <groupId>com.jprofiler</groupId>
  <artifactId>jprofiler-probe-embedded</artifactId>
  <version>VERSION</version>
</dependency>

Gradle

dependencies {
  implementation group: 'com.jprofiler', name: 'jprofiler-probe-embedded', version: 'VERSION'
}

License

Classes in this package and its sub-packages are licensed under the Apache License, version 2.0.

Payload

Import: import com.jprofiler.api.probe.embedded.Payload;

@JProfilerEmbeddedClass
public class Payload

By calling this class you can add entries to the payload call tree and hotspots of your probe.

You can either use a pair of Payload.enter and Payload.exit calls or the execute wrappers. If you write your own wrapper in another JVM language it is advisable to use the Payload.enter and Payload.exit primitives.

When using the primitives, it is very important that a matching Payload.exit is always called, so the exit call must be put in a finally block like this:

     Payload.enter(MyProbe.class);
     try {
         // your code
     } finally {
         Payload.exit("my payload string");
     }
 

If you use control objects in your probe (for example to record connections like in the JDBC probe) you can use the Payload.enter or the similarly overloaded execute wrappers to associate a payload with a control object. With the Payload.openControlObject, Payload.closeControlObject and PayloadProbe.getControlObjectName methods you can further customize control object recording. Your configuration subclass of PayloadProbe must override PayloadProbe.isControlObjects and return true to enable control object recording as a capability for the probe.

If you want to record different event types which also correspond to different control object states, you have to override PayloadProbe.getCustomTypes and return a custom enum class. Objects of this class can then be passed to Payload.enter. The toString() method of the enums will be used to get the event name. If you want to control the event color, the enum class can implement the TypeCustomizer interface.

Methods

SignatureReturnsDescription
enter(Class<? extends PayloadProbe>)voidStart a payload.
enter(Class<? extends PayloadProbe>, Object, Enum<?>)voidStart a payload.
exit(String)voidFinishes recording of a payload.
execute(Class<? extends PayloadProbe>, String, Runnable)voidA wrapper for the Payload.enter and Payload.exit primitives for a Runnable.
execute(Class<? extends PayloadProbe>, String, Object, Enum<?>, Runnable)voidA wrapper for the Payload.enter and Payload.exit primitives for a Runnable.
execute(Class<? extends PayloadProbe>, String, Callable<T>)TA wrapper for the Payload.enter and Payload.exit primitives for a Callable.
execute(Class<? extends PayloadProbe>, String, Object, Enum<?>, Callable<T>)TA wrapper for the Payload.enter and Payload.exit primitives for a Callable.
openControlObject(Class<? extends PayloadProbe>, Object, String)voidRecords an open event for a control object and assigns a name to it.
closeControlObject(Class<? extends PayloadProbe>, Object)voidCloses a control object.
register(Class<? extends PayloadProbe>)voidYou can register your probe independently of enter and execute calls.

##### enter(Class<? extends PayloadProbe>)

public static void enter(Class<? extends PayloadProbe> probe)

Start a payload. A matching Payload.exit call must always be called.

Parameters:

  • probe — the configuration class. Must not be null.

##### enter(Class, Object, Enum)

public static void enter(Class<? extends PayloadProbe> probe, Object controlObject, Enum<?> type)

Start a payload. A matching Payload.exit call must always be called.

Parameters:

  • probe — the configuration class. Must not be null.
  • controlObject — the control object this payload belongs to or null. If control objects should be recorded you have to override PayloadProbe.isControlObjects.
  • type — the payload type. Must be an object of your custom enum class registered by overriding PayloadProbe.getCustomTypes or null.

##### exit(String)

public static void exit(String name)

Finishes recording of a payload. A matching enter call must have been called first.

Parameters:

  • name — the name of the recorded payload. If null, the payload recording will be discarded.

##### execute(Class<? extends PayloadProbe>, String, Runnable)

public static void execute(Class<? extends PayloadProbe> probe, String name, Runnable runnable)

A wrapper for the Payload.enter and Payload.exit primitives for a Runnable.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the name of the recorded payload. If null, the payload recording will be discarded.
  • runnable — the runnable that will be timed for the payload recording.

##### execute(Class, String, Object, Enum, Runnable)

public static void execute(Class<? extends PayloadProbe> probe, String name, Object controlObject, Enum<?> type, Runnable runnable)

A wrapper for the Payload.enter and Payload.exit primitives for a Runnable.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the name of the recorded payload. If null, the payload recording will be discarded.
  • controlObject — the control object this payload belongs to or null. If control objects should be recorded you have to override PayloadProbe.isControlObjects.
  • type — the payload type. Must be an object of your custom enum class registered by overriding PayloadProbe.getCustomTypes or null.
  • runnable — the runnable that will be timed for the payload recording.

##### execute(Class<? extends PayloadProbe>, String, Callable)

public static <T> T execute(Class<? extends PayloadProbe> probe, String name, Callable<T> callable) throws Exception

A wrapper for the Payload.enter and Payload.exit primitives for a Callable.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the name of the recorded payload. If null, the payload recording will be discarded.
  • callable — the callable that will be timed for the payload recording.

##### execute(Class, String, Object, Enum, Callable)

public static <T> T execute(Class<? extends PayloadProbe> probe, String name, Object controlObject, Enum<?> type, Callable<T> callable) throws Exception

A wrapper for the Payload.enter and Payload.exit primitives for a Callable.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the name of the recorded payload. If null, the payload recording will be discarded.
  • controlObject — the control object this payload belongs to or null. If control objects should be recorded you have to override PayloadProbe.isControlObjects.
  • type — the payload type. Must be an object of your custom enum class registered by overriding PayloadProbe.getCustomTypes or null.
  • callable — the callable that will be timed for the payload recording.

##### openControlObject(Class<? extends PayloadProbe>, Object, String)

public static void openControlObject(Class<? extends PayloadProbe> probe, Object controlObject, String name)

Records an open event for a control object and assigns a name to it. The control object will be displayed in the control objects view and the timeline. Your configuration subclass of PayloadProbe must override PayloadProbe.isControlObjects and return true to enable control object recording as a capability for the probe.

If you don't use this method and a previously unknown control object is used in the enter or execute methods and you have overridden the PayloadProbe.getControlObjectName method of your configuration class, it will be called to assign a name to the new control object. No open event will be created in the events view in that case.

Parameters:

  • probe — the configuration class. Must not be null.
  • controlObject — the control object
  • name — the name of the control object

##### closeControlObject(Class<? extends PayloadProbe>, Object)

public static void closeControlObject(Class<? extends PayloadProbe> probe, Object controlObject)

Closes a control object. If the control object is not currently open, this method has no effect.

Parameters:

  • probe — the configuration class. Must not be null.
  • controlObject — the control object

##### register(Class<? extends PayloadProbe>)

public static void register(Class<? extends PayloadProbe> probe)

You can register your probe independently of enter and execute calls. As soon as the probe is registered it will be displayed in the JProfiler UI and telemetries can be recorded. You don't have to call this method if you don't want to start telemetry recording before an enter or execute call takes place. enter or execute and all control object methods will automatically register your probe.

Parameters:

  • probe — the configuration class. Must not be null.

Constructors

SignatureDescription
Payload()

##### Payload()

public Payload()

PayloadProbe

Import: import com.jprofiler.api.probe.embedded.PayloadProbe;

@JProfilerEmbeddedClass
public abstract class PayloadProbe

For each payload probe, you have to create a subtype of this class and pass it as a class literal to the methods in Payload.

You can override the methods of this class to configure your probe. The only method you have to implement is PayloadProbe.getName.

You can add additional custom telemetries by adding public static methods to your subclass that return a number type and are annotated with Telemetry.

Methods

SignatureReturnsDescription
getName()StringImplement this method to specify the display name of your probe.
getDescription()StringYou can override this method to add a description to your probe in the JProfiler UI.
isEvents()booleanYou can override this method and return false if you want to remove the events view.
isDefaultTelemetries()booleanYou can override this method and return false if you want to remove the default telemetries.
isControlObjects()booleanIf your probe supports control objects, you have to override this method and return true.
getCustomTypes()Class<? extends Enum>You can specify custom types for events.
getControlObjectName(Object)StringIf you use control objects and a previously unknown control object is passed to Payload.enter, Payload.execute or Payload.execute, the JProfiler agent will call this method to associate a name with the control object.

##### getName()

public abstract String getName()

Implement this method to specify the display name of your probe. In the JProfiler UI, this string is used for the view name in the "JVM & Custom Probes" section of the view selector.

Returns: the name of your probe

##### getDescription()

public String getDescription()

You can override this method to add a description to your probe in the JProfiler UI. It is shown in the probe view below the probe name.

Returns: your optional description

##### isEvents()

public boolean isEvents()

You can override this method and return false if you want to remove the events view.

Returns: if the events view should be displayed

##### isDefaultTelemetries()

public boolean isDefaultTelemetries()

You can override this method and return false if you want to remove the default telemetries. The default telemetries are the event frequency and the average duration telemetries as well as the open control object telemetry if PayloadProbe.isControlObjects returns true.

Returns: if the default telemetries will be recorded

##### isControlObjects()

public boolean isControlObjects()

If your probe supports control objects, you have to override this method and return true.

Returns: if control objects can be recorded

##### getCustomTypes()

public Class<? extends Enum> getCustomTypes()

You can specify custom types for events. If control objects are recorded, the same types are used for the associated control object states. In the overridden method, return an Enum class with all your states as constants. The toString() method is used for the event display name. You can further customize your events by implementing TypeCustomizer in the enum class.

Returns: the class of your event enum

##### getControlObjectName(Object)

public String getControlObjectName(Object controlObject)

If you use control objects and a previously unknown control object is passed to Payload.enter, Payload.execute or Payload.execute, the JProfiler agent will call this method to associate a name with the control object. You can alternatively associate a name with a control object by calling Payload.openControlObject.

Parameters:

  • controlObject — the control object that has no name associated yet

Returns: a name that will be displayed in the JProfiler UI for this object

Constructors

SignatureDescription
PayloadProbe()

##### PayloadProbe()

public PayloadProbe()

Split

Import: import com.jprofiler.api.probe.embedded.Split;

@JProfilerEmbeddedClass
public class Split

By calling this class you can add an arbitrary split in the call tree, just like the URL splitting of JProfiler's built-in "HTTP server" probe.

You can either use a pair of Split.enter and Split.exit calls or the two execute wrappers. If you write your own wrapper in another JVM language it is advisable to use the Split.enter and Split.exit primitives.

When using the primitives, it is very important that a matching Split.exit is always called, so the exit call must be put in a finally block like this:

    Split.enter(MyProbe.class, "my split string");
    try {
        // your code
    } finally {
        Split.exit();
    }

Methods

SignatureReturnsDescription
enter(Class<? extends SplitProbe>, String)voidSplit the call tree with the given name.
exit()voidMarks the end of a split.
execute(Class<? extends SplitProbe>, String, Runnable)voidA wrapper for the Split.enter and Split.exit primitives for a Runnable.
execute(Class<? extends SplitProbe>, String, Callable<T>)TA wrapper for the Split.enter and Split.exit primitives for a Callable.
register(Class<? extends SplitProbe>)voidYou can register your probe independently of Split.enter and execute calls.

##### enter(Class<? extends SplitProbe>, String)

public static void enter(Class<? extends SplitProbe> probe, String name)

Split the call tree with the given name. A matching Split.exit call must always be called.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the line that should show up in the call tree. If null, the call tree won't be split.

##### exit()

public static void exit()

Marks the end of a split. A matching Split.enter call must have been called first.

##### execute(Class<? extends SplitProbe>, String, Runnable)

public static void execute(Class<? extends SplitProbe> probe, String name, Runnable runnable)

A wrapper for the Split.enter and Split.exit primitives for a Runnable.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the line that should show up in the call tree. If null, the call tree won't be split.
  • runnable — the runnable that will be executed inside the split.

##### execute(Class<? extends SplitProbe>, String, Callable)

public static <T> T execute(Class<? extends SplitProbe> probe, String name, Callable<T> callable) throws Exception

A wrapper for the Split.enter and Split.exit primitives for a Callable.

Parameters:

  • probe — the configuration class. Must not be null.
  • name — the line that should show up in the call tree. If null, the call tree won't be split.
  • callable — the callable that will be executed inside the split.

##### register(Class<? extends SplitProbe>)

public static void register(Class<? extends SplitProbe> probe)

You can register your probe independently of Split.enter and execute calls. As soon as the probe is registered it will be displayed in the JProfiler UI and telemetries can be recorded. You don't have to call this method if you don't want to start telemetry recording before an Split.enter or execute call takes place. Split.enter or execute will automatically register your probe.

Parameters:

  • probe — the configuration class. Must not be null.

Constructors

SignatureDescription
Split()

##### Split()

public Split()

SplitProbe

Import: import com.jprofiler.api.probe.embedded.SplitProbe;

@JProfilerEmbeddedClass
public abstract class SplitProbe

For each split probe, you have to create a subtype of this class and pass it as a class literal to the methods in Split. You can override the methods of this class to configure your probe.

If you return true in SplitProbe.isPayloads you can add additional custom telemetries by adding public static methods to your subclass that return a number type and are annotated with Telemetry.

Methods

SignatureReturnsDescription
isReentrant()booleanIf you want to create nested splits with this probe you can override this method and return true.
isPayloads()booleanYou can override this method and return true to create an entry in the probes section and record your top level splits as payloads.
getName()StringIf you return true in SplitProbe.isPayloads you can override this method to specify the display name of your probe.
getDescription()StringIf you return true in SplitProbe.isPayloads you can override this method to add a description for your probe in JProfiler's probe section.
isEvents()booleanIf you return true in SplitProbe.isPayloads, but want to hide the events view you can override this method and return false.
isDefaultTelemetries()booleanIf you return true in SplitProbe.isPayloads but want to remove the default payload telemetries you can override this method and return false.

##### isReentrant()

public boolean isReentrant()

If you want to create nested splits with this probe you can override this method and return true. Otherwise, only the top level call in the stack to the methods in Split will have an effect.

Returns: if nested splits will be recorded

##### isPayloads()

public boolean isPayloads()

You can override this method and return true to create an entry in the probes section and record your top level splits as payloads.

Returns: if the top level splits should also be recorded as payloads in the probes section

##### getName()

public String getName()

If you return true in SplitProbe.isPayloads you can override this method to specify the display name of your probe. In the JProfiler UI, this string is used for the view name in the "JVM & Custom Probes" section of the view selector. If you do not override this method, the simple class name of the probe is used.

Returns: the name of your probe

##### getDescription()

public String getDescription()

If you return true in SplitProbe.isPayloads you can override this method to add a description for your probe in JProfiler's probe section.

Returns: the description of your probe

##### isEvents()

public boolean isEvents()

If you return true in SplitProbe.isPayloads, but want to hide the events view you can override this method and return false.

Returns: if events are recorded for payloads

##### isDefaultTelemetries()

public boolean isDefaultTelemetries()

If you return true in SplitProbe.isPayloads but want to remove the default payload telemetries you can override this method and return false. The default telemetries are the event frequency and the average duration telemetries.

Returns: if the default telemetries will be recorded

Constructors

SignatureDescription
SplitProbe()

##### SplitProbe()

public SplitProbe()

ThreadState

Import: import com.jprofiler.api.probe.embedded.ThreadState;

@JProfilerEmbeddedClass
public final enum ThreadState

Allows you to override the thread state recorded in JProfiler.

You can nest calls to ThreadState.enter and ThreadState.exit, but only the outermost call is used for recording.

It is very important that a matching ThreadState.exit is always called, so the exit call must be put in a finally block like this:

    ThreadState.NETIO.enter();
    try {
        // your code
    } finally {
        ThreadState.exit();
    }

Constants

##### RUNNABLE

The current thread is runnable.

##### WAITING

The current thread is waiting.

##### BLOCKED

The current thread is blocked on a monitor.

##### NETIO

The current thread is in a Net IO operation.

Methods

SignatureReturnsDescription
values()ThreadState[]
valueOf(String)ThreadState
enter()voidEnters a thread state.
exit()voidExits the current override state and resets the state to the value reported by the JVM.

##### values()

public static ThreadState[] values()

##### valueOf(String)

public static ThreadState valueOf(String name)

##### enter()

public void enter()

Enters a thread state. This state will be recorded until the matching exit is called.

##### exit()

public static void exit()

Exits the current override state and resets the state to the value reported by the JVM.

TypeCustomizer

Import: import com.jprofiler.api.probe.embedded.TypeCustomizer;

interface TypeCustomizer

Interface to further customize event enums registered with PayloadProbe.getCustomTypes. Your enum class can implement this interface to customize the color of your types.

Methods

SignatureReturnsDescription
getColor()intThe color of your enum constant.

##### getColor()

int getColor()

The color of your enum constant.

Returns: the RGB int value of a color, for example 0xCCAA00

Package com.jprofiler.api.probe.embedded.telemetry

Contains the classes for adding custom telemetries to an embedded probe.

The Telemetry class contains further information.

Telemetry

Import: import com.jprofiler.api.probe.embedded.telemetry.Telemetry;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@interface Telemetry implements Annotation

Create a custom telemetry from the numeric return value of the annotated static method in your subclasses of PayloadProbe or SplitProbe.

Only public static parameterless methods can be used for creating custom telemetries, annotating instance methods or non-public static methods will not have any effect. The method must return a numeric value, either a primitive value like int or double, a java.math.BigDecimal or a primitive wrapper instance like java.lang.Integer or java.lang.Double.

The method is called periodically on a dedicated thread. This may have implications for the requirements of thread safety in your code. If the numeric value is calculated on the fly, access to the data structures must be made thread-safe by making access to those data structures synchronized. Alternatively, you could calculate a cached value when convenient and save it to a volatile atomic value, like an int or a class from the java.util.concurrent.atomic package.

For example, the following code snippet defines a custom telemetry with the name "Connection count":

&#064;Telemetry("Connection count")
    public static int getConnectionCount() {
        return connectionCount;
    }

Multiple lines in a single custom telemetry

If you want to compare several measurements in the same telemetry, you can annotate multiple methods with the same Telemetry.value for the telemetry name, but with a different Telemetry.line parameter.

For example:

&#064;Telemetry(value = "Queries", line = "Successful queries")
    public static int getSuccessCount() {
        return successCount;
    }
    &#064;Telemetry(value = "Queries", line = "Failed queries")
    public static int getErrorCount() {
        return errorCount;
    }

This will create a single custom telemetry with the name "Queries" and two data lines named "Successful queries" and "Failed queries".

Elements

ElementTypeDefaultDescription
valueString—The name of the telemetry.
lineString""The optional line name of the telemetry.
formatTelemetryFormat@com.jprofiler.api.probe.embedded.telemetry.TelemetryFormatOptional display options for the telemetry.

##### value

The name of the telemetry. Give different names to different telemetries. Reuse the same name when annotating different methods if you are creating a custom telemetry with multiple lines. If only a single line is used, you can omit the "value" parameter name, as in

&#064;Telemetry("Connection count")

##### line

The optional line name of the telemetry. Only specify this parameter if you're creating a telemetry with multiple lines. See Telemetry for an example.

##### format

Optional display options for the telemetry.

TelemetryFormat

Import: import com.jprofiler.api.probe.embedded.telemetry.TelemetryFormat;

@interface TelemetryFormat implements Annotation

Display options for a Telemetry annotation. This annotation is used by the Telemetry.format parameter.

Elements

ElementTypeDefaultDescription
valueTelemetryUnitPLAINThe unit of the recorded values.
scaleint0A scaling factor for the telemetry.
stackedbooleanfalseDetermines whether multiple lines in a telemetry should be stacked into an area graph.

##### value

The unit of the recorded values. By default, telemetries are unitless.

##### scale

A scaling factor for the telemetry. In the UI, recorded values will be multiplied with 10^-scale.

In JProfiler, probe telemetry data is stored in 32-bit ints. So this is especially useful for telemetries that will show higher values than 2^31. For example, if you use the TelemetryUnit.BYTES you can return kB instead and set the scale to -3.

This is also useful to show fractional values. For example, if you want to show a percentage with two decimal digits, the returned value should be the percentage times 100 and the scale parameter should be set to 2.

##### stacked

Determines whether multiple lines in a telemetry should be stacked into an area graph. By default, multiple telemetry lines are not stacked. An example of a stacked graph is the "Heap usage" telemetry.

TelemetryUnit

Import: import com.jprofiler.api.probe.embedded.telemetry.TelemetryUnit;

public final enum TelemetryUnit

Telemetry unit used in the TelemetryFormat annotation.

Constants

##### PLAIN

The telemetry value is a unitless number.

##### PER_SECOND

The telemetry value has the unit "per second".

##### PERCENT

The telemetry value has the unit "percent".

##### MILLISECONDS

The telemetry value has the unit "milliseconds". Conversion into higher unit prefixes such as seconds is done automatically as required.

##### MICROSECONDS

The telemetry value has the unit "microseconds". Conversion into higher unit prefixes such as seconds is done automatically as required.

##### BYTES

The telemetry value has the unit "bytes". Conversion into higher unit prefixes such as kB, MB or GB is done automatically as required.

In JProfiler, probe telemetry data is stored in 32-bit ints. If you expect higher values than 2^31 bytes, you can for example return kB instead and set TelemetryFormat.scale to -3.

Methods

SignatureReturnsDescription
values()TelemetryUnit[]
valueOf(String)TelemetryUnit

##### values()

public static TelemetryUnit[] values()

##### valueOf(String)

public static TelemetryUnit valueOf(String name)