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