Part V Parsing a Recording File

The example ParseRecordingFileSample.java describes various ways you can parse a recording file. It starts a recording to record several Hello and Message events.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

import jdk.jfr.Event;
import jdk.jfr.EventType;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.Recording;
import jdk.jfr.consumer.EventStream;
import jdk.jfr.consumer.RecordingFile;

public class ParseRecordingFileSample {
    
    @Name("com.oracle.Hello")
    @Label("Hello World!")
    static class Hello extends Event {
        @Label("Greeting")
        String greeting;
    }
    
    @Name("com.oracle.Message")
    @Label("Message")
    static class Message extends Event {
        @Label("Text")
        String text;
    }

    public static void main(String... args) throws IOException {

        try (Recording r = new Recording()) {
            r.start();
            for (int i = 0; i < 3; i++) {
                Message messageEvent = new Message();
                messageEvent.begin();
                messageEvent.text = "message " + i;
                messageEvent.commit();
                
                Hello helloEvent = new Hello();
                helloEvent.begin();
                helloEvent.greeting = "hello " + i;
                helloEvent.commit();
            }
            r.stop();
            Path file = Files.createTempFile("recording", ".jfr");
            r.dump(file);
          
            try (var recordingFile = new RecordingFile(file)) {
                System.out.println("Reading events one by one");
                System.out.println("=========================");
                while (recordingFile.hasMoreEvents()) {
                    var e = recordingFile.readEvent();
                    String eventName = e.getEventType().getName();
                    System.out.println("Name: " + eventName);
                }
                System.out.println();
                System.out.println("List of registered event types");
                System.out.println("==============================");
                for (EventType eventType : recordingFile.readEventTypes())
                {
                    System.out.println(eventType.getName());
                }
            }
            System.out.println();

            System.out.println("Reading all events at once");
            System.out.println("==========================");
            
            for (var e : RecordingFile.readAllEvents(file)) {
                String eventName = e.getEventType().getName();
                System.out.println("Name: " + eventName);
            }
            System.out.println();
            
            System.out.println("Reading events one by one, printing only "
                    + "com.oracle.Message events");
            System.out.println("========================================="
                    + "=========================");
            
            try (EventStream eventStream = EventStream.openFile(file)) {
                eventStream.onEvent("com.oracle.Message", e -> {
                    System.out.println(
                        "Name: " + e.getEventType().getName());
                });
                eventStream.start();
            }
        }
    }
}

Run ParseRecordingFileSample with this command:

java ParseRecordingFileSample.java

When running ParseRecordingFileSample, you don't have to start Flight Recorder with the command-line option -XX:StartFlightRecording; the method Recording.start() starts it. ParseRecordingFileSample prints the following:

Reading events one by one
=========================
Name: com.oracle.Message
Name: com.oracle.Hello
Name: com.oracle.Message
Name: com.oracle.Hello
Name: com.oracle.Message
Name: com.oracle.Hello

List of registered event types
==============================
jdk.ThreadStart
jdk.ThreadEnd
jdk.ThreadSleep
...
jdk.X509Validation
com.oracle.Message
com.oracle.Hello

Reading all events at once
==========================
Name: com.oracle.Message
Name: com.oracle.Hello
Name: com.oracle.Message
Name: com.oracle.Hello
Name: com.oracle.Message
Name: com.oracle.Hello

Reading events one by one, printing only com.oracle.Message events
==================================================================
Name: com.oracle.Message
Name: com.oracle.Message
Name: com.oracle.Message

Write Recording Data to a File

ParseRecordingFileSample demonstrates several ways you can parse a recording file. However, you first need a recording file, and this sample doesn't create one at the command line. Instead, it calls Recording.dump(Path) to write recording data to a temporary file:
Path file = Files.createTempFile("recording", ".jfr");
r.dump(file);
Note that the recording must be started but not necessarily stopped.

Read Events One by One

Use this technique for large recordings and if you need to access metadata.

The method RecordingFile.readEvent() reads the next event in the recording while RecordingEvent.hasMoreEvents() returns true if unread events exist in the recording file:

while (recordingFile.hasMoreEvents()) {
    var e = recordingFile.readEvent();
    String eventName = e.getEventType().getName();
    System.out.println("Name: " + eventName);
}

List Registered Event Types

The method RecordingFile.readEventTypes() returns a list of all event types in the recording.

Read All Events at Once

Use this technique for smaller recordings that fit in memory.

The method RecordingFile.readAllEvents(Path) returns a list of all events in the recording file. It's intended for small recording files where it's more convenient to read all events in a single operation. It's not intended for reading large recording files.

Read Only Specific Events with Event Streaming API

To process only specific events, you could read events one by one with RecordingFile.readEvent(), as described previously, then check the event's name. However, if you use the event streaming API, then event objects of the same type are reused to reduced allocation pressure.

This technique involves creating an event stream with EventStream.openFile(Path), then calling EventStream.onEvent(String eventName, Consumer) to register an action that will be performed if eventName matches the event's name:

try (EventStream eventStream = EventStream.openFile(file)) {
    eventStream.onEvent("com.oracle.Message", e -> {
        System.out.println("Name: " +
            e.getEventType().getName());
    });
    eventStream.start();
}