001package io.prometheus.metrics.instrumentation.jvm;
002
003import io.prometheus.metrics.config.PrometheusProperties;
004import io.prometheus.metrics.core.metrics.CounterWithCallback;
005import io.prometheus.metrics.core.metrics.GaugeWithCallback;
006import io.prometheus.metrics.model.registry.PrometheusRegistry;
007import java.lang.management.ClassLoadingMXBean;
008import java.lang.management.ManagementFactory;
009import javax.annotation.Nullable;
010
011/**
012 * JVM Class Loading metrics. The {@link JvmClassLoadingMetrics} are registered as part of the
013 * {@link JvmMetrics} like this:
014 *
015 * <pre>{@code
016 * JvmMetrics.builder().register();
017 * }</pre>
018 *
019 * However, if you want only the {@link JvmClassLoadingMetrics} you can also register them directly:
020 *
021 * <pre>{@code
022 * JvmClassLoadingMetrics.builder().register();
023 * }</pre>
024 *
025 * Example metrics being exported:
026 *
027 * <pre>
028 * # HELP jvm_classes_currently_loaded The number of classes that are currently loaded in the JVM
029 * # TYPE jvm_classes_currently_loaded gauge
030 * jvm_classes_currently_loaded 1109.0
031 * # HELP jvm_classes_loaded_total The total number of classes that have been loaded since the JVM has started execution
032 * # TYPE jvm_classes_loaded_total counter
033 * jvm_classes_loaded_total 1109.0
034 * # HELP jvm_classes_unloaded_total The total number of classes that have been unloaded since the JVM has started execution
035 * # TYPE jvm_classes_unloaded_total counter
036 * jvm_classes_unloaded_total 0.0
037 * </pre>
038 */
039public class JvmClassLoadingMetrics {
040
041  private static final String JVM_CLASSES_CURRENTLY_LOADED = "jvm_classes_currently_loaded";
042  private static final String JVM_CLASSES_LOADED_TOTAL = "jvm_classes_loaded_total";
043  private static final String JVM_CLASSES_UNLOADED_TOTAL = "jvm_classes_unloaded_total";
044
045  private final PrometheusProperties config;
046  private final ClassLoadingMXBean classLoadingBean;
047
048  private JvmClassLoadingMetrics(ClassLoadingMXBean classLoadingBean, PrometheusProperties config) {
049    this.classLoadingBean = classLoadingBean;
050    this.config = config;
051  }
052
053  private void register(PrometheusRegistry registry) {
054
055    GaugeWithCallback.builder(config)
056        .name(JVM_CLASSES_CURRENTLY_LOADED)
057        .help("The number of classes that are currently loaded in the JVM")
058        .callback(callback -> callback.call(classLoadingBean.getLoadedClassCount()))
059        .register(registry);
060
061    CounterWithCallback.builder(config)
062        .name(JVM_CLASSES_LOADED_TOTAL)
063        .help(
064            "The total number of classes that have been loaded since the JVM has started execution")
065        .callback(callback -> callback.call(classLoadingBean.getTotalLoadedClassCount()))
066        .register(registry);
067
068    CounterWithCallback.builder(config)
069        .name(JVM_CLASSES_UNLOADED_TOTAL)
070        .help(
071            "The total number of classes that have been unloaded since the JVM has "
072                + "started execution")
073        .callback(callback -> callback.call(classLoadingBean.getUnloadedClassCount()))
074        .register(registry);
075  }
076
077  public static Builder builder() {
078    return new Builder(PrometheusProperties.get());
079  }
080
081  public static Builder builder(PrometheusProperties config) {
082    return new Builder(config);
083  }
084
085  public static class Builder {
086
087    private final PrometheusProperties config;
088    @Nullable private ClassLoadingMXBean classLoadingBean;
089
090    private Builder(PrometheusProperties config) {
091      this.config = config;
092    }
093
094    /** Package private. For testing only. */
095    Builder classLoadingBean(ClassLoadingMXBean classLoadingBean) {
096      this.classLoadingBean = classLoadingBean;
097      return this;
098    }
099
100    public void register() {
101      register(PrometheusRegistry.defaultRegistry);
102    }
103
104    public void register(PrometheusRegistry registry) {
105      ClassLoadingMXBean classLoadingBean =
106          this.classLoadingBean != null
107              ? this.classLoadingBean
108              : ManagementFactory.getClassLoadingMXBean();
109      new JvmClassLoadingMetrics(classLoadingBean, config).register(registry);
110    }
111  }
112}