0

I use the following code in order to start JFR recording and to save results in file. The file is indeed created, but how to parse it? I thought it should be jfr file type, but jdk.jfr.consumer.RecordingFile fails to parse it ("java.io.IOException: Not a Flight Recorder file"). Any help/examples will be appreciated.

    String host = "localhost";
    int port = 9999;
    String s = "/jndi/rmi://" + host + ":" + port + "/jmxrmi";
    JMXServiceURL url = new JMXServiceURL("rmi", "", 0, s);
    JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(url, null);
    jmxConnector.connect();
    MBeanServerConnection mbeanConnection = jmxConnector.getMBeanServerConnection();
    FlightRecorderMXBean frb = JMX.newMXBeanProxy(mbeanConnection, new ObjectName("jdk.management.jfr:type=FlightRecorder"),
            FlightRecorderMXBean.class);

    long recId = frb.newRecording();

    System.out.println("RECORDING STARTED");
    frb.startRecording(recId);
    Thread.sleep(60000);
    frb.stopRecording(recId);
    System.out.println("RECORDING ENDED");
            
    long streamId = frb.openStream(recId, null);

    FileOutputStream fw = new FileOutputStream("./jfrstream_" + recId);
    byte[] buff = frb.readStream(streamId);
    while (buff != null)
    {
        buff = frb.readStream(streamId);
        if (buff != null)
        {
            //System.out.println("buff.length=" + buff.length);
            fw.write(buff);
        }
    }
    frb.closeStream(streamId);
    fw.flush();
    fw.close();
    
user9517026
  • 103
  • 1
  • 4
  • 1
    Looks correct. I can reproduce the issue/bug. The only unusual thing I can see, but supported, is the null passed to readStream. Unit tests and JMC uses a map. https://github.com/openjdk/jdk/blob/master/test/jdk/jdk/jfr/jmx/TestStream.java – Kire Haglin Mar 22 '21 at 17:41
  • Thanks for a nice example. I'll try it. Other question: my recording lasts 1min. ExecutionSample events are supposed to be every 10ms. So I should get 6000 ExecutionSample events. Why I get only 14? – user9517026 Mar 22 '21 at 20:26
  • 1
    It's complicated, but it's not the number of events. Think 1 ms (maximum), 10 ms (high), 20 ms normal. If you don't have load on the machine, there will be very few event (if any). – Kire Haglin Mar 22 '21 at 23:34

1 Answers1

1

The problem is that you don't write the data for the first read.

The following code works:

File dump(long streamId, FlightRecorderMXBean bean) throws IOException {
  File f = new File("stream_" + streamId + ".jfr");
  try (var fos = new FileOutputStream(f); var bos = new BufferedOutputStream(fos)) {
    while (true) {
      byte[] data = bean.readStream(streamId);
       if (data == null) {
         bos.flush();
         return f;
       }
       bos.write(data);
    }
  }
}

Or you can use JDK 17, where a dump method has been added to RemoteRecordingStream and avoid the FlightRecorderMXBean all together.

try (var rrs = new RemoteRecordingStream(connection)) {
  rrs.start();
  rrs.stop();
  rrs.dump(Path.of("recording.jfr");
}
Kire Haglin
  • 6,569
  • 22
  • 27