Custom JDK Flight Recorder Events - Sip of Java

JDK Flight Recorder (JFR) is an event based profiling tool that comes built into the JDK. With an overhead of <1% on default settings, JFR can be used in production for tracking the behavior and performance of the Java runtime and applications, which can be useful for resolving production bugs or finding opportunities for performance optimizations.

As of JDK 18, there are over 150 pre-defined JFR event types covering events such as; thread creation and removal, GC pauses, memory allocation, and more. These events provide a rich and detailed view into the operations of the Java runtime and application. However there might be cases where there are gaps in the data being gathered, for this JFR also supports tracking of custom event types.

Creating and Using a Custom JFR Event

To create a custom JFR event, extend the jdk.jfr.Event class, like in the example below:

import jdk.jfr.Event;

public class MyEvent extends Event {

}

To use this event in your application, you will need to initialize the event, and then call .being() and .commit() around the code you want to track, like below:

public void myMethod(){
	MyEvent myEvent = new MyEvent();
	myEvent.begin();
	
	//...do work here
	
	myEvent.commit();
}

Currently the only information being captured is the execution time between the .begin() and .commit() and the stack. However custom events can capture additional information.

Allowed JFR Fields

Custom JFR events are allowed to have fields which JFR will collect, however those fields must be of the following types:

  • byte
  • short
  • int
  • long
  • float
  • double
  • char
  • boolean
  • java.lang.String, which may be null
  • java.lang.Thread, which may be null
  • java.lang.Class, which may be null

These fields can provide additional context to what is happening within an application, such as, client entered values, values returned from other systems, or other information a developer might finding beneficial. JFR will silently ignore fields of types other than the ones listed above.

JFR Annotations

JFR also provides annotations for controlling when an event is enabled, or for providing metadata. Key annotations to be aware of include:

  • Category: Event annotation, to associate the event type with a category, in the format of a human-readable path.
  • Description: Annotation that describes an element by using a sentence or two.
  • Enabled: Event annotation, determines if an event should be enabled by default.
  • Label: Annotation that sets a human-readable name for an element (for example, “Maximum Throughput”).
  • Name: Annotation that sets the default name for an element.
  • StackTrace: Event annotation, determines whether an event by default has a stack trace or not.
  • Threshold: Event annotation, specifies the default duration below which an event is not recorded (for example, “20 ms”).

Additional Annotations

There are several other annotations also pre-defined by JFR:

  • BooleanFlag: Event field annotation, specifies that the value is a boolean flag, a true or false value.
  • ContentType: Meta annotation, specifies that an annotation represents a content type, such as a time span or a frequency.
  • DataAmount: Event field annotation, specifies that a value represents an amount of data (for example, bytes).
  • Experimental: Annotation that specifies that an element is experimental and may change without notice.
  • Frequency: Event field annotation, specifies that the value is a frequency, measured in Hz.
  • MemoryAddress: Event field annotation, specifies that the value is a memory address.
  • MetadataDefinition: Meta annotation for defining new types of event metadata.
  • Percentage: Event field annotation to use on fractions, typically between 0.0 and 1.0, to specify that the value is a percentage.
  • Period: Event annotation, specifies the default setting value for a periodic event.
  • Registered: Event annotation, for programmatic event registration.
  • Relational: Meta annotation for relational annotations, to be used on an annotation.
  • SettingDefinition: Annotation that specifies that a method in an event class should be used to filter out events.
  • Timespan: Event field annotation, specifies that the value is a duration.
  • Timestamp:Event field annotation, specifies that the value is a point in time.
  • TransitionFrom: Event field annotation, specifies that the event transitioned from a thread.
  • TransitionTo: Event field annotation, specifies that the event will soon transition to a thread.
  • Unsigned: Event field annotation, specifies that the value is of an unsigned data type.

Configuring JFR Events

Events, both pre-defined, and custom, can be configured with a .jfc file or via command line. Configuring an event in a .jfc file would look like the following:

<configuration>
	...
	<event name="com.oracle.jfr.MyEvent">
   		<setting name="enabled">true</setting>
	</event>
	...
</configuration>

Note: If the @Name tag is not used, the default name of an event will be its fully qualified name.

Events can also be configured via the command line like in the below example:

-XX:StartFlightRecording=event-setting=<event-name>#<setting-name>=<value>

Further Reading

For more information on the JDK Flight Recorder, its API, or using JDK Flight Recorder in your application, be sure to check the following links:

Happy coding!