Control JFR Programmatically
- November 19, 2020
- 2057 Unique Views
- 2 min read
Continuing from part 1 and part 2, while from JDK 14 events can be consumed on the fly, previous JDK versions (from JDK 11) offer a public API useful enough to control Flight Recorder programmatically or to read events from a JFR file.
Configuration c = Configuration.getConfiguration("profile"); [1]
Recording r = new Recording(c);
r.setName("monitor jvm");
r.enable("jdk.*"); [2]
r.setMaxAge(java.time.Duration.ofMinutes(4)); [3]
r.start(); [4]
// to be profiled
r.stop(); [5]
r.dump(Files.createFile("/var/log/jfr/app-initiated.jfr")); [6]
- As shown above, choose the JFR configuration.
- Choose which events the recording should be interested in. Another signature accepts classes, it’s unlikely to be helpful for JDK events, but it may get interesting for custom events, your classes.
- Eventually set recording constraints, like the maximum age of the records.
- Hit record.
- When the recording session is over, stop JFR.
- Then store the results in the location of your choosing.
The above snippet creates a continuous profiling session with a 4 minute window.
Now the API allows reading emitted .jfr files. The API represents what’s actually in a file, a schema of the events and the events themselves.
try(RecordingFile rf = new RecordingFile(Paths.get("/var/log/jfr/app-initiated.jfr"))( { [1]
// read the schema
rf.readEventTypes().forEach((EventType et) -> { [2]
System.out.println(et.getName());
et.getFields()
.stream()
.map((ValueDescriptor vd) -> vd.getName())
.forEach(System.out::println);
});
// actual events
for(jdk.jfr.consumer.RecordedEvent e = rf.readEvent(); rf.hasMoreEvents(); e = rf.readEvent()) { [3]
System.out.println(e.getEventType().getName()); [4]
}
}
- Open the JFR file, it’s a
Closeableand it reads a file, so be sure to use it in atry-with-resourcesblock. readEventTypes()gets you the schema of the events, fields name, labels, thresholds, etc.- Then there’s this weird enumeration style API to read the events
hasMoreEvents()andreadEvent(). - Access details on the event type.
RecordingFile API is a bit awkward to work with, more specifically parsing each event requires looking at the event descriptor (via getEventType(), or getFields()), and interrogate the event as fields presence may evolve with each JDK revision. The javadoc advises defensive programming style when reading a JFR file:
if (event.hasField("intValue")) {
int intValue = event.getValue("intValue");
System.out.println("Int value: " + intValue);
}
This API is now complemented by streaming live events JEP-349 in JDK 14 using an API RecordingStream that is mix of the above, that’s out of scope for this article. But that’s yet another reason to make the effort to upgrade our JDK.
Such API facilities are useful especially when combined with other technologies like Spring Actuators. Yet when there’s available integration or when using these integrations is too late, like recording startup, the most actionable way to get recording is from the command line.
______________________________________________________________________________
Used with permission and thanks, initially written and published by Brice Dutheil in his blog.
Don’t Forget to Share This Post!
Comments (2)
Tobiloba
3 years agoI see that you save the point of interest as text in the DB but the response gotten from ChatGPT is JSON. Does this mean you convert the response into string using libraries like gson before saving it in the database?
Denis Magda
3 years agoHey, The response is a String object in the JSON format [1]. The repository takes this JSON string as is and stores to the database [2]. Presently, Spring Data auto-generates the CREATE TABLE statement on the startup and sets the "point of interest" column's type to "text" (or "varchar", don't remember). However, it's always possible to ask Spring Data to use the "json" or "jsonb" type for the column if you wish to query the JSON at the database level. Finally, Vaadin displays a list of PointsOfInterests. Those are generated using the org.json library [3]. Let me know if you have other questions. Hope this helps. [1] https://github.com/YugabyteDB-Samples/budget-journey-gpt/blob/main/src/main/java/com/yugabyte/com/TripsAdvisorService.java#L103 [2] https://github.com/YugabyteDB-Samples/budget-journey-gpt/blob/main/src/main/java/com/yugabyte/com/TripsAdvisorService.java#L74 [3] https://github.com/YugabyteDB-Samples/budget-journey-gpt/blob/main/src/main/java/com/yugabyte/com/TripsAdvisorService.java#L114