diff options
author | Yang Song <songy23@users.noreply.github.com> | 2018-04-27 14:47:12 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-27 14:47:12 -0700 |
commit | dec25072b4b7671a8ff35f0a121b41eddff5f66f (patch) | |
tree | f395d21ddce7c2889c987cd46c0bbdcdc469b089 /impl_core/src | |
parent | 4e62aac18595243b9ed4c98137c24e7413c1dc48 (diff) | |
download | opencensus-java-dec25072b4b7671a8ff35f0a121b41eddff5f66f.tar.gz |
Add Aggregation.LastValue and AggregationData.LastValueData to support Gauge (#1055)
* Add LastValue and LastValueData
* Support LastValue and LastValueData in impl
* Use Utils instead of Precondition
* Add LastValue and remove Mean from match() method.
* Support LastValue and LastValueData in exporters and zpages.
* Update MutableLastValue, add comments on why Mean is still supported.
Diffstat (limited to 'impl_core/src')
6 files changed, 231 insertions, 55 deletions
diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java b/impl_core/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java index deabdce7..51504cff 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java @@ -38,6 +38,7 @@ abstract class MutableAggregation { */ abstract void add(double value); + // TODO(songya): remove this method once interval stats is completely removed. /** * Combine the internal values of this MutableAggregation and value of the given * MutableAggregation, with the given fraction. Then set the internal value of this @@ -55,7 +56,8 @@ abstract class MutableAggregation { Function<? super MutableSum, T> p0, Function<? super MutableCount, T> p1, Function<? super MutableMean, T> p2, - Function<? super MutableDistribution, T> p3); + Function<? super MutableDistribution, T> p3, + Function<? super MutableLastValue, T> p4); /** Calculate sum on aggregated {@code MeasureValue}s. */ static final class MutableSum extends MutableAggregation { @@ -98,7 +100,8 @@ abstract class MutableAggregation { Function<? super MutableSum, T> p0, Function<? super MutableCount, T> p1, Function<? super MutableMean, T> p2, - Function<? super MutableDistribution, T> p3) { + Function<? super MutableDistribution, T> p3, + Function<? super MutableLastValue, T> p4) { return p0.apply(this); } } @@ -144,7 +147,8 @@ abstract class MutableAggregation { Function<? super MutableSum, T> p0, Function<? super MutableCount, T> p1, Function<? super MutableMean, T> p2, - Function<? super MutableDistribution, T> p3) { + Function<? super MutableDistribution, T> p3, + Function<? super MutableLastValue, T> p4) { return p1.apply(this); } } @@ -212,7 +216,8 @@ abstract class MutableAggregation { Function<? super MutableSum, T> p0, Function<? super MutableCount, T> p1, Function<? super MutableMean, T> p2, - Function<? super MutableDistribution, T> p3) { + Function<? super MutableDistribution, T> p3, + Function<? super MutableLastValue, T> p4) { return p2.apply(this); } } @@ -354,8 +359,66 @@ abstract class MutableAggregation { Function<? super MutableSum, T> p0, Function<? super MutableCount, T> p1, Function<? super MutableMean, T> p2, - Function<? super MutableDistribution, T> p3) { + Function<? super MutableDistribution, T> p3, + Function<? super MutableLastValue, T> p4) { return p3.apply(this); } } + + /** Calculate last value on aggregated {@code MeasureValue}s. */ + static final class MutableLastValue extends MutableAggregation { + + // Initial value that will get reset as soon as first value is added. + private double lastValue = Double.NaN; + // TODO(songya): remove this once interval stats is completely removed. + private boolean initialized = false; + + private MutableLastValue() {} + + /** + * Construct a {@code MutableLastValue}. + * + * @return an empty {@code MutableLastValue}. + */ + static MutableLastValue create() { + return new MutableLastValue(); + } + + @Override + void add(double value) { + lastValue = value; + // TODO(songya): remove this once interval stats is completely removed. + if (!initialized) { + initialized = true; + } + } + + @Override + void combine(MutableAggregation other, double fraction) { + checkArgument(other instanceof MutableLastValue, "MutableLastValue expected."); + MutableLastValue otherValue = (MutableLastValue) other; + // Assume other is always newer than this, because we combined interval buckets in time order. + // If there's a newer value, overwrite current value. + this.lastValue = otherValue.initialized ? otherValue.getLastValue() : this.lastValue; + } + + /** + * Returns the last value. + * + * @return the last value. + */ + double getLastValue() { + return lastValue; + } + + @Override + final <T> T match( + Function<? super MutableSum, T> p0, + Function<? super MutableCount, T> p1, + Function<? super MutableMean, T> p2, + Function<? super MutableDistribution, T> p3, + Function<? super MutableLastValue, T> p4) { + return p4.apply(this); + } + } } diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/MutableViewData.java b/impl_core/src/main/java/io/opencensus/implcore/stats/MutableViewData.java index d60715b5..f4136616 100644 --- a/impl_core/src/main/java/io/opencensus/implcore/stats/MutableViewData.java +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MutableViewData.java @@ -19,7 +19,7 @@ package io.opencensus.implcore.stats; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.HashMultimap; +import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import io.opencensus.common.Duration; @@ -29,16 +29,20 @@ import io.opencensus.common.Timestamp; import io.opencensus.implcore.internal.CheckerFrameworkUtils; import io.opencensus.implcore.stats.MutableAggregation.MutableCount; import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution; +import io.opencensus.implcore.stats.MutableAggregation.MutableLastValue; import io.opencensus.implcore.stats.MutableAggregation.MutableMean; import io.opencensus.implcore.stats.MutableAggregation.MutableSum; import io.opencensus.implcore.tags.TagContextImpl; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Count; import io.opencensus.stats.Aggregation.Distribution; +import io.opencensus.stats.Aggregation.LastValue; import io.opencensus.stats.Aggregation.Sum; import io.opencensus.stats.AggregationData; import io.opencensus.stats.AggregationData.CountData; import io.opencensus.stats.AggregationData.DistributionData; +import io.opencensus.stats.AggregationData.LastValueDataDouble; +import io.opencensus.stats.AggregationData.LastValueDataLong; import io.opencensus.stats.AggregationData.SumDataDouble; import io.opencensus.stats.AggregationData.SumDataLong; import io.opencensus.stats.Measure; @@ -157,9 +161,9 @@ abstract class MutableViewData { return aggregation.match( CreateMutableSum.INSTANCE, CreateMutableCount.INSTANCE, - CreateMutableMean.INSTANCE, CreateMutableDistribution.INSTANCE, - Functions.<MutableAggregation>throwIllegalArgumentException()); + CreateMutableLastValue.INSTANCE, + AggregationDefaultFunction.INSTANCE); } /** @@ -175,7 +179,8 @@ abstract class MutableViewData { new CreateSumData(measure), CreateCountData.INSTANCE, CreateMeanData.INSTANCE, - CreateDistributionData.INSTANCE); + CreateDistributionData.INSTANCE, + new CreateLastValueData(measure)); } // Covert a mapping from TagValues to MutableAggregation, to a mapping from TagValues to @@ -389,7 +394,9 @@ abstract class MutableViewData { // tag values to aggregation data. private Map<List</*@Nullable*/ TagValue>, AggregationData> combineBucketsAndGetAggregationMap( Timestamp now) { - Multimap<List</*@Nullable*/ TagValue>, MutableAggregation> multimap = HashMultimap.create(); + // Need to maintain the order of inserted MutableAggregations (inserted based on time order). + Multimap<List</*@Nullable*/ TagValue>, MutableAggregation> multimap = + LinkedHashMultimap.create(); // TODO(sebright): Decide whether to use a different class instead of LinkedList. @SuppressWarnings("JdkObsolete") @@ -491,14 +498,20 @@ abstract class MutableViewData { private static final CreateMutableCount INSTANCE = new CreateMutableCount(); } - private static final class CreateMutableMean - implements Function<Aggregation.Mean, MutableAggregation> { + // TODO(songya): remove this once Mean aggregation is completely removed. Before that + // we need to continue supporting Mean, since it could still be used by users and some + // deprecated RPC views. + private static final class AggregationDefaultFunction + implements Function<Aggregation, MutableAggregation> { @Override - public MutableAggregation apply(Aggregation.Mean arg) { - return MutableMean.create(); + public MutableAggregation apply(Aggregation arg) { + if (arg instanceof Aggregation.Mean) { + return MutableMean.create(); + } + throw new IllegalArgumentException("Unknown Aggregation."); } - private static final CreateMutableMean INSTANCE = new CreateMutableMean(); + private static final AggregationDefaultFunction INSTANCE = new AggregationDefaultFunction(); } private static final class CreateMutableDistribution @@ -511,6 +524,16 @@ abstract class MutableViewData { private static final CreateMutableDistribution INSTANCE = new CreateMutableDistribution(); } + private static final class CreateMutableLastValue + implements Function<LastValue, MutableAggregation> { + @Override + public MutableAggregation apply(LastValue arg) { + return MutableLastValue.create(); + } + + private static final CreateMutableLastValue INSTANCE = new CreateMutableLastValue(); + } + private static final class CreateSumData implements Function<MutableSum, AggregationData> { private final Measure measure; @@ -566,6 +589,25 @@ abstract class MutableViewData { private static final CreateDistributionData INSTANCE = new CreateDistributionData(); } + private static final class CreateLastValueData + implements Function<MutableLastValue, AggregationData> { + + private final Measure measure; + + private CreateLastValueData(Measure measure) { + this.measure = measure; + } + + @Override + public AggregationData apply(final MutableLastValue arg) { + return measure.match( + Functions.<AggregationData>returnConstant(LastValueDataDouble.create(arg.getLastValue())), + Functions.<AggregationData>returnConstant( + LastValueDataLong.create(Math.round(arg.getLastValue()))), + Functions.<AggregationData>throwAssertionError()); + } + } + private static final class CreateCumulative implements Function<View.AggregationWindow.Cumulative, MutableViewData> { @Override diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java index 054a5b44..5508588a 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java @@ -19,8 +19,10 @@ package io.opencensus.implcore.stats; import static com.google.common.truth.Truth.assertThat; import io.opencensus.common.Function; +import io.opencensus.common.Functions; import io.opencensus.implcore.stats.MutableAggregation.MutableCount; import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution; +import io.opencensus.implcore.stats.MutableAggregation.MutableLastValue; import io.opencensus.implcore.stats.MutableAggregation.MutableMean; import io.opencensus.implcore.stats.MutableAggregation.MutableSum; import io.opencensus.stats.BucketBoundaries; @@ -48,6 +50,7 @@ public class MutableAggregationTest { assertThat(MutableSum.create().getSum()).isWithin(TOLERANCE).of(0); assertThat(MutableCount.create().getCount()).isEqualTo(0); assertThat(MutableMean.create().getMean()).isWithin(TOLERANCE).of(0); + assertThat(MutableLastValue.create().getLastValue()).isNaN(); BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(0.1, 2.2, 33.3)); MutableDistribution mutableDistribution = MutableDistribution.create(bucketBoundaries); @@ -81,7 +84,8 @@ public class MutableAggregationTest { MutableSum.create(), MutableCount.create(), MutableMean.create(), - MutableDistribution.create(BUCKET_BOUNDARIES)); + MutableDistribution.create(BUCKET_BOUNDARIES), + MutableLastValue.create()); List<Double> values = Arrays.asList(-1.0, 1.0, -5.0, 20.0, 5.0); @@ -120,6 +124,13 @@ public class MutableAggregationTest { assertThat(arg.getBucketCounts()).isEqualTo(new long[] {0, 2, 2, 1}); return null; } + }, + new Function<MutableLastValue, Void>() { + @Override + public Void apply(MutableLastValue arg) { + assertThat(arg.getLastValue()).isWithin(TOLERANCE).of(5.0); + return null; + } }); } } @@ -131,39 +142,22 @@ public class MutableAggregationTest { MutableSum.create(), MutableCount.create(), MutableMean.create(), - MutableDistribution.create(BUCKET_BOUNDARIES)); + MutableDistribution.create(BUCKET_BOUNDARIES), + MutableLastValue.create()); List<String> actual = new ArrayList<String>(); for (MutableAggregation aggregation : aggregations) { actual.add( aggregation.match( - new Function<MutableSum, String>() { - @Override - public String apply(MutableSum arg) { - return "SUM"; - } - }, - new Function<MutableCount, String>() { - @Override - public String apply(MutableCount arg) { - return "COUNT"; - } - }, - new Function<MutableMean, String>() { - @Override - public String apply(MutableMean arg) { - return "MEAN"; - } - }, - new Function<MutableDistribution, String>() { - @Override - public String apply(MutableDistribution arg) { - return "DISTRIBUTION"; - } - })); + Functions.returnConstant("SUM"), + Functions.returnConstant("COUNT"), + Functions.returnConstant("MEAN"), + Functions.returnConstant("DISTRIBUTION"), + Functions.returnConstant("LASTVALUE"))); } - assertThat(actual).isEqualTo(Arrays.asList("SUM", "COUNT", "MEAN", "DISTRIBUTION")); + assertThat(actual) + .isEqualTo(Arrays.asList("SUM", "COUNT", "MEAN", "DISTRIBUTION", "LASTVALUE")); } @Test diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java index bde75232..e397ad65 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java @@ -22,15 +22,19 @@ import com.google.common.collect.ImmutableMap; import io.opencensus.common.Timestamp; import io.opencensus.implcore.stats.MutableAggregation.MutableCount; import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution; +import io.opencensus.implcore.stats.MutableAggregation.MutableLastValue; import io.opencensus.implcore.stats.MutableAggregation.MutableMean; import io.opencensus.implcore.stats.MutableAggregation.MutableSum; import io.opencensus.stats.Aggregation.Count; import io.opencensus.stats.Aggregation.Distribution; +import io.opencensus.stats.Aggregation.LastValue; import io.opencensus.stats.Aggregation.Mean; import io.opencensus.stats.Aggregation.Sum; import io.opencensus.stats.AggregationData; import io.opencensus.stats.AggregationData.CountData; import io.opencensus.stats.AggregationData.DistributionData; +import io.opencensus.stats.AggregationData.LastValueDataDouble; +import io.opencensus.stats.AggregationData.LastValueDataLong; import io.opencensus.stats.AggregationData.MeanData; import io.opencensus.stats.AggregationData.SumDataDouble; import io.opencensus.stats.AggregationData.SumDataLong; @@ -91,6 +95,10 @@ public class MutableViewDataTest { assertThat(((MutableMean) MutableViewData.createMutableAggregation(Mean.create())).getMean()) .isWithin(EPSILON) .of(0D); + assertThat( + ((MutableLastValue) MutableViewData.createMutableAggregation(LastValue.create())) + .getLastValue()) + .isNaN(); MutableDistribution mutableDistribution = (MutableDistribution) @@ -104,15 +112,18 @@ public class MutableViewDataTest { @Test public void createAggregationData() { BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0)); + List<AggregationData> aggregates = new ArrayList<AggregationData>(); + aggregates.add(MutableViewData.createAggregationData(MutableSum.create(), MEASURE_DOUBLE)); + aggregates.add(MutableViewData.createAggregationData(MutableSum.create(), MEASURE_LONG)); + aggregates.add( + MutableViewData.createAggregationData(MutableLastValue.create(), MEASURE_DOUBLE)); + aggregates.add(MutableViewData.createAggregationData(MutableLastValue.create(), MEASURE_LONG)); + List<MutableAggregation> mutableAggregations = Arrays.asList( MutableCount.create(), MutableMean.create(), MutableDistribution.create(bucketBoundaries)); - List<AggregationData> aggregates = new ArrayList<AggregationData>(); - - aggregates.add(MutableViewData.createAggregationData(MutableSum.create(), MEASURE_DOUBLE)); - aggregates.add(MutableViewData.createAggregationData(MutableSum.create(), MEASURE_LONG)); for (MutableAggregation mutableAggregation : mutableAggregations) { aggregates.add(MutableViewData.createAggregationData(mutableAggregation, MEASURE_DOUBLE)); } @@ -121,6 +132,8 @@ public class MutableViewDataTest { .containsExactly( SumDataDouble.create(0), SumDataLong.create(0), + LastValueDataDouble.create(Double.NaN), + LastValueDataLong.create(0), CountData.create(0), MeanData.create(0, 0), DistributionData.create( diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java index 1d57dbe2..88e1df02 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java @@ -26,6 +26,8 @@ import io.opencensus.stats.Aggregation; import io.opencensus.stats.AggregationData; import io.opencensus.stats.AggregationData.CountData; import io.opencensus.stats.AggregationData.DistributionData; +import io.opencensus.stats.AggregationData.LastValueDataDouble; +import io.opencensus.stats.AggregationData.LastValueDataLong; import io.opencensus.stats.AggregationData.MeanData; import io.opencensus.stats.AggregationData.SumDataDouble; import io.opencensus.stats.AggregationData.SumDataLong; @@ -117,14 +119,6 @@ final class StatsTestUtil { return null; } }, - new Function<MeanData, Void>() { - @Override - public Void apply(MeanData arg) { - assertThat(actual).isInstanceOf(MeanData.class); - assertThat(((MeanData) actual).getMean()).isWithin(tolerance).of(arg.getMean()); - return null; - } - }, new Function<DistributionData, Void>() { @Override public Void apply(DistributionData arg) { @@ -133,7 +127,37 @@ final class StatsTestUtil { return null; } }, - Functions.<Void>throwIllegalArgumentException()); + new Function<LastValueDataDouble, Void>() { + @Override + public Void apply(LastValueDataDouble arg) { + assertThat(actual).isInstanceOf(LastValueDataDouble.class); + assertThat(((LastValueDataDouble) actual).getLastValue()) + .isWithin(tolerance) + .of(arg.getLastValue()); + return null; + } + }, + new Function<LastValueDataLong, Void>() { + @Override + public Void apply(LastValueDataLong arg) { + assertThat(actual).isInstanceOf(LastValueDataLong.class); + assertThat(((LastValueDataLong) actual).getLastValue()).isEqualTo(arg.getLastValue()); + return null; + } + }, + new Function<AggregationData, Void>() { + @Override + public Void apply(AggregationData arg) { + if (arg instanceof MeanData) { + assertThat(actual).isInstanceOf(MeanData.class); + assertThat(((MeanData) actual).getMean()) + .isWithin(tolerance) + .of(((MeanData) arg).getMean()); + return null; + } + throw new IllegalArgumentException("Unknown Aggregation."); + } + }); } // Create an empty ViewData with the given View. diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java index 2ec0da1a..270d65c0 100644 --- a/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java @@ -28,9 +28,12 @@ import io.opencensus.implcore.internal.SimpleEventQueue; import io.opencensus.implcore.tags.TagsComponentImplBase; import io.opencensus.stats.Aggregation; import io.opencensus.stats.Aggregation.Distribution; +import io.opencensus.stats.Aggregation.LastValue; import io.opencensus.stats.Aggregation.Mean; import io.opencensus.stats.Aggregation.Sum; import io.opencensus.stats.AggregationData; +import io.opencensus.stats.AggregationData.LastValueDataDouble; +import io.opencensus.stats.AggregationData.LastValueDataLong; import io.opencensus.stats.AggregationData.MeanData; import io.opencensus.stats.AggregationData.SumDataDouble; import io.opencensus.stats.AggregationData.SumDataLong; @@ -109,6 +112,7 @@ public class ViewManagerImplTest { private static final Sum SUM = Sum.create(); private static final Mean MEAN = Mean.create(); private static final Distribution DISTRIBUTION = Distribution.create(BUCKET_BOUNDARIES); + private static final LastValue LAST_VALUE = LastValue.create(); private final TestClock clock = TestClock.create(); @@ -284,6 +288,16 @@ public class ViewManagerImplTest { testRecordCumulative(MEASURE_LONG, SUM, 1000, 2000, 3000, 4000); } + @Test + public void testRecordDouble_lastvalue_cumulative() { + testRecordCumulative(MEASURE_DOUBLE, LAST_VALUE, 11.1, 22.2, 33.3, 44.4); + } + + @Test + public void testRecordLong_lastvalue_cumulative() { + testRecordCumulative(MEASURE_LONG, LAST_VALUE, 1000, 2000, 3000, 4000); + } + private void testRecordCumulative(Measure measure, Aggregation aggregation, double... values) { View view = createCumulativeView(VIEW_NAME, measure, aggregation, Arrays.asList(KEY)); clock.setTime(Timestamp.create(1, 2)); @@ -357,6 +371,32 @@ public class ViewManagerImplTest { SumDataLong.create(30)); } + @Test + public void testRecordDouble_lastvalue_interval() { + testRecordInterval( + MEASURE_DOUBLE, + LAST_VALUE, + new double[] {20.0, -1.0, 1.0, -5.0, 5.0}, + 9.0, + 30.0, + LastValueDataDouble.create(5.0), + LastValueDataDouble.create(9.0), + LastValueDataDouble.create(30.0)); + } + + @Test + public void testRecordLong_lastvalue_interval() { + testRecordInterval( + MEASURE_LONG, + LAST_VALUE, + new double[] {1000, 2000, 3000, 4000, 5000}, + -5000, + 30, + LastValueDataLong.create(5000), + LastValueDataLong.create(-5000), + LastValueDataLong.create(30)); + } + private void testRecordInterval( Measure measure, Aggregation aggregation, |