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