Today it's possible to stream events using the EventStream, RecordingStream and RemoteRecordingStream classes and it works well for application monitoring.
However, sometimes it's also interesting to get a recording dump to do a more thorough analysis using tools such as JDK Mission Control. This can be achieved using the classes Recording and FlightRecorderMXBean, but for convenience and reduced overhead, especially when streaming events from a remote host, it may be beneficial to allow the dump to be done on the stream directly. Users can then react to events appearing in the stream by taking a recording dump, which gives them history and essential context for troubleshooting a problem.
One way to do this is to augment the RemoteRecordingStream with a dump method, for example, if monitoring high CPU usage on a remote process:
private int count = 0;
private double[] userLoad= new double[30];
...
try (var stream = new RemoteRecordingStream(connection)) {
stream.setSettings(Configuration.getConfiguration("default").toSettings()));
stream.onEvent("jdk.CPULoad", event -> {
userLoad[count%30] = event.getDouble("jvmUser");
double average = Arrays.stream(userLoad).average().getAsDouble();
count++;
if (average > 0.95) {
String now = Instant.now().truncatedTo(ChronoUnit.SECONDS).toString();
now = now.replace("-" ,"").replace(":", "");
Path p = Path.of("High_CPU_" + now + ".jfr);
stream.dump(p);
Arrays.fill(userLoad, 0.0);
}
}
stream.start();
}
The dump is created from data already transferred to the client, and the amount to keep at the client can be set by setMaxAge(Duration) and setMaxSize(long) methods before the incident happens. This is probably sufficient for most cases, but one could imagine a scenario where the amount of data to dump will depend on the problem at hand. For example, in a high CPU load scenario, 30 seconds might be sufficient, but you may want 5 minutes or more if it is something else.
One way to do this is to expose a clone of the underlying recording object, somewhat similar to the copy(boolean) method that exists today for the Recording class. This gives the user flexibility to set maxAge and maxSize per dump.
try (Recording recording = stream.takeSnapshot()) {
r.setMaxAge(Duration.ofSeconds(30));
String now = Instant.now().truncatedTo(ChronoUnit.SECONDS).toString();
now = now.replace("-" ,"").replace(":", "");
Path p = Path.of("high_cpu_" + now) + ".jfr);
recording.dump(p);
}
Today, once the client consumes event data, it is removed unless maxAge or maxSize is set. One problem with a takeSnapshot() methods is determining what to do if maxAge or maxSize has not been set. An empty recording? A recording of the last chunk? IllegalStateException?
However, sometimes it's also interesting to get a recording dump to do a more thorough analysis using tools such as JDK Mission Control. This can be achieved using the classes Recording and FlightRecorderMXBean, but for convenience and reduced overhead, especially when streaming events from a remote host, it may be beneficial to allow the dump to be done on the stream directly. Users can then react to events appearing in the stream by taking a recording dump, which gives them history and essential context for troubleshooting a problem.
One way to do this is to augment the RemoteRecordingStream with a dump method, for example, if monitoring high CPU usage on a remote process:
private int count = 0;
private double[] userLoad= new double[30];
...
try (var stream = new RemoteRecordingStream(connection)) {
stream.setSettings(Configuration.getConfiguration("default").toSettings()));
stream.onEvent("jdk.CPULoad", event -> {
userLoad[count%30] = event.getDouble("jvmUser");
double average = Arrays.stream(userLoad).average().getAsDouble();
count++;
if (average > 0.95) {
String now = Instant.now().truncatedTo(ChronoUnit.SECONDS).toString();
now = now.replace("-" ,"").replace(":", "");
Path p = Path.of("High_CPU_" + now + ".jfr);
stream.dump(p);
Arrays.fill(userLoad, 0.0);
}
}
stream.start();
}
The dump is created from data already transferred to the client, and the amount to keep at the client can be set by setMaxAge(Duration) and setMaxSize(long) methods before the incident happens. This is probably sufficient for most cases, but one could imagine a scenario where the amount of data to dump will depend on the problem at hand. For example, in a high CPU load scenario, 30 seconds might be sufficient, but you may want 5 minutes or more if it is something else.
One way to do this is to expose a clone of the underlying recording object, somewhat similar to the copy(boolean) method that exists today for the Recording class. This gives the user flexibility to set maxAge and maxSize per dump.
try (Recording recording = stream.takeSnapshot()) {
r.setMaxAge(Duration.ofSeconds(30));
String now = Instant.now().truncatedTo(ChronoUnit.SECONDS).toString();
now = now.replace("-" ,"").replace(":", "");
Path p = Path.of("high_cpu_" + now) + ".jfr);
recording.dump(p);
}
Today, once the client consumes event data, it is removed unless maxAge or maxSize is set. One problem with a takeSnapshot() methods is determining what to do if maxAge or maxSize has not been set. An empty recording? A recording of the last chunk? IllegalStateException?
- csr for
-
JDK-8266266 JFR: Dump recording from a recording stream
-
- Closed
-
- relates to
-
JDK-8268138 docs build error after JDK-8263332 integration
-
- Resolved
-