001package io.prometheus.metrics.instrumentation.jvm; 002 003import io.prometheus.metrics.config.PrometheusProperties; 004import io.prometheus.metrics.core.metrics.SummaryWithCallback; 005import io.prometheus.metrics.model.registry.PrometheusRegistry; 006import io.prometheus.metrics.model.snapshots.Labels; 007import io.prometheus.metrics.model.snapshots.Quantiles; 008import io.prometheus.metrics.model.snapshots.Unit; 009import java.lang.management.GarbageCollectorMXBean; 010import java.lang.management.ManagementFactory; 011import java.util.List; 012import javax.annotation.Nullable; 013 014/** 015 * JVM Garbage Collector metrics. The {@link JvmGarbageCollectorMetrics} are registered as part of 016 * the {@link JvmMetrics} like this: 017 * 018 * <pre>{@code 019 * JvmMetrics.builder().register(); 020 * }</pre> 021 * 022 * However, if you want only the {@link JvmGarbageCollectorMetrics} you can also register them 023 * directly: 024 * 025 * <pre>{@code 026 * JvmGarbageCollectorMetrics.builder().register(); 027 * }</pre> 028 * 029 * Example metrics being exported: 030 * 031 * <pre> 032 * # HELP jvm_gc_collection_seconds Time spent in a given JVM garbage collector in seconds. 033 * # TYPE jvm_gc_collection_seconds summary 034 * jvm_gc_collection_seconds_count{gc="PS MarkSweep"} 0 035 * jvm_gc_collection_seconds_sum{gc="PS MarkSweep"} 0.0 036 * jvm_gc_collection_seconds_count{gc="PS Scavenge"} 0 037 * jvm_gc_collection_seconds_sum{gc="PS Scavenge"} 0.0 038 * </pre> 039 */ 040public class JvmGarbageCollectorMetrics { 041 042 private static final String JVM_GC_COLLECTION_SECONDS = "jvm_gc_collection_seconds"; 043 044 private final PrometheusProperties config; 045 private final List<GarbageCollectorMXBean> garbageCollectorBeans; 046 private final Labels constLabels; 047 048 private JvmGarbageCollectorMetrics( 049 List<GarbageCollectorMXBean> garbageCollectorBeans, 050 PrometheusProperties config, 051 Labels constLabels) { 052 this.config = config; 053 this.garbageCollectorBeans = garbageCollectorBeans; 054 this.constLabels = constLabels; 055 } 056 057 private void register(PrometheusRegistry registry) { 058 059 SummaryWithCallback.builder(config) 060 .name(JVM_GC_COLLECTION_SECONDS) 061 .help("Time spent in a given JVM garbage collector in seconds.") 062 .unit(Unit.SECONDS) 063 .labelNames("gc") 064 .callback( 065 callback -> { 066 for (GarbageCollectorMXBean gc : garbageCollectorBeans) { 067 callback.call( 068 gc.getCollectionCount(), 069 Unit.millisToSeconds(gc.getCollectionTime()), 070 Quantiles.EMPTY, 071 gc.getName()); 072 } 073 }) 074 .constLabels(constLabels) 075 .register(registry); 076 } 077 078 public static Builder builder() { 079 return new Builder(PrometheusProperties.get()); 080 } 081 082 public static Builder builder(PrometheusProperties config) { 083 return new Builder(config); 084 } 085 086 public static class Builder { 087 088 private final PrometheusProperties config; 089 @Nullable private List<GarbageCollectorMXBean> garbageCollectorBeans; 090 private Labels constLabels = Labels.EMPTY; 091 092 private Builder(PrometheusProperties config) { 093 this.config = config; 094 } 095 096 public Builder constLabels(Labels constLabels) { 097 this.constLabels = constLabels; 098 return this; 099 } 100 101 /** Package private. For testing only. */ 102 Builder garbageCollectorBeans(List<GarbageCollectorMXBean> garbageCollectorBeans) { 103 this.garbageCollectorBeans = garbageCollectorBeans; 104 return this; 105 } 106 107 public void register() { 108 register(PrometheusRegistry.defaultRegistry); 109 } 110 111 public void register(PrometheusRegistry registry) { 112 List<GarbageCollectorMXBean> garbageCollectorBeans = this.garbageCollectorBeans; 113 if (garbageCollectorBeans == null) { 114 garbageCollectorBeans = ManagementFactory.getGarbageCollectorMXBeans(); 115 } 116 new JvmGarbageCollectorMetrics(garbageCollectorBeans, config, constLabels).register(registry); 117 } 118 } 119}