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