模块 jdk.jfr

接口 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() 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

自从:
14
  • 方法详情

    • 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 - 如果在流开始后添加了一个动作
      自从:
      16
    • onEvent

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

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

      参数:
      action - 对每个 RecordedEvent 执行的操作,而不是 null
      参见:
    • onEvent

      void onEvent(String  eventName, Consumer <RecordedEvent > action)
      注册一个操作以对所有匹配名称的事件执行。
      参数:
      eventName - 事件的名称,而不是 null
      action - 对每个与事件名称匹配的 RecordedEvent 执行的操作,而不是 null
    • onFlush

      void onFlush(Runnable  action)
      注册在流被刷新后执行的操作。
      参数:
      action - 在刷新流后执行的操作,而不是 null
    • onError

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

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

      注册一个动作会重写默认行为。如果注册了多个动作,则按照注册的顺序执行。

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

      参数:
      action - 发生异常时要执行的操作,而不是 null
    • onClose

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

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

      参数:
      action - 在流关闭后执行的操作,而不是 null
      参见:
    • close

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

      如果一个流以异步或同步方式启动,它会立即停止或在下一次刷新后停止。此方法确实NOT保证所有已注册的操作在返回前完成。

      关闭之前关闭的流没有任何效果。

      指定者:
      close 在接口 AutoCloseable
    • remove

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

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

      参数:
      action - 注销操作,而不是 null
      返回:
      true 如果操作未注册,false 否则
      参见:
    • setReuse

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

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

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

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

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

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

      参数:
      startTime - 开始时间,而不是 null
      抛出:
      IllegalStateException - 如果流已经开始
      参见:
    • setEndTime

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

      必须在开始流之前设置结束时间。

      在结束时间,流关闭。

      参数:
      endTime - 结束时间,而不是 null
      抛出:
      IllegalStateException - 如果流已经开始
      参见:
    • start

      void start()
      开始处理动作。

      操作在当前线程中执行。

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

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

      void startAsync()
      开始异步处理动作。

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

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

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

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

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