001package io.prometheus.metrics.core.datapoints;
002
003import io.prometheus.metrics.annotations.StableApi;
004import java.util.concurrent.Callable;
005import java.util.function.Supplier;
006
007/**
008 * Convenience API for timing durations.
009 *
010 * <p>Durations are recorded in seconds. The Prometheus instrumentation guidelines <a
011 * href="https://prometheus.io/docs/instrumenting/writing_exporters/#naming">say</a>: <i>"Metrics
012 * must use base units (e.g. seconds, bytes) and leave converting them to something more readable to
013 * graphing tools".</i>
014 */
015@StableApi
016public interface TimerApi {
017
018  /**
019   * Start a {@code Timer}. Example:
020   *
021   * <pre>{@code
022   * Histogram histogram = Histogram.builder()
023   *         .name("http_request_duration_seconds")
024   *         .help("HTTP request service time in seconds")
025   *         .unit(SECONDS)
026   *         .labelNames("method", "path")
027   *         .register();
028   *
029   * try (Timer timer = histogram.labelValues("GET", "/").startTimer()) {
030   *     // duration of this code block will be observed.
031   * }
032   * }</pre>
033   *
034   * Durations are recorded in seconds. The Prometheus instrumentation guidelines <a
035   * href="https://prometheus.io/docs/instrumenting/writing_exporters/#naming">say</a>: <i>"Metrics
036   * must use base units (e.g. seconds, bytes) and leave converting them to something more readable
037   * to graphing tools".</i>
038   */
039  Timer startTimer();
040
041  /**
042   * Observe the duration of the {@code func} call. Example:
043   *
044   * <pre>{@code
045   * Histogram histogram = Histogram.builder()
046   *         .name("request_duration_seconds")
047   *         .help("HTTP request service time in seconds")
048   *         .unit(SECONDS)
049   *         .labelNames("method", "path")
050   *         .register();
051   *
052   * histogram2.labelValues("GET", "/").time(() -> {
053   *     // duration of this code block will be observed.
054   * });
055   * }</pre>
056   *
057   * <p>Durations are recorded in seconds. The Prometheus instrumentation guidelines <a
058   * href="https://prometheus.io/docs/instrumenting/writing_exporters/#naming">say</a>: <i>"Metrics
059   * must use base units (e.g. seconds, bytes) and leave converting them to something more readable
060   * to graphing tools".</i>
061   */
062  @SuppressWarnings("try")
063  default void time(Runnable func) {
064    try (Timer ignored = startTimer()) {
065      func.run();
066    }
067  }
068
069  /** Like {@link #time(Runnable)}, but returns the return value of {@code func}. */
070  @SuppressWarnings("try")
071  default <T> T time(Supplier<T> func) {
072    try (Timer ignored = startTimer()) {
073      return func.get();
074    }
075  }
076
077  /** Like {@link #time(Supplier)}, but {@code func} may throw a checked {@code Exception}. */
078  @SuppressWarnings("try")
079  default <T> T timeChecked(Callable<T> func) throws Exception {
080    try (Timer ignored = startTimer()) {
081      return func.call();
082    }
083  }
084}