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