diff --git a/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/BufferPoolsExports.java b/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/BufferPoolsExports.java
new file mode 100644
index 000000000..6ff7d522b
--- /dev/null
+++ b/simpleclient_hotspot/src/main/java/io/prometheus/client/hotspot/BufferPoolsExports.java
@@ -0,0 +1,71 @@
+package io.prometheus.client.hotspot;
+
+import io.prometheus.client.Collector;
+import io.prometheus.client.CounterMetricFamily;
+import io.prometheus.client.GaugeMetricFamily;
+
+import java.lang.management.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Exports metrics about JVM buffer pools.
+ *
+ * Example usage:
+ *
+ * {@code
+ * new BufferPoolsExports().register();
+ * }
+ *
+ * Example metrics being exported:
+ *
+ * jvm_buffer_pool_bytes_used{name="direct"} 2000000
+ * jvm_buffer_pool_bytes_capacity{name="direct"} 200000
+ * jvm_buffer_pool_count{name="nonheap"} 20
+ *
+ */
+public class BufferPoolsExports extends Collector {
+ private final List poolBeans;
+
+ public BufferPoolsExports() {
+ this(ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class));
+ }
+
+ public BufferPoolsExports(List poolBeans) {
+ this.poolBeans = poolBeans;
+ }
+
+ void addBufferPoolMetrics(List sampleFamilies) {
+ GaugeMetricFamily used = new GaugeMetricFamily(
+ "jvm_buffer_pool_bytes_used",
+ "Estimate of the memory (bytes) that the Java virtual machine is using for this buffer pool.",
+ Collections.singletonList("name"));
+
+ GaugeMetricFamily capacity = new GaugeMetricFamily(
+ "jvm_buffer_pool_bytes_capacity",
+ "Estimate of the total capacity (bytes) of the buffers in this pool.",
+ Collections.singletonList("name"));
+
+ CounterMetricFamily count = new CounterMetricFamily(
+ "jvm_buffer_pool_count",
+ "Estimate of the number of buffers in the pool",
+ Collections.singletonList("name"));
+
+ for (BufferPoolMXBean poolBean : this.poolBeans) {
+ used.addMetric(Collections.singletonList(poolBean.getName()), poolBean.getMemoryUsed());
+ capacity.addMetric(Collections.singletonList(poolBean.getName()), poolBean.getTotalCapacity());
+ count.addMetric(Collections.singletonList(poolBean.getName()), poolBean.getCount());
+ }
+
+ sampleFamilies.add(used);
+ sampleFamilies.add(capacity);
+ sampleFamilies.add(count);
+ }
+
+ public List collect() {
+ List mfs = new ArrayList();
+ addBufferPoolMetrics(mfs);
+ return mfs;
+ }
+}
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 371110e13..bab982b08 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
@@ -26,6 +26,7 @@ public static synchronized void initialize() {
new ThreadExports().register();
new ClassLoadingExports().register();
new VersionInfoExports().register();
+ new BufferPoolsExports().register();
initialized = true;
}
}
diff --git a/simpleclient_hotspot/src/test/java/io/prometheus/client/hotspot/BufferPoolsExportsTest.java b/simpleclient_hotspot/src/test/java/io/prometheus/client/hotspot/BufferPoolsExportsTest.java
new file mode 100644
index 000000000..48893a1fb
--- /dev/null
+++ b/simpleclient_hotspot/src/test/java/io/prometheus/client/hotspot/BufferPoolsExportsTest.java
@@ -0,0 +1,81 @@
+package io.prometheus.client.hotspot;
+
+import io.prometheus.client.CollectorRegistry;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.lang.management.BufferPoolMXBean;
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class BufferPoolsExportsTest {
+
+ private BufferPoolMXBean mockPoolsBean1 = Mockito.mock(BufferPoolMXBean.class);
+ private BufferPoolMXBean mockPoolsBean2 = Mockito.mock(BufferPoolMXBean.class);
+ private List mockList = Arrays.asList(mockPoolsBean1, mockPoolsBean2);
+ private CollectorRegistry registry = new CollectorRegistry();
+ private BufferPoolsExports collectorUnderTest;
+
+ @Before
+ public void setUp() {
+ when(mockPoolsBean1.getName()).thenReturn("direct");
+ when(mockPoolsBean1.getTotalCapacity()).thenReturn(200000L);
+ when(mockPoolsBean1.getMemoryUsed()).thenReturn(100000L);
+ when(mockPoolsBean1.getCount()).thenReturn(3L);
+ when(mockPoolsBean2.getName()).thenReturn("mapped");
+ when(mockPoolsBean2.getTotalCapacity()).thenReturn(0L);
+ when(mockPoolsBean2.getMemoryUsed()).thenReturn(0L);
+ when(mockPoolsBean2.getCount()).thenReturn(0L);
+ collectorUnderTest = new BufferPoolsExports(mockList).register(registry);
+ }
+
+ @Test
+ public void testMemoryPools() {
+ assertEquals(
+ 100000L,
+ registry.getSampleValue(
+ "jvm_buffer_pool_bytes_used",
+ new String[]{"name"},
+ new String[]{"direct"}),
+ .0000001);
+ assertEquals(
+ 200000L,
+ registry.getSampleValue(
+ "jvm_buffer_pool_bytes_capacity",
+ new String[]{"name"},
+ new String[]{"direct"}),
+ .0000001);
+ assertEquals(
+ 3L,
+ registry.getSampleValue(
+ "jvm_buffer_pool_count",
+ new String[]{"name"},
+ new String[]{"direct"}),
+ .0000001);
+ assertEquals(
+ 0L,
+ registry.getSampleValue(
+ "jvm_buffer_pool_bytes_used",
+ new String[]{"name"},
+ new String[]{"mapped"}),
+ .0000001);
+ assertEquals(
+ 0L,
+ registry.getSampleValue(
+ "jvm_buffer_pool_bytes_capacity",
+ new String[]{"name"},
+ new String[]{"mapped"}),
+ .0000001);
+ assertEquals(
+ 0L,
+ registry.getSampleValue(
+ "jvm_buffer_pool_count",
+ new String[]{"name"},
+ new String[]{"mapped"}),
+ .0000001);
+ }
+}