From 046bf087d7c2cd54bc2f191fbf06d0816e09f621 Mon Sep 17 00:00:00 2001 From: Artyom Gabeev Date: Sat, 7 Sep 2024 12:26:47 +0300 Subject: [PATCH] extract java21 module --- build.gradle | 2 +- micrometer-java21/build.gradle | 18 ++++++ .../jfr/JfrVirtualThreadEventMetrics.java | 63 ++++++++++++++----- .../JfrVirtualThreadEventMetricsTests.java | 58 +++++++++++++++++ settings.gradle | 1 + 5 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 micrometer-java21/build.gradle rename micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/JvmVirtualThreadEventMetrics.java => micrometer-java21/src/main/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetrics.java (53%) create mode 100644 micrometer-java21/src/test/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetricsTests.java diff --git a/build.gradle b/build.gradle index 3474c52ccd..b6d2e0f452 100644 --- a/build.gradle +++ b/build.gradle @@ -337,7 +337,7 @@ subprojects { check.dependsOn("testModules") - if (!(project.name in ['micrometer-registry-prometheus', 'micrometer-registry-prometheus-simpleclient', 'micrometer-jakarta9', 'micrometer-java11', 'micrometer-jetty12'])) { // add projects here that do not exist in the previous minor so should be excluded from japicmp + if (!(project.name in ['micrometer-registry-prometheus', 'micrometer-registry-prometheus-simpleclient', 'micrometer-jakarta9', 'micrometer-java11', 'micrometer-java21', 'micrometer-jetty12'])) { // add projects here that do not exist in the previous minor so should be excluded from japicmp apply plugin: 'me.champeau.gradle.japicmp' apply plugin: 'de.undercouch.download' diff --git a/micrometer-java21/build.gradle b/micrometer-java21/build.gradle new file mode 100644 index 0000000000..cce86c6a5e --- /dev/null +++ b/micrometer-java21/build.gradle @@ -0,0 +1,18 @@ +description 'Micrometer core classes that require Java 21' + +dependencies { + api project(":micrometer-core") + + testImplementation 'org.awaitility:awaitility' + testImplementation project(":micrometer-observation-test") +} + +java { + targetCompatibility = 21 +} + +tasks.withType(JavaCompile).configureEach { + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 + options.release = 21 +} diff --git a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/JvmVirtualThreadEventMetrics.java b/micrometer-java21/src/main/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetrics.java similarity index 53% rename from micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/JvmVirtualThreadEventMetrics.java rename to micrometer-java21/src/main/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetrics.java index ba884348d2..4fc14579e9 100644 --- a/micrometer-core/src/main/java/io/micrometer/core/instrument/binder/jvm/JvmVirtualThreadEventMetrics.java +++ b/micrometer-java21/src/main/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetrics.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package io.micrometer.core.instrument.binder.jvm; +package io.micrometer.java21.instrument.binder.jfr; import io.micrometer.core.instrument.Counter; import io.micrometer.core.instrument.MeterRegistry; @@ -25,35 +25,46 @@ import java.io.Closeable; import java.io.IOException; import java.time.Duration; +import java.util.Objects; import static java.util.Collections.emptyList; -public class JvmVirtualThreadEventMetrics implements MeterBinder, Closeable { +public class JfrVirtualThreadEventMetrics implements MeterBinder, Closeable { - private static final String PINNED_EVENT = "jdk.VirtualThreadPinned"; + public static final String PINNED_EVENT = "jdk.VirtualThreadPinned"; - private static final String SUBMIT_FAILED_EVENT = "jdk.VirtualThreadSubmitFailed"; + public static final String SUBMIT_FAILED_EVENT = "jdk.VirtualThreadSubmitFailed"; + + private final RecordingSettings settings; private final Iterable tags; - private final RecordingStream recordingStream; + private boolean started = false; + + private RecordingStream recordingStream; - public JvmVirtualThreadEventMetrics() { - this(emptyList()); + public JfrVirtualThreadEventMetrics() { + this(new RecordingSettings(), emptyList()); } - public JvmVirtualThreadEventMetrics(Iterable tags) { - this.tags = tags; - this.recordingStream = new RecordingStream(); + public JfrVirtualThreadEventMetrics(Iterable tags) { + this(new RecordingSettings(), tags); + } - recordingStream.enable(PINNED_EVENT); - recordingStream.enable(SUBMIT_FAILED_EVENT); - recordingStream.setMaxAge(Duration.ofSeconds(5)); - recordingStream.startAsync(); + public JfrVirtualThreadEventMetrics(RecordingSettings settings, Iterable tags) { + this.settings = settings; + this.tags = tags; } @Override public void bindTo(MeterRegistry registry) { + if (started) { + return; + } + + started = true; + recordingStream = createRecordingStream(settings); + final Timer pinnedTimer = Timer.builder("jvm.virtual.thread.pinned") .tags(tags) @@ -70,8 +81,30 @@ public void bindTo(MeterRegistry registry) { recordingStream.onEvent(SUBMIT_FAILED_EVENT, event -> submitFailedCounter.increment()); } + protected RecordingStream createRecordingStream(RecordingSettings settings) { + final RecordingStream recordingStream = new RecordingStream(); + recordingStream.enable(PINNED_EVENT).withThreshold(settings.pinnedThreshold); + recordingStream.enable(SUBMIT_FAILED_EVENT); + recordingStream.setMaxAge(settings.maxAge); + recordingStream.setMaxSize(settings.maxSize); + recordingStream.startAsync(); + return recordingStream; + } + @Override public void close() throws IOException { - recordingStream.close(); + if (started) { + recordingStream.close(); + } + } + + public record RecordingSettings(Duration maxAge, long maxSize, Duration pinnedThreshold) { + public RecordingSettings { + Objects.requireNonNull(maxAge, "maxAge parameter must not be null"); + Objects.requireNonNull(pinnedThreshold, "pinnedThreshold must not be null"); + } + public RecordingSettings() { + this(Duration.ofSeconds(5), 10L * 1024 * 1024, Duration.ofMillis(1)); + } } } diff --git a/micrometer-java21/src/test/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetricsTests.java b/micrometer-java21/src/test/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetricsTests.java new file mode 100644 index 0000000000..20c10f2040 --- /dev/null +++ b/micrometer-java21/src/test/java/io/micrometer/java21/instrument/binder/jfr/JfrVirtualThreadEventMetricsTests.java @@ -0,0 +1,58 @@ +package io.micrometer.java21.instrument.binder.jfr; + +import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.Tags; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.time.Duration; + +import static org.awaitility.Awaitility.await; + +class JfrVirtualThreadEventMetricsTests { + + private static final Tags USER_TAGS = Tags.of("k", "v"); + + private MeterRegistry registry; + + private JfrVirtualThreadEventMetrics jfrMetrics; + + @BeforeEach + void setup() { + registry = new SimpleMeterRegistry(); + jfrMetrics = new JfrVirtualThreadEventMetrics(USER_TAGS); + jfrMetrics.bindTo(registry); + } + + @Test + void registerPinnedEvent() throws Exception { + Thread.ofVirtual() + .name("vt-test") + .start(() -> { + synchronized (this) { + sleep(Duration.ofMillis(100)); + } + }) + .join(); + + await().atMost(Duration.ofSeconds(2)) + .until(() -> registry.get("jvm.virtual.thread.pinned").timer().count() == 1); + } + + private void sleep(Duration duration) { + try { + Thread.sleep(duration); + } + catch (InterruptedException ignored) { + } + } + + @AfterEach + void cleanup() throws IOException { + jfrMetrics.close(); + } + +} diff --git a/settings.gradle b/settings.gradle index d6d41a33d1..7683ccaf54 100644 --- a/settings.gradle +++ b/settings.gradle @@ -47,6 +47,7 @@ include 'concurrency-tests' include 'micrometer-bom' include 'micrometer-jakarta9' include 'micrometer-java11' +include 'micrometer-java21' include 'micrometer-jetty11' include 'micrometer-jetty12' include 'micrometer-osgi-test'