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