JFR Event Stream - Sip of Java
Billy Korando on May 12, 2022JDK Flight Recorder (JFR) is an event-based tool for monitoring and profiling built into the JDK. JFR has a very low overhead of <1% using default settings allowing it to be used in production. Typically extracting information out of JFR requires performing a dump; however, added in JDK 14, the package jdk.jfr.consumer
provides APIs for the consumption of JFR events without requiring a JFR dump to be done. Let’s take a look at how this API can be used.
Creating JFR Event Streams
The central class in the new Event Streaming API is the interface jdk.jfr.consumer.EventStream
, which, as the name suggests, represents a stream of events.
EventStream Factory Methods
EventStream
provides three factory methods for creating a new EventStream
instance:
openFile(java.nio.file.Path)
- Creates anEventStream
from a recording file.openRepository()
- Creates anEventStream
from the repository of the current JVM.openRepository(java.nio.file.Path)
- Creates anEventStream
from a directory.
EventStream Implementations
There are also two public implementations which can be instantiated as well:
jdk.jfr.consumer.RecordingStream
- A recording stream of the current JVM.jdk.management.jfr.RemoteRecordingStream
- A recording stream that can serialize events using ajavax.management.MBeanServerConnection
Registering Events
Once an EventStream
has been created, actions can be registered to it. There are two ways of registering actions for events:
-
onEvent(consumer)
- all events will be registered to this action. -
onEvent(String, Consumer)
- only events whose name matches will be registered to this action.
Additionally actions can be registered for when other conditions are met:
onClose(Runnable)
- Registers an action to perform when the stream is closed.onError(Consumer<Throwable>)
- Registers an action to perform if an exception occurs.onFlush(Runnable)
- Registers an action to perform after the stream has been flushed.onMetadata(Consumer<MetadataEvent>)
- Registers an action to perform when new metadata arrives in the stream.Example
An example of creating a JFR event stream might look like this. In this example, the stream checks for when a monitored process is reading from a file and prints to console the event’s start time, end time, and total duration.
try (EventStream es = EventStream.openRepository()) {
es.onEvent("jdk.FileRead", event -> {
System.out.println("File read!");
System.out.println("Start: " + event.getStartTime());
System.out.println("End: " + event.getEndTime());
System.out.println("Duration: " + event.getDuration());
});
es.start();
}
Attaching Streams
A JFR event stream can be attached as both an in-process and an external process. Examples of how a JFR event stream can be attached to an external process include:
- Java Agent
- Process Id
- JMX Socket
- Read from a recording file
- And more!
JFR Event Streams Performance Overhead
While JFR targets a <1% overhead with default settings, how a JFR Event Stream is implemented can impact performance. How many events are registered to the stream and the action(s) behavior will determine the performance impact for an in-process stream.
For external streams, how events are retrieved might impact performance. If events are streamed over a JMX socket, that will require the stream events to be serialized, which could mean significant overhead. However, if the external stream is reading from a recording file or directory, this will not put any additional overhead on the monitored process.
Additional Reading
- JEP 349
jdk.jfr.consumer
JavaDoc- Flight Recorder API Programmer’s Guide
- Remote Recording Stream
- Java Event Stream Example
Happy coding!