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

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

There is a newer version: 1.13.0
Show newest version
/**
 * Copyright 2017 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.Timed; import io.micrometer.core.instrument.distribution.DistributionStatisticConfig; import io.micrometer.core.instrument.distribution.HistogramSupport; 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.Consumer; import java.util.function.Supplier; /** * A long task timer is used to track the total duration of all in-flight long-running tasks and the number of * such tasks. * * @author Jon Schneider */ public interface LongTaskTimer extends Meter, HistogramSupport { static Builder builder(String name) { return new Builder(name); } /** * Create a timer builder from a {@link Timed} annotation. * * @param timed The annotation instance to base a new timer on. * @return This builder. */ static Builder builder(Timed timed) { if (!timed.longTask()) { throw new IllegalArgumentException("Cannot build a long task timer from a @Timed annotation that is not marked as a long task"); } if (timed.value().isEmpty()) { throw new IllegalArgumentException("Long tasks instrumented with @Timed require the value attribute to be non-empty"); } return new Builder(timed.value()) .tags(timed.extraTags()) .publishPercentileHistogram(timed.histogram()) .description(timed.description().isEmpty() ? null : timed.description()); } /** * 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. */ default T recordCallable(Callable f) throws Exception { Sample sample = start(); try { return f.call(); } finally { sample.stop(); } } /** * 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 Supplier}. * @return The return value of {@code f}. */ default T record(Supplier f) { Sample sample = start(); try { return f.get(); } finally { sample.stop(); } } /** * Executes the runnable {@code f} and records the time taken. * * @param f Function to execute and measure the execution time with a reference to the * timer id useful for looking up current duration. */ default void record(Consumer f) { Sample sample = start(); try { f.accept(sample); } finally { sample.stop(); } } /** * Executes the runnable {@code f} and records the time taken. * * @param f Function to execute and measure the execution time. */ default void record(Runnable f) { Sample sample = start(); try { f.run(); } finally { sample.stop(); } } /** * Start keeping time for a task. * * @return A task id that can be used to look up how long the task has been running. */ Sample start(); /** * @param unit The time unit to scale the duration to. * @return The cumulative duration of all current tasks. */ double duration(TimeUnit unit); /** * @return The current number of tasks being executed. */ int activeTasks(); /** * @param unit The base unit of time to scale the mean to. * @return The distribution average for all recorded events. * @since 1.5.1 */ default double mean(TimeUnit unit) { int activeTasks = activeTasks(); return activeTasks == 0 ? 0 : duration(unit) / activeTasks; } /** * The amount of time the longest running task has been running * * @param unit The time unit to scale the max to. * @return The maximum active task duration. * @since 1.5.0 */ double max(TimeUnit unit); /** * @return The base time unit of the long task timer to which all published metrics will be scaled * @since 1.5.0 */ TimeUnit baseTimeUnit(); /** * Mark a given task as completed. * * @param task Id for the task to stop. This should be the value returned from {@link #start()}. * @return Duration for the task in nanoseconds. A -1 value will be returned for an unknown task. * @deprecated Use {@link Sample#stop()}. As of 1.5.0, this always returns -1 as tasks no longer have IDs. */ @SuppressWarnings("unused") @Deprecated default long stop(long task) { return -1; } /** * The current duration for an active task. * * @param task Id for the task to stop. This should be the value returned from {@link #start()}. * @param unit The time unit to scale the duration to. * @return Duration for the task. A -1 value will be returned for an unknown task. * @deprecated Use {@link Sample#duration(TimeUnit)}. As of 1.5.0, this always returns -1 as tasks no longer have IDs. */ @SuppressWarnings("unused") @Deprecated default double duration(long task, TimeUnit unit) { return -1; } @Override default Iterable measure() { return Arrays.asList( new Measurement(() -> (double) activeTasks(), Statistic.ACTIVE_TASKS), new Measurement(() -> duration(TimeUnit.NANOSECONDS), Statistic.DURATION) ); } abstract class Sample { /** * Records the duration of the operation * * @return The duration, in nanoseconds, of this sample that was stopped */ public abstract long stop(); /** * @param unit time unit to which the return value will be scaled * @return duration of this sample */ public abstract double duration(TimeUnit unit); } /** * Fluent builder for long task timers. */ class Builder { private final String name; private Tags tags = Tags.empty(); private final DistributionStatisticConfig.Builder distributionConfigBuilder = new DistributionStatisticConfig.Builder(); @Nullable private String description; private Builder(String name) { this.name = name; minimumExpectedValue(Duration.ofMinutes(2)); maximumExpectedValue(Duration.ofHours(2)); } /** * @param tags Must be an even number of arguments representing key/value pairs of tags. * @return The long task timer builder with added tags. */ public Builder tags(String... tags) { return tags(Tags.of(tags)); } /** * @param tags Tags to add to the eventual long task timer. * @return The long task timer builder with added tags. */ public Builder tags(Iterable tags) { this.tags = this.tags.and(tags); return this; } /** * @param key The tag key. * @param value The tag value. * @return The long task timer builder with a single added tag. */ public Builder tag(String key, String value) { this.tags = tags.and(key, value); return this; } /** * @param description Description text of the eventual long task timer. * @return The long task timer builder with added description. */ public Builder description(@Nullable String description) { this.description = description; return this; } /** * Publish at a minimum a histogram containing your defined service level objective (SLO) boundaries. * When used in conjunction with {@link Builder#publishPercentileHistogram()}, the boundaries defined * here are included alongside other buckets used to generate aggregable percentile approximations. * * @param slos Publish SLO boundaries in the set of histogram buckets shipped to the monitoring system. * @return This builder. * @since 1.5.0 */ public Builder serviceLevelObjectives(@Nullable Duration... slos) { if (slos != null) { this.distributionConfigBuilder.serviceLevelObjectives(Arrays.stream(slos).mapToDouble(Duration::toNanos).toArray()); } return this; } /** * Sets the minimum value that this timer is expected to observe. Sets a lower bound * on histogram buckets that are shipped to monitoring systems that support aggregable percentile approximations. * * @param min The minimum value that this timer is expected to observe. * @return This builder. * @since 1.5.0 */ public Builder minimumExpectedValue(@Nullable Duration min) { if (min != null) this.distributionConfigBuilder.minimumExpectedValue((double) min.toNanos()); return this; } /** * Sets the maximum value that this timer is expected to observe. Sets an upper bound * on histogram buckets that are shipped to monitoring systems that support aggregable percentile approximations. * * @param max The maximum value that this timer is expected to observe. * @return This builder. * @since 1.5.0 */ public Builder maximumExpectedValue(@Nullable Duration max) { if (max != null) this.distributionConfigBuilder.maximumExpectedValue((double) max.toNanos()); return this; } /** * Statistics emanating from a timer like max, percentiles, and histogram counts decay over time to * give greater weight to recent samples (exception: histogram counts are cumulative for those systems that expect cumulative * histogram buckets). Samples are accumulated to such statistics in ring buffers which rotate after * this expiry, with a buffer length of {@link #distributionStatisticBufferLength(Integer)}. * * @param expiry The amount of time samples are accumulated to a histogram before it is reset and rotated. * @return This builder. * @since 1.5.0 */ public Builder distributionStatisticExpiry(@Nullable Duration expiry) { this.distributionConfigBuilder.expiry(expiry); return this; } /** * Statistics emanating from a timer like max, percentiles, and histogram counts decay over time to * give greater weight to recent samples (exception: histogram counts are cumulative for those systems that expect cumulative * histogram buckets). Samples are accumulated to such statistics in ring buffers which rotate after * {@link #distributionStatisticExpiry(Duration)}, with this buffer length. * * @param bufferLength The number of histograms to keep in the ring buffer. * @return This builder. * @since 1.5.0 */ public Builder distributionStatisticBufferLength(@Nullable Integer bufferLength) { this.distributionConfigBuilder.bufferLength(bufferLength); return this; } /** * Produces an additional time series for each requested percentile. This percentile * is computed locally, and so can't be aggregated with percentiles computed across other * dimensions (e.g. in a different instance). Use {@link #publishPercentileHistogram()} * to publish a histogram that can be used to generate aggregable percentile approximations. * * @param percentiles Percentiles to compute and publish. The 95th percentile should be expressed as {@code 0.95}. * @return This builder. * @since 1.5.0 */ public Builder publishPercentiles(@Nullable double... percentiles) { this.distributionConfigBuilder.percentiles(percentiles); return this; } /** * Determines the number of digits of precision to maintain on the dynamic range histogram used to compute * percentile approximations. The higher the degrees of precision, the more accurate the approximation is at the * cost of more memory. * * @param digitsOfPrecision The digits of precision to maintain for percentile approximations. * @return This builder. * @since 1.5.0 */ public Builder percentilePrecision(@Nullable Integer digitsOfPrecision) { this.distributionConfigBuilder.percentilePrecision(digitsOfPrecision); return this; } /** * Adds histogram buckets used to generate aggregable percentile approximations in monitoring * systems that have query facilities to do so (e.g. Prometheus' {@code histogram_quantile}, * Atlas' {@code :percentiles}). * * @return This builder. * @since 1.5.0 */ public Builder publishPercentileHistogram() { return publishPercentileHistogram(true); } /** * Adds histogram buckets used to generate aggregable percentile approximations in monitoring * systems that have query facilities to do so (e.g. Prometheus' {@code histogram_quantile}, * Atlas' {@code :percentiles}). * * @param enabled Determines whether percentile histograms should be published. * @return This builder. * @since 1.5.0 */ public Builder publishPercentileHistogram(@Nullable Boolean enabled) { this.distributionConfigBuilder.percentilesHistogram(enabled); return this; } /** * Add the long task timer to a single registry, or return an existing long task timer in that registry. The returned * long task timer will be unique for each registry, but each registry is guaranteed to only create one long task timer * for the same combination of name and tags. * * @param registry A registry to add the long task timer to, if it doesn't already exist. * @return A new or existing long task timer. */ public LongTaskTimer register(MeterRegistry registry) { return registry.more().longTaskTimer(new Meter.Id(name, tags, null, description, Type.LONG_TASK_TIMER), distributionConfigBuilder.build()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy