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