もともとこんな感じで同期で作っていたので「es.start()
の部分をes.startAsync()
にしたら非同期になるだろ」と思いやったらイベントが全然処理されない。
import jdk.jfr.Configuration; import jdk.jfr.consumer.EventStream; import jdk.jfr.consumer.RecordingStream; public class JfrEventStreamingInProcessAsync { public static void main(String[] args) throws Exception { Configuration config = Configuration.getConfiguration("default"); try (EventStream es = new RecordingStream(config)) { es.onEvent("jdk.CPULoad", System.out::println); es.start(); } } }
デバッグ実行で調べてみると、JFR Event Streamng の非同期実行が始まる前に、非同期実行とストリーミング用のJFRがなぜか止まってしまい処理できないようだ。
JFR Event Streamingスレッドがclose()
を呼ぶ前にステータスがcloseされてしまうので、別のスレッドがclose()
を実行しているに違いない。
どうやら、EventStream
をtry-catch-resoucesで作っていたのでAutoClosableによりmainスレッドがclose()
を実行し、その後立ち上がってくるJFR Event Streamingスレッドが処理をする頃にはJFRが停止させられてしまっていた。
なのでtry-catch-resourcesをやめたのと、アプリケーションが終了する時にclose()
メソッドが呼ばれるようにした。Quarkus での実装例は以下のようにApplicationScoped
を使用しました。ただのJavaアプリで実装する時は、onStart
の部分をpreMain
で、onStop
の部分をシャットダウンフックで実装すれば良いと思います。
@ApplicationScoped public class JfrEventStreamingApplicationBean { private EventStream es; void onStart(@Observes StartupEvent ev) { try { Configuration config = Configuration.getConfiguration("default"); this.es = new RecordingStream(config); this.es.onEvent("jdk.CPULoad", System.out::println); this.es.startAsync(); } catch (ParseException | IOException e) { System.err.println("Couldn't start JFR Event Streaming"); } } void onStop(@Observes ShutdownEvent ev) { if (this.es != null) { es.close(); } } }