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

io.micrometer.core.instrument.AbstractTimer 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.instrument.distribution.*; import io.micrometer.core.instrument.distribution.pause.ClockDriftPauseDetector; import io.micrometer.core.instrument.distribution.pause.PauseDetector; import io.micrometer.core.instrument.util.MeterEquivalence; import io.micrometer.core.lang.Nullable; import org.LatencyUtils.IntervalEstimator; import org.LatencyUtils.SimplePauseDetector; import org.LatencyUtils.TimeCappedMovingAverageIntervalEstimator; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; public abstract class AbstractTimer extends AbstractMeter implements Timer { private static Map pauseDetectorCache = new ConcurrentHashMap<>(); protected final Clock clock; protected final Histogram histogram; private final TimeUnit baseTimeUnit; // Only used when pause detection is enabled @Nullable private IntervalEstimator intervalEstimator = null; @Nullable private org.LatencyUtils.PauseDetector pauseDetector; /** * Creates a new timer. * * @param id The timer's name and tags. * @param clock The clock used to measure latency. * @param distributionStatisticConfig Configuration determining which distribution statistics are sent. * @param pauseDetector Compensation for coordinated omission. * @param baseTimeUnit The time scale of this timer. * @deprecated Timer implementations should now declare at construction time whether they support aggregable percentiles or not. * By declaring it up front, Micrometer can memory optimize the histogram structure used to store distribution statistics. */ @Deprecated protected AbstractTimer(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig, PauseDetector pauseDetector, TimeUnit baseTimeUnit) { this(id, clock, distributionStatisticConfig, pauseDetector, baseTimeUnit, false); } /** * Creates a new timer. * * @param id The timer's name and tags. * @param clock The clock used to measure latency. * @param distributionStatisticConfig Configuration determining which distribution statistics are sent. * @param pauseDetector Compensation for coordinated omission. * @param baseTimeUnit The time scale of this timer. * @param supportsAggregablePercentiles Indicates whether the registry supports percentile approximations from histograms. */ protected AbstractTimer(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig, PauseDetector pauseDetector, TimeUnit baseTimeUnit, boolean supportsAggregablePercentiles) { super(id); this.clock = clock; this.baseTimeUnit = baseTimeUnit; initPauseDetector(pauseDetector); if (distributionStatisticConfig.isPublishingPercentiles()) { // hdr-based histogram this.histogram = new TimeWindowPercentileHistogram(clock, distributionStatisticConfig, supportsAggregablePercentiles); } else if (distributionStatisticConfig.isPublishingHistogram()) { // fixed boundary histograms, which have a slightly better memory footprint // when we don't need Micrometer-computed percentiles this.histogram = new TimeWindowFixedBoundaryHistogram(clock, distributionStatisticConfig, supportsAggregablePercentiles); } else { // noop histogram this.histogram = NoopHistogram.INSTANCE; } } private void initPauseDetector(PauseDetector pauseDetectorType) { pauseDetector = pauseDetectorCache.computeIfAbsent(pauseDetectorType, detector -> { if (detector instanceof ClockDriftPauseDetector) { ClockDriftPauseDetector clockDriftPauseDetector = (ClockDriftPauseDetector) detector; return new SimplePauseDetector(clockDriftPauseDetector.getSleepInterval().toNanos(), clockDriftPauseDetector.getPauseThreshold().toNanos(), 1, false); } return null; }); if (pauseDetector instanceof SimplePauseDetector) { this.intervalEstimator = new TimeCappedMovingAverageIntervalEstimator(128, 10000000000L, pauseDetector); pauseDetector.addListener((pauseLength, pauseEndTime) -> { // System.out.println("Pause of length " + (pauseLength / 1e6) + "ms, end time " + pauseEndTime); if (intervalEstimator != null) { long estimatedInterval = intervalEstimator.getEstimatedInterval(pauseEndTime); long observedLatencyMinbar = pauseLength - estimatedInterval; if (observedLatencyMinbar >= estimatedInterval) { recordValueWithExpectedInterval(observedLatencyMinbar, estimatedInterval); } } }); } } private void recordValueWithExpectedInterval(long nanoValue, long expectedIntervalBetweenValueSamples) { record(nanoValue, TimeUnit.NANOSECONDS); if (expectedIntervalBetweenValueSamples <= 0) return; for (long missingValue = nanoValue - expectedIntervalBetweenValueSamples; missingValue >= expectedIntervalBetweenValueSamples; missingValue -= expectedIntervalBetweenValueSamples) { record(missingValue, TimeUnit.NANOSECONDS); } } @Override public T recordCallable(Callable f) throws Exception { final long s = clock.monotonicTime(); try { return f.call(); } finally { final long e = clock.monotonicTime(); record(e - s, TimeUnit.NANOSECONDS); } } @Override public T record(Supplier f) { final long s = clock.monotonicTime(); try { return f.get(); } finally { final long e = clock.monotonicTime(); record(e - s, TimeUnit.NANOSECONDS); } } @Override public void record(Runnable f) { final long s = clock.monotonicTime(); try { f.run(); } finally { final long e = clock.monotonicTime(); record(e - s, TimeUnit.NANOSECONDS); } } @Override public final void record(long amount, TimeUnit unit) { if (amount >= 0) { histogram.recordLong(TimeUnit.NANOSECONDS.convert(amount, unit)); recordNonNegative(amount, unit); if (intervalEstimator != null) { intervalEstimator.recordInterval(clock.monotonicTime()); } } } protected abstract void recordNonNegative(long amount, TimeUnit unit); @Override public HistogramSnapshot takeSnapshot() { return histogram.takeSnapshot(count(), totalTime(TimeUnit.NANOSECONDS), max(TimeUnit.NANOSECONDS)); } @Override public TimeUnit baseTimeUnit() { return baseTimeUnit; } @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") @Override public boolean equals(@Nullable Object o) { return MeterEquivalence.equals(this, o); } @Override public int hashCode() { return MeterEquivalence.hashCode(this); } @Override public void close() { histogram.close(); if (pauseDetector != null) { pauseDetector.shutdown(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy