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