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}