001package io.prometheus.metrics.instrumentation.jvm; 002 003import io.prometheus.metrics.config.PrometheusProperties; 004import io.prometheus.metrics.core.metrics.GaugeWithCallback; 005import io.prometheus.metrics.model.registry.PrometheusRegistry; 006import io.prometheus.metrics.model.snapshots.Labels; 007import io.prometheus.metrics.model.snapshots.Unit; 008import java.lang.management.BufferPoolMXBean; 009import java.lang.management.ManagementFactory; 010import java.util.List; 011import javax.annotation.Nullable; 012 013/** 014 * JVM Buffer Pool metrics. The {@link JvmBufferPoolMetrics} are registered as part of the {@link 015 * JvmMetrics} like this: 016 * 017 * <pre>{@code 018 * JvmMetrics.builder().register(); 019 * }</pre> 020 * 021 * However, if you want only the {@link JvmBufferPoolMetrics} you can also register them directly: 022 * 023 * <pre>{@code 024 * JvmBufferPoolMetrics.builder().register(); 025 * }</pre> 026 * 027 * Example metrics being exported: 028 * 029 * <pre> 030 * # HELP jvm_buffer_pool_capacity_bytes Bytes capacity of a given JVM buffer pool. 031 * # TYPE jvm_buffer_pool_capacity_bytes gauge 032 * jvm_buffer_pool_capacity_bytes{pool="direct"} 8192.0 033 * jvm_buffer_pool_capacity_bytes{pool="mapped"} 0.0 034 * # HELP jvm_buffer_pool_used_buffers Used buffers of a given JVM buffer pool. 035 * # TYPE jvm_buffer_pool_used_buffers gauge 036 * jvm_buffer_pool_used_buffers{pool="direct"} 1.0 037 * jvm_buffer_pool_used_buffers{pool="mapped"} 0.0 038 * # HELP jvm_buffer_pool_used_bytes Used bytes of a given JVM buffer pool. 039 * # TYPE jvm_buffer_pool_used_bytes gauge 040 * jvm_buffer_pool_used_bytes{pool="direct"} 8192.0 041 * jvm_buffer_pool_used_bytes{pool="mapped"} 0.0 042 * </pre> 043 */ 044public class JvmBufferPoolMetrics { 045 046 private static final String JVM_BUFFER_POOL_USED_BYTES = "jvm_buffer_pool_used_bytes"; 047 private static final String JVM_BUFFER_POOL_CAPACITY_BYTES = "jvm_buffer_pool_capacity_bytes"; 048 private static final String JVM_BUFFER_POOL_USED_BUFFERS = "jvm_buffer_pool_used_buffers"; 049 050 private final PrometheusProperties config; 051 private final List<BufferPoolMXBean> bufferPoolBeans; 052 private final Labels constLabels; 053 054 private JvmBufferPoolMetrics( 055 List<BufferPoolMXBean> bufferPoolBeans, PrometheusProperties config, Labels constLabels) { 056 this.config = config; 057 this.bufferPoolBeans = bufferPoolBeans; 058 this.constLabels = constLabels; 059 } 060 061 private void register(PrometheusRegistry registry) { 062 063 GaugeWithCallback.builder(config) 064 .name(JVM_BUFFER_POOL_USED_BYTES) 065 .help("Used bytes of a given JVM buffer pool.") 066 .unit(Unit.BYTES) 067 .labelNames("pool") 068 .callback( 069 callback -> { 070 for (BufferPoolMXBean pool : bufferPoolBeans) { 071 callback.call(pool.getMemoryUsed(), pool.getName()); 072 } 073 }) 074 .constLabels(constLabels) 075 .register(registry); 076 077 GaugeWithCallback.builder(config) 078 .name(JVM_BUFFER_POOL_CAPACITY_BYTES) 079 .help("Bytes capacity of a given JVM buffer pool.") 080 .unit(Unit.BYTES) 081 .labelNames("pool") 082 .callback( 083 callback -> { 084 for (BufferPoolMXBean pool : bufferPoolBeans) { 085 callback.call(pool.getTotalCapacity(), pool.getName()); 086 } 087 }) 088 .constLabels(constLabels) 089 .register(registry); 090 091 GaugeWithCallback.builder(config) 092 .name(JVM_BUFFER_POOL_USED_BUFFERS) 093 .help("Used buffers of a given JVM buffer pool.") 094 .labelNames("pool") 095 .callback( 096 callback -> { 097 for (BufferPoolMXBean pool : bufferPoolBeans) { 098 callback.call(pool.getCount(), pool.getName()); 099 } 100 }) 101 .constLabels(constLabels) 102 .register(registry); 103 } 104 105 public static Builder builder() { 106 return new Builder(PrometheusProperties.get()); 107 } 108 109 public static Builder builder(PrometheusProperties config) { 110 return new Builder(config); 111 } 112 113 public static class Builder { 114 115 private final PrometheusProperties config; 116 @Nullable private List<BufferPoolMXBean> bufferPoolBeans; 117 private Labels constLabels = Labels.EMPTY; 118 119 private Builder(PrometheusProperties config) { 120 this.config = config; 121 } 122 123 public Builder constLabels(Labels constLabels) { 124 this.constLabels = constLabels; 125 return this; 126 } 127 128 /** Package private. For testing only. */ 129 Builder bufferPoolBeans(List<BufferPoolMXBean> bufferPoolBeans) { 130 this.bufferPoolBeans = bufferPoolBeans; 131 return this; 132 } 133 134 public void register() { 135 register(PrometheusRegistry.defaultRegistry); 136 } 137 138 public void register(PrometheusRegistry registry) { 139 List<BufferPoolMXBean> bufferPoolBeans = this.bufferPoolBeans; 140 if (bufferPoolBeans == null) { 141 bufferPoolBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); 142 } 143 new JvmBufferPoolMetrics(bufferPoolBeans, config, constLabels).register(registry); 144 } 145 } 146}