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