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