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.SummaryWithCallback;
006import io.prometheus.metrics.model.registry.PrometheusRegistry;
007import io.prometheus.metrics.model.snapshots.Labels;
008import io.prometheus.metrics.model.snapshots.Quantiles;
009import io.prometheus.metrics.model.snapshots.Unit;
010import java.lang.management.GarbageCollectorMXBean;
011import java.lang.management.ManagementFactory;
012import java.util.List;
013import javax.annotation.Nullable;
014
015/**
016 * JVM Garbage Collector metrics. The {@link JvmGarbageCollectorMetrics} are registered as part of
017 * the {@link JvmMetrics} like this:
018 *
019 * <pre>{@code
020 * JvmMetrics.builder().register();
021 * }</pre>
022 *
023 * However, if you want only the {@link JvmGarbageCollectorMetrics} you can also register them
024 * directly:
025 *
026 * <pre>{@code
027 * JvmGarbageCollectorMetrics.builder().register();
028 * }</pre>
029 *
030 * Example metrics being exported:
031 *
032 * <pre>
033 * # HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds.
034 * # TYPE jvm_gc_collection_seconds summary
035 * jvm_gc_collection_seconds_count{gc="PS MarkSweep"} 0
036 * jvm_gc_collection_seconds_sum{gc="PS MarkSweep"} 0.0
037 * jvm_gc_collection_seconds_count{gc="PS Scavenge"} 0
038 * jvm_gc_collection_seconds_sum{gc="PS Scavenge"} 0.0
039 * </pre>
040 */
041@StableApi
042public class JvmGarbageCollectorMetrics {
043
044  private static final String JVM_GC_COLLECTION_SECONDS = "jvm_gc_collection_seconds";
045
046  private final PrometheusProperties config;
047  private final List<GarbageCollectorMXBean> garbageCollectorBeans;
048  private final Labels constLabels;
049
050  private JvmGarbageCollectorMetrics(
051      List<GarbageCollectorMXBean> garbageCollectorBeans,
052      PrometheusProperties config,
053      Labels constLabels) {
054    this.config = config;
055    this.garbageCollectorBeans = garbageCollectorBeans;
056    this.constLabels = constLabels;
057  }
058
059  private void register(PrometheusRegistry registry) {
060
061    SummaryWithCallback.builder(config)
062        .name(JVM_GC_COLLECTION_SECONDS)
063        .help("Time spent in a given JVM garbage collector in seconds.")
064        .unit(Unit.SECONDS)
065        .labelNames("gc")
066        .callback(
067            callback -> {
068              for (GarbageCollectorMXBean gc : garbageCollectorBeans) {
069                callback.call(
070                    gc.getCollectionCount(),
071                    Unit.millisToSeconds(gc.getCollectionTime()),
072                    Quantiles.EMPTY,
073                    gc.getName());
074              }
075            })
076        .constLabels(constLabels)
077        .register(registry);
078  }
079
080  public static Builder builder() {
081    return new Builder(PrometheusProperties.get());
082  }
083
084  public static Builder builder(PrometheusProperties config) {
085    return new Builder(config);
086  }
087
088  public static class Builder {
089
090    private final PrometheusProperties config;
091    @Nullable private List<GarbageCollectorMXBean> garbageCollectorBeans;
092    private Labels constLabels = Labels.EMPTY;
093
094    private Builder(PrometheusProperties config) {
095      this.config = config;
096    }
097
098    public Builder constLabels(Labels constLabels) {
099      this.constLabels = constLabels;
100      return this;
101    }
102
103    /** Package private. For testing only. */
104    Builder garbageCollectorBeans(List<GarbageCollectorMXBean> garbageCollectorBeans) {
105      this.garbageCollectorBeans = garbageCollectorBeans;
106      return this;
107    }
108
109    public void register() {
110      register(PrometheusRegistry.defaultRegistry);
111    }
112
113    public void register(PrometheusRegistry registry) {
114      List<GarbageCollectorMXBean> garbageCollectorBeans = this.garbageCollectorBeans;
115      if (garbageCollectorBeans == null) {
116        garbageCollectorBeans = ManagementFactory.getGarbageCollectorMXBeans();
117      }
118      new JvmGarbageCollectorMetrics(garbageCollectorBeans, config, constLabels).register(registry);
119    }
120  }
121}