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