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