001package io.prometheus.client.hotspot; 002 003import io.prometheus.client.Collector; 004import io.prometheus.client.GaugeMetricFamily; 005 006import java.lang.management.ManagementFactory; 007import java.lang.management.MemoryMXBean; 008import java.lang.management.MemoryPoolMXBean; 009import java.lang.management.MemoryUsage; 010import java.util.ArrayList; 011import java.util.Collections; 012import java.util.List; 013 014/** 015 * Exports metrics about JVM memory areas. 016 * <p> 017 * Example usage: 018 * <pre> 019 * {@code 020 * new MemoryPoolsExports().register(); 021 * } 022 * </pre> 023 * Example metrics being exported: 024 * <pre> 025 * jvm_memory_bytes_used{area="heap"} 2000000 026 * jvm_memory_bytes_committed{area="nonheap"} 200000 027 * jvm_memory_bytes_max{area="nonheap"} 2000000 028 * jvm_memory_pool_bytes_used{pool="PS Eden Space"} 2000 029 * </pre> 030 */ 031public class MemoryPoolsExports extends Collector { 032 private final MemoryMXBean memoryBean; 033 private final List<MemoryPoolMXBean> poolBeans; 034 035 public MemoryPoolsExports() { 036 this( 037 ManagementFactory.getMemoryMXBean(), 038 ManagementFactory.getMemoryPoolMXBeans()); 039 } 040 041 public MemoryPoolsExports(MemoryMXBean memoryBean, 042 List<MemoryPoolMXBean> poolBeans) { 043 this.memoryBean = memoryBean; 044 this.poolBeans = poolBeans; 045 } 046 047 void addMemoryAreaMetrics(List<MetricFamilySamples> sampleFamilies) { 048 MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); 049 MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage(); 050 051 GaugeMetricFamily finalizer = new GaugeMetricFamily( 052 "jvm_memory_objects_pending_finalization", 053 "The number of objects waiting in the finalizer queue.", 054 memoryBean.getObjectPendingFinalizationCount()); 055 sampleFamilies.add(finalizer); 056 057 GaugeMetricFamily used = new GaugeMetricFamily( 058 "jvm_memory_bytes_used", 059 "Used bytes of a given JVM memory area.", 060 Collections.singletonList("area")); 061 used.addMetric(Collections.singletonList("heap"), heapUsage.getUsed()); 062 used.addMetric(Collections.singletonList("nonheap"), nonHeapUsage.getUsed()); 063 sampleFamilies.add(used); 064 065 GaugeMetricFamily committed = new GaugeMetricFamily( 066 "jvm_memory_bytes_committed", 067 "Committed (bytes) of a given JVM memory area.", 068 Collections.singletonList("area")); 069 committed.addMetric(Collections.singletonList("heap"), heapUsage.getCommitted()); 070 committed.addMetric(Collections.singletonList("nonheap"), nonHeapUsage.getCommitted()); 071 sampleFamilies.add(committed); 072 073 GaugeMetricFamily max = new GaugeMetricFamily( 074 "jvm_memory_bytes_max", 075 "Max (bytes) of a given JVM memory area.", 076 Collections.singletonList("area")); 077 max.addMetric(Collections.singletonList("heap"), heapUsage.getMax()); 078 max.addMetric(Collections.singletonList("nonheap"), nonHeapUsage.getMax()); 079 sampleFamilies.add(max); 080 081 GaugeMetricFamily init = new GaugeMetricFamily( 082 "jvm_memory_bytes_init", 083 "Initial bytes of a given JVM memory area.", 084 Collections.singletonList("area")); 085 init.addMetric(Collections.singletonList("heap"), heapUsage.getInit()); 086 init.addMetric(Collections.singletonList("nonheap"), nonHeapUsage.getInit()); 087 sampleFamilies.add(init); 088 } 089 090 void addMemoryPoolMetrics(List<MetricFamilySamples> sampleFamilies) { 091 092 // Note: The Prometheus naming convention is that units belong at the end of the metric name. 093 // For new metrics like jvm_memory_pool_collection_used_bytes we follow that convention. 094 // For old metrics like jvm_memory_pool_bytes_used we keep the names as they are to avoid a breaking change. 095 096 GaugeMetricFamily used = new GaugeMetricFamily( 097 "jvm_memory_pool_bytes_used", 098 "Used bytes of a given JVM memory pool.", 099 Collections.singletonList("pool")); 100 sampleFamilies.add(used); 101 GaugeMetricFamily committed = new GaugeMetricFamily( 102 "jvm_memory_pool_bytes_committed", 103 "Committed bytes of a given JVM memory pool.", 104 Collections.singletonList("pool")); 105 sampleFamilies.add(committed); 106 GaugeMetricFamily max = new GaugeMetricFamily( 107 "jvm_memory_pool_bytes_max", 108 "Max bytes of a given JVM memory pool.", 109 Collections.singletonList("pool")); 110 sampleFamilies.add(max); 111 GaugeMetricFamily init = new GaugeMetricFamily( 112 "jvm_memory_pool_bytes_init", 113 "Initial bytes of a given JVM memory pool.", 114 Collections.singletonList("pool")); 115 sampleFamilies.add(init); 116 GaugeMetricFamily collectionUsed = new GaugeMetricFamily( 117 "jvm_memory_pool_collection_used_bytes", 118 "Used bytes after last collection of a given JVM memory pool.", 119 Collections.singletonList("pool")); 120 sampleFamilies.add(collectionUsed); 121 GaugeMetricFamily collectionCommitted = new GaugeMetricFamily( 122 "jvm_memory_pool_collection_committed_bytes", 123 "Committed after last collection bytes of a given JVM memory pool.", 124 Collections.singletonList("pool")); 125 sampleFamilies.add(collectionCommitted); 126 GaugeMetricFamily collectionMax = new GaugeMetricFamily( 127 "jvm_memory_pool_collection_max_bytes", 128 "Max bytes after last collection of a given JVM memory pool.", 129 Collections.singletonList("pool")); 130 sampleFamilies.add(collectionMax); 131 GaugeMetricFamily collectionInit = new GaugeMetricFamily( 132 "jvm_memory_pool_collection_init_bytes", 133 "Initial after last collection bytes of a given JVM memory pool.", 134 Collections.singletonList("pool")); 135 sampleFamilies.add(collectionInit); 136 for (final MemoryPoolMXBean pool : poolBeans) { 137 MemoryUsage poolUsage = pool.getUsage(); 138 used.addMetric( 139 Collections.singletonList(pool.getName()), 140 poolUsage.getUsed()); 141 committed.addMetric( 142 Collections.singletonList(pool.getName()), 143 poolUsage.getCommitted()); 144 max.addMetric( 145 Collections.singletonList(pool.getName()), 146 poolUsage.getMax()); 147 init.addMetric( 148 Collections.singletonList(pool.getName()), 149 poolUsage.getInit()); 150 MemoryUsage collectionPoolUsage = pool.getCollectionUsage(); 151 if (collectionPoolUsage != null) { 152 collectionUsed.addMetric( 153 Collections.singletonList(pool.getName()), 154 collectionPoolUsage.getUsed()); 155 collectionCommitted.addMetric( 156 Collections.singletonList(pool.getName()), 157 collectionPoolUsage.getCommitted()); 158 collectionMax.addMetric( 159 Collections.singletonList(pool.getName()), 160 collectionPoolUsage.getMax()); 161 collectionInit.addMetric( 162 Collections.singletonList(pool.getName()), 163 collectionPoolUsage.getInit()); 164 } 165 } 166 } 167 168 public List<MetricFamilySamples> collect() { 169 List<MetricFamilySamples> mfs = new ArrayList<MetricFamilySamples>(); 170 addMemoryAreaMetrics(mfs); 171 addMemoryPoolMetrics(mfs); 172 return mfs; 173 } 174}