Module jdk.jfr
Package jdk.jfr.consumer

Interface EventStream

所有超接口:
AutoCloseable
所有已知实现类:
RecordingStream, RemoteRecordingStream

public interface EventStream extends AutoCloseable
表示事件流。

流是事件序列,与流交互的方式是注册操作。不应实现EventStream接口,未来的JDK版本可能会完全禁止这样做。

要在事件到达时接收通知,请使用onEvent(Consumer)方法注册操作。要过滤具有特定名称的事件流,请使用onEvent(String, Consumer)方法。

默认情况下,相同的RecordedEvent对象可用于表示两个或多个不同的事件。该对象可以多次传递给相同的操作,也可以传递给其他操作。要在操作完成后使用事件对象,应将setReuse(boolean)方法设置为false,以便为每个事件分配一个新对象。

事件以批次传递。要在批次完成时接收通知,请使用onFlush(Runnable)方法注册操作。这是一个机会,可以在Java虚拟机(JVM)准备下一批时聚合或将数据推送到外部系统。

批次内的事件按其结束时间按时间顺序排序。事件的良序仅对JVM在刷新点可用的事件保持,即作为单个批次传递的事件集。因此,批次中传递的事件可能与先前批次中传递的事件不一致,但永远不会与同一批次中的事件不一致。如果不关心排序,可以使用setOrdered(boolean)方法禁用排序。

要将事件分派给已注册的操作,必须启动流。要在当前线程中开始处理,请调用start()方法。要在单独的线程中异步处理操作,请调用startAsync()方法。要等待流的完成,请使用awaitTermination()awaitTermination(Duration)方法。

当流结束时,它会自动关闭。要手动停止事件处理,请通过调用close()方法关闭流。在异常情况下,例如被监视的JVM退出时,流也可以自动关闭。要在任何这些情况下接收通知,请使用onClose(Runnable)方法注册操作。

如果操作中发生意外异常,可以在错误处理程序中捕获异常。可以使用onError(Consumer)方法注册错误处理程序。如果未注册错误处理程序,则默认行为是将异常及其回溯打印到标准错误流。

以下示例显示了如何使用EventStream来监听运行Flight Recorder的JVM上的事件

try (var es = EventStream.openRepository()) {
    es.onEvent("jdk.CPULoad", event -> {
        System.out.println("CPU Load " + event.getEndTime());
        System.out.println(" Machine total: " + 100 * event.getFloat("machineTotal") + "%");
        System.out.println(" JVM User: " + 100 * event.getFloat("jvmUser") + "%");
        System.out.println(" JVM System: " + 100 * event.getFloat("jvmSystem") + "%");
        System.out.println();
    });
    es.onEvent("jdk.GarbageCollection", event -> {
        System.out.println("Garbage collection: " + event.getLong("gcId"));
        System.out.println(" Cause: " + event.getString("cause"));
        System.out.println(" Total pause: " + event.getDuration("sumOfPauses"));
        System.out.println(" Longest pause: " + event.getDuration("longestPause"));
        System.out.println();
    });
    es.start();
}

要与流一起开始记录,请参见RecordingStream

自 JDK 版本:
14
  • Method Details

    • openRepository

      static EventStream openRepository() throws IOException
      从当前Java虚拟机(JVM)的存储库创建流。

      默认情况下,流从Flight Recorder刷新的下一个事件开始。

      返回:
      一个事件流,非null
      抛出:
      IOException - 如果无法打开流,或在尝试访问存储库时发生I/O错误
      SecurityException - 如果存在安全管理器并且调用者没有FlightRecorderPermission("accessFlightRecorder")
    • openRepository

      static EventStream openRepository(Path directory) throws IOException
      从磁盘存储库创建事件流。

      默认情况下,流从Flight Recorder刷新的下一个事件开始。

      只应打开受信任的磁盘存储库。

      参数:
      directory - 磁盘存储库的位置,非null
      返回:
      一个事件流,非null
      抛出:
      IOException - 如果无法打开流,或在尝试访问存储库时发生I/O错误
      SecurityException - 如果存在安全管理器并且其checkRead方法拒绝对目录或目录中的文件的读取访问
    • openFile

      static EventStream openFile(Path file) throws IOException
      从文件创建事件流。

      默认情况下,流从文件中的第一个事件开始。

      只应打开来自受信任来源的记录文件。

      参数:
      file - 文件的位置,非null
      返回:
      一个事件流,非null
      抛出:
      IOException - 如果无法打开文件,或在读取过程中发生I/O错误
      SecurityException - 如果存在安全管理器并且其checkRead方法拒绝对文件的读取访问
    • onMetadata

      default void onMetadata(Consumer<MetadataEvent> action)
      注册在流中新元数据到达时执行的操作。事件的事件类型总是在实际事件之前到达。操作必须在流开始之前注册。

      以下示例显示了如何监听新事件类型,如果事件类型名称与正则表达式匹配,则注册操作,并且如果找到匹配的事件,则增加计数器。使用每个事件类型一个操作,而不是通用的onEvent(Consumer)方法的好处是,流实现可以避免读取不感兴趣的事件。

      static long count = 0;
      public static void main(String... args) throws IOException {
          Path file = Path.of(args[0]);
          String regExp = args[1];
          var pr = Pattern.compile(regExp).asMatchPredicate();
          try (var s = EventStream.openFile(file)) {
              s.setOrdered(false);
              s.onMetadata(metadata -> metadata.getAddedEventTypes()
               .stream().map(EventType::getName).filter(pr)
               .forEach(eventName -> s.onEvent(eventName, event -> count++)));
              s.start();
              System.out.println(count + " events matches " + regExp);
          }
      }
      
      实现要求:
      此方法的默认实现为空。
      参数:
      action - 要执行的操作,非null
      抛出:
      IllegalStateException - 如果在流开始后添加了操作
      自 JDK 版本:
      16
    • onEvent

      void onEvent(Consumer<RecordedEvent> action)
      注册一个在流中的所有事件上执行的操作。

      要在事件类型的子集上执行操作,请考虑使用onEvent(String, Consumer)onMetadata(Consumer),因为这可能比在通用操作中实现的任何选择或过滤机制更高效。

      参数:
      action - 在每个RecordedEvent上执行的操作,不能为空
      参见:
    • onEvent

      void onEvent(String eventName, Consumer<RecordedEvent> action)
      注册一个在匹配名称的所有事件上执行的操作。
      参数:
      eventName - 事件的名称,不能为空
      action - 在匹配事件名称的每个RecordedEvent上执行的操作,不能为空
    • onFlush

      void onFlush(Runnable action)
      注册一个在流刷新后执行的操作。
      参数:
      action - 在流刷新后执行的操作,不能为空
    • onError

      void onError(Consumer<Throwable> action)
      注册一个在发生异常时执行的操作。

      如果未注册操作,则异常堆栈跟踪将打印到标准错误输出。

      注册操作会覆盖默认行为。如果已注册多个操作,则按注册顺序执行它们。

      如果此方法本身引发异常,则结果行为是未定义的。

      参数:
      action - 在发生异常时执行的操作,不能为空
    • onClose

      void onClose(Runnable action)
      注册一个在流关闭时执行的操作。

      如果流已关闭,则操作将立即在当前线程中执行。

      参数:
      action - 在流关闭后执行的操作,不能为空
      参见:
    • close

      void close()
      释放与此流关联的所有资源。

      如果流已启动(异步或同步),则立即停止或在下一次刷新后停止。此方法不保证在返回之前完成所有已注册的操作。

      关闭先前关闭的流不会产生任何效果。

      指定者:
      close 在接口 AutoCloseable
    • remove

      boolean remove(Object action)
      注销一个操作。

      如果操作已注册多次,则所有实例都将被注销。

      参数:
      action - 要注销的操作,不能为空
      返回:
      true表示操作已注销,否则为false
      参见:
    • setReuse

      void setReuse(boolean reuse)
      指定在onEvent(Consumer)操作中的事件对象可以被重用。

      如果重用设置为true,则操作完成后不应保留对事件对象的引用。

      参数:
      reuse - 如果可以重用事件对象,则为true,否则为false
    • setOrdered

      void setOrdered(boolean ordered)
      指定事件按照它们提交到流中的时间按时间顺序到达。
      参数:
      ordered - 如果事件对象按时间顺序到达onEvent(Consumer)
    • setStartTime

      void setStartTime(Instant startTime)
      指定流的开始时间。

      必须在启动流之前设置开始时间

      参数:
      startTime - 开始时间,不能为空
      抛出:
      IllegalStateException - 如果流已经启动
      参见:
    • setEndTime

      void setEndTime(Instant endTime)
      指定流的结束时间。

      必须在启动流之前设置结束时间。

      在结束时间时,流将关闭。

      参数:
      endTime - 结束时间,不能为空
      抛出:
      IllegalStateException - 如果流已经启动
      参见:
    • start

      void start()
      开始执行操作。

      操作在当前线程中执行。

      要停止流,请使用close()方法。

      抛出:
      IllegalStateException - 如果流已经启动或关闭
    • startAsync

      void startAsync()
      开始异步执行操作。

      操作在单独的线程中执行。

      要停止流,请使用close()方法。

      抛出:
      IllegalStateException - 如果流已经启动或关闭
    • awaitTermination

      void awaitTermination(Duration timeout) throws InterruptedException
      阻塞直到所有操作完成,或流关闭,或超时发生,或当前线程被中断,以先发生者为准。
      参数:
      timeout - 等待的最长时间,不能为空
      抛出:
      IllegalArgumentException - 如果超时为负数
      InterruptedException - 在等待时被中断
      参见:
    • awaitTermination

      void awaitTermination() throws InterruptedException
      阻塞直到所有操作完成,或流关闭,或当前线程被中断,以先发生者为准。
      抛出:
      InterruptedException - 在等待时被中断
      参见: