001package io.prometheus.metrics.instrumentation.jvm;
002
003import static io.prometheus.metrics.model.snapshots.Unit.millisToSeconds;
004
005import io.prometheus.metrics.annotations.StableApi;
006import io.prometheus.metrics.config.PrometheusProperties;
007import io.prometheus.metrics.core.metrics.CounterWithCallback;
008import io.prometheus.metrics.model.registry.PrometheusRegistry;
009import io.prometheus.metrics.model.snapshots.Labels;
010import io.prometheus.metrics.model.snapshots.Unit;
011import java.lang.management.CompilationMXBean;
012import java.lang.management.ManagementFactory;
013import javax.annotation.Nullable;
014
015/**
016 * JVM Compilation metrics. The {@link JvmCompilationMetrics} are registered as part of the {@link
017 * JvmMetrics} like this:
018 *
019 * <pre>{@code
020 * JvmMetrics.builder().register();
021 * }</pre>
022 *
023 * However, if you want only the {@link JvmCompilationMetrics} you can also register them directly:
024 *
025 * <pre>{@code
026 * JvmCompilationMetrics.builder().register();
027 * }</pre>
028 *
029 * Example metrics being exported:
030 *
031 * <pre>
032 * # HELP jvm_compilation_time_seconds_total The total time in seconds taken for HotSpot class compilation
033 * # TYPE jvm_compilation_time_seconds_total counter
034 * jvm_compilation_time_seconds_total 0.152
035 * </pre>
036 */
037@StableApi
038public class JvmCompilationMetrics {
039
040  private static final String JVM_COMPILATION_TIME_SECONDS_TOTAL =
041      "jvm_compilation_time_seconds_total";
042
043  private final PrometheusProperties config;
044  private final CompilationMXBean compilationBean;
045  private final Labels constLabels;
046
047  private JvmCompilationMetrics(
048      CompilationMXBean compilationBean, PrometheusProperties config, Labels constLabels) {
049    this.compilationBean = compilationBean;
050    this.config = config;
051    this.constLabels = constLabels;
052  }
053
054  private void register(PrometheusRegistry registry) {
055
056    if (compilationBean == null || !compilationBean.isCompilationTimeMonitoringSupported()) {
057      return;
058    }
059
060    CounterWithCallback.builder(config)
061        .name(JVM_COMPILATION_TIME_SECONDS_TOTAL)
062        .help("The total time in seconds taken for HotSpot class compilation")
063        .unit(Unit.SECONDS)
064        .callback(
065            callback -> callback.call(millisToSeconds(compilationBean.getTotalCompilationTime())))
066        .constLabels(constLabels)
067        .register(registry);
068  }
069
070  public static Builder builder() {
071    return new Builder(PrometheusProperties.get());
072  }
073
074  public static Builder builder(PrometheusProperties config) {
075    return new Builder(config);
076  }
077
078  public static class Builder {
079
080    private final PrometheusProperties config;
081    @Nullable private CompilationMXBean compilationBean;
082    private Labels constLabels = Labels.EMPTY;
083
084    private Builder(PrometheusProperties config) {
085      this.config = config;
086    }
087
088    public Builder constLabels(Labels constLabels) {
089      this.constLabels = constLabels;
090      return this;
091    }
092
093    /** Package private. For testing only. */
094    Builder compilationBean(CompilationMXBean compilationBean) {
095      this.compilationBean = compilationBean;
096      return this;
097    }
098
099    public void register() {
100      register(PrometheusRegistry.defaultRegistry);
101    }
102
103    public void register(PrometheusRegistry registry) {
104      CompilationMXBean compilationBean =
105          this.compilationBean != null
106              ? this.compilationBean
107              : ManagementFactory.getCompilationMXBean();
108      new JvmCompilationMetrics(compilationBean, config, constLabels).register(registry);
109    }
110  }
111}