Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8263332

JFR: Dump recording from a recording stream

    XMLWordPrintable

    Details

    • Type: Enhancement
    • Status: Resolved
    • Priority: P3
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 17
    • Component/s: hotspot
    • Labels:
      None
    • Subcomponent:
      jfr
    • Resolved In Build:
      b26

      Description

      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?



        Attachments

          Issue Links

            Activity

              People

              Assignee:
              egahlin Erik Gahlin
              Reporter:
              egahlin Erik Gahlin
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: