diff --git a/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/DefaultExports.java b/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/DefaultExports.java
index 79cd6ed5e..ee041cbd1 100644
--- a/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/DefaultExports.java
+++ b/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/DefaultExports.java
@@ -42,6 +42,7 @@ public static void register(CollectorRegistry registry) {
new ThreadExports().register(registry);
new ClassLoadingExports().register(registry);
new VersionInfoExports().register(registry);
+ new SafepointExports().register(registry);
}
}
diff --git a/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/SafepointExports.java b/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/SafepointExports.java
new file mode 100644
index 000000000..6f1387cef
--- /dev/null
+++ b/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/SafepointExports.java
@@ -0,0 +1,63 @@
+package io.prometheus.client.hotspot;
+
+import io.prometheus.client.Collector;
+import io.prometheus.client.CounterMetricFamily;
+import io.prometheus.client.SummaryMetricFamily;
+import sun.management.HotspotRuntimeMBean;
+import sun.management.ManagementFactoryHelper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Exports metrics about JVM Safepoints.
+ *
+ * Example usage:
+ *
+ * {@code
+ * new SafepointExports().register();
+ * }
+ *
+ * Example metrics being exported:
+ *
+ * jvm_safepoint_seconds_count{} 200
+ * jvm_safepoint_seconds_sum{} 6.7
+ * jvm_safepoint_sync_time_seconds{} 6.7
+ *
+ */
+public class SafepointExports extends Collector {
+ private final HotspotRuntimeMBean hotspotRuntimeMBean;
+
+ public SafepointExports() {
+ this(ManagementFactoryHelper.getHotspotRuntimeMBean());
+ }
+
+ SafepointExports(HotspotRuntimeMBean hotspotRuntimeMBean) {
+ this.hotspotRuntimeMBean = hotspotRuntimeMBean;
+ }
+
+ public List collect() {
+ SummaryMetricFamily safepoint = new SummaryMetricFamily(
+ "jvm_safepoint_seconds",
+ "The accumulated time spent at safepoints in seconds. This is the accumulated elapsed time that the application has been stopped for safepoint operations. (count: The number of safepoints taken place since the JVM started.",
+ Collections.EMPTY_LIST);
+
+ safepoint.addMetric(
+ Collections.EMPTY_LIST,
+ hotspotRuntimeMBean.getSafepointCount(),
+ hotspotRuntimeMBean.getTotalSafepointTime() / MILLISECONDS_PER_SECOND);
+
+ CounterMetricFamily safepointSyncTime = new CounterMetricFamily(
+ "jvm_safepoint_sync_time_seconds",
+ "The accumulated time spent getting to safepoints in seconds.",
+ hotspotRuntimeMBean.getSafepointSyncTime() / MILLISECONDS_PER_SECOND);
+
+ List mfs = new ArrayList();
+ mfs.add(safepoint);
+ mfs.add(safepointSyncTime);
+
+ return mfs;
+ }
+}
diff --git a/simpleclient_hotspot/src/test/java/io/prometheus/client/hotspot/SafepointExportsTest.java b/simpleclient_hotspot/src/test/java/io/prometheus/client/hotspot/SafepointExportsTest.java
new file mode 100644
index 000000000..469683c13
--- /dev/null
+++ b/simpleclient_hotspot/src/test/java/io/prometheus/client/hotspot/SafepointExportsTest.java
@@ -0,0 +1,47 @@
+package io.prometheus.client.hotspot;
+
+import io.prometheus.client.CollectorRegistry;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import sun.management.HotspotRuntimeMBean;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class SafepointExportsTest {
+
+ private HotspotRuntimeMBean mockHotspotRuntimeBean = Mockito.mock(HotspotRuntimeMBean.class);
+ private CollectorRegistry registry = new CollectorRegistry();
+ private SafepointExports collectorUnderTest;
+
+ private static final String[] EMPTY_LABEL = new String[0];
+
+
+ @Before
+ public void setUp() {
+ when(mockHotspotRuntimeBean.getSafepointCount()).thenReturn(300L);
+ when(mockHotspotRuntimeBean.getTotalSafepointTime()).thenReturn(13L);
+ when(mockHotspotRuntimeBean.getSafepointSyncTime()).thenReturn(31L);
+ collectorUnderTest = new SafepointExports(mockHotspotRuntimeBean).register(registry);
+ }
+
+ @Test
+ public void testSafepoints() {
+ assertEquals(
+ 300L,
+ registry.getSampleValue(
+ "jvm_safepoint_seconds_count", EMPTY_LABEL, EMPTY_LABEL),
+ .0000001);
+ assertEquals(
+ 0.013,
+ registry.getSampleValue(
+ "jvm_safepoint_seconds_sum", EMPTY_LABEL, EMPTY_LABEL),
+ .0000001);
+ assertEquals(
+ 0.031,
+ registry.getSampleValue(
+ "jvm_safepoint_sync_time_seconds", EMPTY_LABEL, EMPTY_LABEL),
+ .0000001);
+ }
+}