|
16 | 16 | package io.micrometer.signalfx;
|
17 | 17 |
|
18 | 18 | import io.micrometer.common.lang.Nullable;
|
19 |
| -import io.micrometer.core.instrument.AbstractTimer; |
20 | 19 | import io.micrometer.core.instrument.Clock;
|
21 | 20 | import io.micrometer.core.instrument.distribution.DistributionStatisticConfig;
|
22 | 21 | import io.micrometer.core.instrument.distribution.HistogramSnapshot;
|
23 |
| -import io.micrometer.core.instrument.distribution.TimeWindowMax; |
| 22 | +import io.micrometer.core.instrument.distribution.StepBucketHistogram; |
24 | 23 | import io.micrometer.core.instrument.distribution.pause.PauseDetector;
|
25 |
| -import io.micrometer.core.instrument.step.StepTuple2; |
26 |
| -import io.micrometer.core.instrument.util.TimeUtils; |
| 24 | +import io.micrometer.core.instrument.step.StepTimer; |
27 | 25 |
|
28 | 26 | import java.util.concurrent.TimeUnit;
|
29 |
| -import java.util.concurrent.atomic.LongAdder; |
30 | 27 |
|
31 | 28 | /**
|
32 |
| - * This class is mostly the same as {@link io.micrometer.core.instrument.step.StepTimer}, |
33 |
| - * with one notable difference: the {@link DistributionStatisticConfig} is modified before |
34 |
| - * being passed to the super class constructor - that forces the histogram generated by |
35 |
| - * this meter to be cumulative. |
| 29 | + * A StepTimer which provides support for multiple flavours of Histograms to be recorded |
| 30 | + * based on {@link SignalFxConfig#publishCumulativeHistogram()} and |
| 31 | + * {@link SignalFxConfig#publishDeltaHistogram()}. |
36 | 32 | *
|
37 | 33 | * @author Bogdan Drutu
|
38 | 34 | * @author Mateusz Rzeszutek
|
| 35 | + * @author Lenin Jaganathan |
39 | 36 | */
|
40 |
| -final class SignalfxTimer extends AbstractTimer { |
41 |
| - |
42 |
| - private final LongAdder count = new LongAdder(); |
43 |
| - |
44 |
| - private final LongAdder total = new LongAdder(); |
45 |
| - |
46 |
| - private final StepTuple2<Long, Long> countTotal; |
47 |
| - |
48 |
| - private final TimeWindowMax max; |
| 37 | +final class SignalfxTimer extends StepTimer { |
49 | 38 |
|
50 | 39 | @Nullable
|
51 |
| - private final DeltaHistogramCounts deltaHistogramCounts; |
| 40 | + private final StepBucketHistogram stepBucketHistogram; |
52 | 41 |
|
53 | 42 | SignalfxTimer(Id id, Clock clock, DistributionStatisticConfig distributionStatisticConfig,
|
54 | 43 | PauseDetector pauseDetector, TimeUnit baseTimeUnit, long stepMillis, boolean isDelta) {
|
55 |
| - super(id, clock, CumulativeHistogramConfigUtil.updateConfig(distributionStatisticConfig), pauseDetector, |
56 |
| - baseTimeUnit, false); |
57 |
| - countTotal = new StepTuple2<>(clock, stepMillis, 0L, 0L, count::sumThenReset, total::sumThenReset); |
58 |
| - max = new TimeWindowMax(clock, distributionStatisticConfig); |
59 |
| - if (distributionStatisticConfig.isPublishingHistogram() && isDelta) { |
60 |
| - deltaHistogramCounts = new DeltaHistogramCounts(); |
| 44 | + super(id, clock, distributionStatisticConfig, pauseDetector, baseTimeUnit, stepMillis, defaultHistogram(clock, |
| 45 | + CumulativeHistogramConfigUtil.updateConfig(distributionStatisticConfig, isDelta), false)); |
| 46 | + |
| 47 | + double[] slo = distributionStatisticConfig.getServiceLevelObjectiveBoundaries(); |
| 48 | + if (slo != null && slo.length > 0 && isDelta) { |
| 49 | + stepBucketHistogram = new StepBucketHistogram(clock, stepMillis, |
| 50 | + DistributionStatisticConfig.builder() |
| 51 | + .serviceLevelObjectives(CumulativeHistogramConfigUtil.addPositiveInfBucket(slo)) |
| 52 | + .build() |
| 53 | + .merge(distributionStatisticConfig), |
| 54 | + false, true); |
61 | 55 | }
|
62 | 56 | else {
|
63 |
| - deltaHistogramCounts = null; |
| 57 | + stepBucketHistogram = null; |
64 | 58 | }
|
65 | 59 | }
|
66 | 60 |
|
67 | 61 | @Override
|
68 | 62 | protected void recordNonNegative(long amount, TimeUnit unit) {
|
69 |
| - final long nanoAmount = (long) TimeUtils.convert(amount, unit, TimeUnit.NANOSECONDS); |
70 |
| - count.increment(); |
71 |
| - total.add(nanoAmount); |
72 |
| - max.record(amount, unit); |
| 63 | + if (stepBucketHistogram != null) { |
| 64 | + stepBucketHistogram.recordLong(TimeUnit.NANOSECONDS.convert(amount, unit)); |
| 65 | + } |
| 66 | + super.recordNonNegative(amount, unit); |
73 | 67 | }
|
74 | 68 |
|
75 | 69 | @Override
|
76 | 70 | public long count() {
|
77 |
| - return countTotal.poll1(); |
78 |
| - } |
79 |
| - |
80 |
| - @Override |
81 |
| - public double totalTime(TimeUnit unit) { |
82 |
| - return TimeUtils.nanosToUnit(countTotal.poll2(), unit); |
83 |
| - } |
84 |
| - |
85 |
| - @Override |
86 |
| - public double max(TimeUnit unit) { |
87 |
| - return max.poll(unit); |
| 71 | + if (stepBucketHistogram != null) { |
| 72 | + // Force the stepBucketHistogram to be aligned to step by calling count. This |
| 73 | + // ensures that all |
| 74 | + // values exported by the Timer are measured for the same step. |
| 75 | + stepBucketHistogram.poll(); |
| 76 | + } |
| 77 | + return super.count(); |
88 | 78 | }
|
89 | 79 |
|
90 | 80 | @Override
|
91 | 81 | public HistogramSnapshot takeSnapshot() {
|
92 | 82 | HistogramSnapshot currentSnapshot = super.takeSnapshot();
|
93 |
| - if (deltaHistogramCounts == null) { |
| 83 | + if (stepBucketHistogram == null) { |
94 | 84 | return currentSnapshot;
|
95 | 85 | }
|
96 |
| - return new HistogramSnapshot(currentSnapshot.count(), // Already delta in sfx |
97 |
| - // implementation |
98 |
| - currentSnapshot.total(), // Already delta in sfx implementation |
99 |
| - currentSnapshot.max(), // Max cannot be calculated as delta, keep the |
100 |
| - // current. |
101 |
| - currentSnapshot.percentileValues(), // No changes to the percentile |
102 |
| - // values. |
103 |
| - deltaHistogramCounts.calculate(currentSnapshot.histogramCounts()), currentSnapshot::outputSummary); |
| 86 | + return new HistogramSnapshot(currentSnapshot.count(), currentSnapshot.total(), currentSnapshot.max(), |
| 87 | + currentSnapshot.percentileValues(), stepBucketHistogram.poll(), currentSnapshot::outputSummary); |
104 | 88 | }
|
105 | 89 |
|
106 | 90 | }
|
0 commit comments