All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micrometer.core.instrument.Timer Maven / Gradle / Ivy

There is a newer version: 1.13.2
Show newest version
/**
 * Copyright 2019 VMware, Inc.
 * 

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* https://www.apache.org/licenses/LICENSE-2.0 *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.micrometer.core.instrument; import io.micrometer.core.annotation.Incubating; import io.micrometer.core.annotation.Timed; import io.micrometer.core.instrument.distribution.CountAtBucket; import io.micrometer.core.instrument.distribution.HistogramSupport; import io.micrometer.core.instrument.distribution.ValueAtPercentile; import io.micrometer.core.instrument.distribution.pause.PauseDetector; import io.micrometer.core.lang.Nullable; import java.time.Duration; import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; /** * Timer intended to track of a large number of short running events. Example would be something like * an HTTP request. Though "short running" is a bit subjective the assumption is that it should be * under a minute. * * @author Jon Schneider * @author Oleksii Bondar */ public interface Timer extends Meter, HistogramSupport { /** * Start a timing sample using the {@link Clock#SYSTEM System clock}. * * @return A timing sample with start time recorded. * @since 1.1.0 */ static Sample start() { return start(Clock.SYSTEM); } /** * Start a timing sample. * * @param registry A meter registry whose clock is to be used * @return A timing sample with start time recorded. */ static Sample start(MeterRegistry registry) { return start(registry.config().clock()); } /** * Start a timing sample. * * @param clock a clock to be used * @return A timing sample with start time recorded. */ static Sample start(Clock clock) { return new Sample(clock); } static Builder builder(String name) { return new Builder(name); } /** * @param registry A meter registry against which the timer will be registered. * @param name The name of the timer. * @return A timing builder that automatically records a timing on close. * @since 1.6.0 */ @Incubating(since = "1.6.0") static ResourceSample resource(MeterRegistry registry, String name) { return new ResourceSample(registry, name); } /** * Create a timer builder from a {@link Timed} annotation. * * @param timed The annotation instance to base a new timer on. * @param defaultName A default name to use in the event that the value attribute is empty. * @return This builder. */ static Builder builder(Timed timed, String defaultName) { if (timed.longTask() && timed.value().isEmpty()) { // the user MUST name long task timers, we don't lump them in with regular // timers with the same name throw new IllegalArgumentException("Long tasks instrumented with @Timed require the value attribute to be non-empty"); } return new Builder(timed.value().isEmpty() ? defaultName : timed.value()) .tags(timed.extraTags()) .description(timed.description().isEmpty() ? null : timed.description()) .publishPercentileHistogram(timed.histogram()) .publishPercentiles(timed.percentiles().length > 0 ? timed.percentiles() : null); } /** * Updates the statistics kept by the timer with the specified amount. * * @param amount Duration of a single event being measured by this timer. If the amount is less than 0 * the value will be dropped. * @param unit Time unit for the amount being recorded. */ void record(long amount, TimeUnit unit); /** * Updates the statistics kept by the timer with the specified amount. * * @param duration Duration of a single event being measured by this timer. */ default void record(Duration duration) { record(duration.toNanos(), TimeUnit.NANOSECONDS); } /** * Executes the Supplier {@code f} and records the time taken. * * @param f Function to execute and measure the execution time. * @param The return type of the {@link Supplier}. * @return The return value of {@code f}. */ @Nullable T record(Supplier f); /** * Executes the callable {@code f} and records the time taken. * * @param f Function to execute and measure the execution time. * @param The return type of the {@link Callable}. * @return The return value of {@code f}. * @throws Exception Any exception bubbling up from the callable. */ @Nullable T recordCallable(Callable f) throws Exception; /** * Executes the runnable {@code f} and records the time taken. * * @param f Function to execute and measure the execution time. */ void record(Runnable f); /** * Wrap a {@link Runnable} so that it is timed when invoked. * * @param f The Runnable to time when it is invoked. * @return The wrapped Runnable. */ default Runnable wrap(Runnable f) { return () -> record(f); } /** * Wrap a {@link Callable} so that it is timed when invoked. * * @param f The Callable to time when it is invoked. * @param The return type of the callable. * @return The wrapped callable. */ default Callable wrap(Callable f) { return () -> recordCallable(f); } /** * Wrap a {@link Supplier} so that it is timed when invoked. * * @param f The {@code Supplier} to time when it is invoked. * @param The return type of the {@code Supplier} result. * @return The wrapped supplier. * @since 1.2.0 */ default Supplier wrap(Supplier f) { return () -> record(f); } /** * @return The number of times that stop has been called on this timer. */ long count(); /** * @param unit The base unit of time to scale the total to. * @return The total time of recorded events. */ double totalTime(TimeUnit unit); /** * @param unit The base unit of time to scale the mean to. * @return The distribution average for all recorded events. */ default double mean(TimeUnit unit) { long count = count(); return count == 0 ? 0 : totalTime(unit) / count; } /** * @param unit The base unit of time to scale the max to. * @return The maximum time of a single event. */ double max(TimeUnit unit); @Override default Iterable measure() { return Arrays.asList( new Measurement(() -> (double) count(), Statistic.COUNT), new Measurement(() -> totalTime(baseTimeUnit()), Statistic.TOTAL_TIME), new Measurement(() -> max(baseTimeUnit()), Statistic.MAX) ); } /** * Provides cumulative histogram counts. * * @param valueNanos The histogram bucket to retrieve a count for. * @return The count of all events less than or equal to the bucket. If valueNanos does not * match a preconfigured bucket boundary, returns NaN. * @deprecated Use {@link #takeSnapshot()} to retrieve bucket counts. */ @Deprecated default double histogramCountAtValue(long valueNanos) { for (CountAtBucket countAtBucket : takeSnapshot().histogramCounts()) { if ((long) countAtBucket.bucket(TimeUnit.NANOSECONDS) == valueNanos) { return countAtBucket.count(); } } return Double.NaN; } /** * @param percentile A percentile in the domain [0, 1]. For example, 0.5 represents the 50th percentile of the * distribution. * @param unit The base unit of time to scale the percentile value to. * @return The latency at a specific percentile. This value is non-aggregable across dimensions. Returns NaN if * percentile is not a preconfigured percentile that Micrometer is tracking. * @deprecated Use {@link #takeSnapshot()} to retrieve bucket counts. */ @Deprecated default double percentile(double percentile, TimeUnit unit) { for (ValueAtPercentile valueAtPercentile : takeSnapshot().percentileValues()) { if (valueAtPercentile.percentile() == percentile) { return valueAtPercentile.value(unit); } } return Double.NaN; } /** * @return The base time unit of the timer to which all published metrics will be scaled */ TimeUnit baseTimeUnit(); /** * Maintains state on the clock's start position for a latency sample. Complete the timing * by calling {@link Sample#stop(Timer)}. Note how the {@link Timer} isn't provided until the * sample is stopped, allowing you to determine the timer's tags at the last minute. */ class Sample { private final long startTime; private final Clock clock; Sample(Clock clock) { this.clock = clock; this.startTime = clock.monotonicTime(); } /** * Records the duration of the operation. * * @param timer The timer to record the sample to. * @return The total duration of the sample in nanoseconds */ public long stop(Timer timer) { long durationNs = clock.monotonicTime() - startTime; timer.record(durationNs, TimeUnit.NANOSECONDS); return durationNs; } } class ResourceSample extends AbstractTimerBuilder implements AutoCloseable { private final MeterRegistry registry; private final long startTime; ResourceSample(MeterRegistry registry, String name) { super(name); this.registry = registry; this.startTime = registry.config().clock().monotonicTime(); } @Override public void close() { long durationNs = registry.config().clock().monotonicTime() - startTime; registry .timer(new Meter.Id(name, tags, null, description, Type.TIMER), distributionConfigBuilder.build(), pauseDetector == null ? registry.config().pauseDetector() : pauseDetector) .record(durationNs, TimeUnit.NANOSECONDS); } } /** * Fluent builder for timers. */ class Builder extends AbstractTimerBuilder { Builder(String name) { super(name); } @Override public Builder tags(String... tags) { return super.tags(tags); } @Override public Builder tags(Iterable tags) { return super.tags(tags); } @Override public Builder tag(String key, String value) { return super.tag(key, value); } @Override public Builder publishPercentiles(double... percentiles) { return super.publishPercentiles(percentiles); } @Override public Builder percentilePrecision(Integer digitsOfPrecision) { return super.percentilePrecision(digitsOfPrecision); } @Override public Builder publishPercentileHistogram() { return super.publishPercentileHistogram(); } @Override public Builder publishPercentileHistogram(Boolean enabled) { return super.publishPercentileHistogram(enabled); } @SuppressWarnings("deprecation") @Override public Builder sla(Duration... sla) { return super.sla(sla); } @Override public Builder serviceLevelObjectives(Duration... slos) { return super.serviceLevelObjectives(slos); } @Override public Builder minimumExpectedValue(Duration min) { return super.minimumExpectedValue(min); } @Override public Builder maximumExpectedValue(Duration max) { return super.maximumExpectedValue(max); } @Override public Builder distributionStatisticExpiry(Duration expiry) { return super.distributionStatisticExpiry(expiry); } @Override public Builder distributionStatisticBufferLength(Integer bufferLength) { return super.distributionStatisticBufferLength(bufferLength); } @Override public Builder pauseDetector(PauseDetector pauseDetector) { return super.pauseDetector(pauseDetector); } @Override public Builder description(String description) { return super.description(description); } /** * Add the timer to a single registry, or return an existing timer in that registry. The returned * timer will be unique for each registry, but each registry is guaranteed to only create one timer * for the same combination of name and tags. * * @param registry A registry to add the timer to, if it doesn't already exist. * @return A new or existing timer. */ public Timer register(MeterRegistry registry) { // the base unit for a timer will be determined by the monitoring system implementation return registry.timer(new Meter.Id(name, tags, null, description, Type.TIMER), distributionConfigBuilder.build(), pauseDetector == null ? registry.config().pauseDetector() : pauseDetector); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy