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