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}