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