package io.github.resilience4j.metrics; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Snapshot; import io.github.resilience4j.metrics.internal.TimerContext; import io.vavr.CheckedFunction0; import io.vavr.CheckedFunction1; import io.vavr.CheckedRunnable; import java.util.concurrent.Callable; import java.util.concurrent.CompletionStage; import java.util.function.Function; import java.util.function.Supplier; import static com.codahale.metrics.Timer.Context; public interface Timer { /** * Starts the Timer */ Context time(); /** * Stops the Timer and records a failed call. * This method must be invoked when a call failed. */ void onError(Context context); /** * Stops the Timer and records a successful call. */ void onSuccess(Context context); /** * Returns the name of this Timer. * * @return the name of this Timer */ String getName(); /** * Returns the MetricRegistry of this Timer. * * @return the MetricRegistry of this Timer */ MetricRegistry getMetricRegistry(); /** * Returns the Metrics of this Timer. * * @return the Metrics of this Timer */ Timer.Metrics getMetrics(); /** * Creates a timer of a provided MetricRegistry * * @param name the name of the timer * @param metricRegistry the MetricRegistry * @return a Bulkhead instance */ static Timer ofMetricRegistry(String name, MetricRegistry metricRegistry) { return new TimerContext(name, metricRegistry); } /** * Creates a timer of a default MetricRegistry * * @param name the name of the timer * @return a Bulkhead instance */ static Timer of(String name) { return new TimerContext(name, new MetricRegistry()); } /** * Decorates and executes the decorated Runnable. * * @param runnable the original Callable */ default void executeRunnable(Runnable runnable) throws Exception { decorateRunnable(this, runnable).run(); } /** * Decorates and executes the decorated Callable. * * @param callable the original Callable * @param <T> the type of results supplied by this Callable * @return the result of the decorated Callable. */ default <T> T executeCallable(Callable<T> callable) throws Exception { return decorateCallable(this, callable).call(); } /** * Decorates and executes the decorated Supplier. * * @param supplier the original Supplier * @param <T> the type of results supplied by this supplier * @return the result of the decorated Supplier. */ default <T> T executeSupplier(Supplier<T> supplier){ return decorateSupplier(this, supplier).get(); } /** * Decorates and executes the decorated CompletionStage Supplier. * * @param supplier the CompletionStage Supplier * @param <T> the type of results supplied by this supplier * @return the result of the decorated Supplier. */ default <T> CompletionStage<T> executeCompletionStageSupplier(Supplier<CompletionStage<T>> supplier){ return decorateCompletionStageSupplier(this, supplier).get(); } /** * Creates a timed checked supplier. * @param timer the timer to use * @param supplier the original supplier * @return a timed supplier */ static <T> CheckedFunction0<T> decorateCheckedSupplier(Timer timer, CheckedFunction0<T> supplier){ return () -> { final Context context = timer.time(); try { T returnValue = supplier.apply(); timer.onSuccess(context); return returnValue; }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * Creates a timed runnable. * @param timer the timer to use * @param runnable the original runnable * @return a timed runnable */ static CheckedRunnable decorateCheckedRunnable(Timer timer, CheckedRunnable runnable){ return () -> { final Context context = timer.time(); try { runnable.run(); timer.onSuccess(context); }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * Creates a timed checked supplier. * @param timer the timer to use * @param supplier the original supplier * @return a timed supplier */ static <T> Supplier<T> decorateSupplier(Timer timer, Supplier<T> supplier){ return () -> { final Context context = timer.time(); try { T returnValue = supplier.get(); timer.onSuccess(context); return returnValue; }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * Creates a timed Callable. * @param timer the timer to use * @param callable the original Callable * @return a timed Callable */ static <T> Callable<T> decorateCallable(Timer timer, Callable<T> callable){ return () -> { final Context context = timer.time(); try { T returnValue = callable.call(); timer.onSuccess(context); return returnValue; }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * Creates a timed runnable. * @param timer the timer to use * @param runnable the original runnable * @return a timed runnable */ static Runnable decorateRunnable(Timer timer, Runnable runnable){ return () -> { final Context context = timer.time(); try { runnable.run(); timer.onSuccess(context); }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * Creates a timed function. * @param timer the timer to use * @param function the original function * @return a timed function */ static <T, R> Function<T, R> decorateFunction(Timer timer, Function<T, R> function){ return (T t) -> { final Context context = timer.time(); try { R returnValue = function.apply(t); timer.onSuccess(context); return returnValue; }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * Creates a timed function. * @param timer the timer to use * @param function the original function * @return a timed function */ static <T, R> CheckedFunction1<T, R> decorateCheckedFunction(Timer timer, CheckedFunction1<T, R> function){ return (T t) -> { final Context context = timer.time(); try { R returnValue = function.apply(t); timer.onSuccess(context); return returnValue; }catch (Throwable e){ timer.onError(context); throw e; } }; } /** * * @param timer the timer to use * @param stageSupplier the CompletionStage Supplier * @return a decorated completion stage */ static <T> Supplier<CompletionStage<T>> decorateCompletionStageSupplier(Timer timer, Supplier<CompletionStage<T>> stageSupplier) { return () -> { final Context context = timer.time(); try { final CompletionStage<T> stage = stageSupplier.get(); stage.whenComplete((result, throwable) -> { if (throwable != null) { timer.onError(context); } else { timer.onSuccess(context); } }); return stage; } catch (Throwable throwable) { timer.onError(context); throw throwable; } }; } interface Metrics { /** * Returns the current number of total calls. * * @return the current number of total calls */ long getNumberOfTotalCalls(); /** * Returns the current number of successful calls. * * @return the current number of successful calls */ long getNumberOfSuccessfulCalls(); /** * Returns the current number of failed calls. * * @return the current number of failed calls */ long getNumberOfFailedCalls(); /** * Returns the fifteen-minute exponentially-weighted moving average rate at which events have * occurred since the meter was created. * * This rate has the same exponential decay factor as the fifteen-minute load average in the * {@code top} Unix command. * * @return the fifteen-minute exponentially-weighted moving average rate at which events have * occurred since the meter was created */ double getFifteenMinuteRate(); /** * Returns the five-minute exponentially-weighted moving average rate at which events have * occurred since the meter was created. * * This rate has the same exponential decay factor as the five-minute load average in the {@code * top} Unix command. * * @return the five-minute exponentially-weighted moving average rate at which events have * occurred since the meter was created */ double getFiveMinuteRate(); /** * Returns the mean rate at which events have occurred since the meter was created. * * @return the mean rate at which events have occurred since the meter was created */ double getMeanRate(); /** * Returns the one-minute exponentially-weighted moving average rate at which events have * occurred since the meter was created. * * This rate has the same exponential decay factor as the one-minute load average in the {@code * top} Unix command. * * @return the one-minute exponentially-weighted moving average rate at which events have * occurred since the meter was created */ double getOneMinuteRate(); /** * Returns a snapshot of the values. * * @return a snapshot of the values */ Snapshot getSnapshot(); } }