aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYang Song <songy23@users.noreply.github.com>2018-07-18 14:12:44 -0700
committerGitHub <noreply@github.com>2018-07-18 14:12:44 -0700
commit26af97f39aaaf8699588cc8d97f76e1a450a2571 (patch)
treea0985a7370796cee4617f51200a31bcaef75d7a0
parent7e9d4b5563650ea06f96e4130b27789caf776753 (diff)
downloadopencensus-java-26af97f39aaaf8699588cc8d97f76e1a450a2571.tar.gz
Metrics: Add Exemplar to Distribution. (#1321)
-rw-r--r--metrics/src/main/java/io/opencensus/metrics/Distribution.java79
-rw-r--r--metrics/src/test/java/io/opencensus/metrics/DistributionTest.java109
-rw-r--r--metrics/src/test/java/io/opencensus/metrics/PointTest.java6
-rw-r--r--metrics/src/test/java/io/opencensus/metrics/ValueTest.java8
4 files changed, 181 insertions, 21 deletions
diff --git a/metrics/src/main/java/io/opencensus/metrics/Distribution.java b/metrics/src/main/java/io/opencensus/metrics/Distribution.java
index a1026c83..86d8bae1 100644
--- a/metrics/src/main/java/io/opencensus/metrics/Distribution.java
+++ b/metrics/src/main/java/io/opencensus/metrics/Distribution.java
@@ -18,9 +18,13 @@ package io.opencensus.metrics;
import com.google.auto.value.AutoValue;
import io.opencensus.common.ExperimentalApi;
+import io.opencensus.common.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
@@ -46,6 +50,7 @@ public abstract class Distribution {
* @param range {@link Range} of the population values, or {@code null} if count is 0.
* @param bucketBoundaries bucket boundaries of a histogram.
* @param buckets {@link Bucket}s of a histogram.
+ * @param exemplars the exemplars associated with histogram buckets.
* @return a {@code Distribution}.
* @since 0.16
*/
@@ -55,7 +60,8 @@ public abstract class Distribution {
double sumOfSquaredDeviations,
@Nullable Range range,
List<Double> bucketBoundaries,
- List<Bucket> buckets) {
+ List<Bucket> buckets,
+ List<Exemplar> exemplars) {
Utils.checkArgument(count >= 0, "count should be non-negative.");
Utils.checkArgument(
sumOfSquaredDeviations >= 0, "sum of squared deviations should be non-negative.");
@@ -67,13 +73,16 @@ public abstract class Distribution {
} else {
Utils.checkArgument(range != null, "range should be present if count is not 0.");
}
+ Utils.checkNotNull(exemplars, "exemplar list should not be null.");
+ Utils.checkListElementNotNull(exemplars, "exemplar should not be null.");
return new AutoValue_Distribution(
mean,
count,
sumOfSquaredDeviations,
range,
copyBucketBounds(bucketBoundaries),
- copyBucketCount(buckets));
+ copyBucketCount(buckets),
+ Collections.<Exemplar>unmodifiableList(new ArrayList<Exemplar>(exemplars)));
}
private static List<Double> copyBucketBounds(List<Double> bucketBoundaries) {
@@ -175,6 +184,14 @@ public abstract class Distribution {
public abstract List<Bucket> getBuckets();
/**
+ * Returns the {@link Exemplar}s associated with histogram buckets.
+ *
+ * @return the {@code Exemplar}s associated with histogram buckets.
+ * @since 0.16
+ */
+ public abstract List<Exemplar> getExemplars();
+
+ /**
* The range of the population values.
*
* @since 0.16
@@ -247,5 +264,61 @@ public abstract class Distribution {
public abstract long getCount();
}
- // TODO(songya): add support for exemplars.
+ /**
+ * An example point that may be used to annotate aggregated distribution values, associated with a
+ * histogram bucket.
+ *
+ * @since 0.16
+ */
+ @Immutable
+ @AutoValue
+ public abstract static class Exemplar {
+
+ Exemplar() {}
+
+ /**
+ * Returns value of the {@link Exemplar} point.
+ *
+ * @return value of the {@code Exemplar} point.
+ * @since 0.16
+ */
+ public abstract double getValue();
+
+ /**
+ * Returns the time that this {@link Exemplar}'s value was recorded.
+ *
+ * @return the time that this {@code Exemplar}'s value was recorded.
+ * @since 0.16
+ */
+ public abstract Timestamp getTimestamp();
+
+ /**
+ * Returns the contextual information about the example value, represented as a string map.
+ *
+ * @return the contextual information about the example value.
+ * @since 0.16
+ */
+ public abstract Map<String, String> getAttachments();
+
+ /**
+ * Creates an {@link Exemplar}.
+ *
+ * @param value value of the {@link Exemplar} point.
+ * @param timestamp the time that this {@code Exemplar}'s value was recorded.
+ * @param attachments the contextual information about the example value.
+ * @return an {@code Exemplar}.
+ * @since 0.16
+ */
+ public static Exemplar create(
+ double value, Timestamp timestamp, Map<String, String> attachments) {
+ Utils.checkNotNull(attachments, "attachments");
+ Map<String, String> attachmentsCopy =
+ Collections.unmodifiableMap(new HashMap<String, String>(attachments));
+ for (Entry<String, String> entry : attachmentsCopy.entrySet()) {
+ Utils.checkNotNull(entry.getKey(), "key of attachments");
+ Utils.checkNotNull(entry.getValue(), "value of attachments");
+ }
+ return new AutoValue_Distribution_Exemplar(value, timestamp, attachmentsCopy);
+ }
+ }
}
diff --git a/metrics/src/test/java/io/opencensus/metrics/DistributionTest.java b/metrics/src/test/java/io/opencensus/metrics/DistributionTest.java
index 46e664d9..1734f9f5 100644
--- a/metrics/src/test/java/io/opencensus/metrics/DistributionTest.java
+++ b/metrics/src/test/java/io/opencensus/metrics/DistributionTest.java
@@ -19,10 +19,14 @@ package io.opencensus.metrics;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.testing.EqualsTester;
+import io.opencensus.common.Timestamp;
import io.opencensus.metrics.Distribution.Bucket;
+import io.opencensus.metrics.Distribution.Exemplar;
import io.opencensus.metrics.Distribution.Range;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@@ -35,6 +39,12 @@ public class DistributionTest {
@Rule public final ExpectedException thrown = ExpectedException.none();
+ private static final List<Bucket> EMPTY_BUCKET_LIST = Collections.<Bucket>emptyList();
+ private static final List<Exemplar> EMPTY_EXEMPLAR_LIST = Collections.<Exemplar>emptyList();
+ private static final Timestamp TIMESTAMP_1 = Timestamp.create(1, 0);
+ private static final Timestamp TIMESTAMP_2 = Timestamp.create(2, 0);
+ private static final Map<String, String> ATTACHMENTS = Collections.singletonMap("key", "value");
+
@Test
public void createAndGet_Range() {
Range range = Range.create(-5.5, 6.6);
@@ -49,12 +59,23 @@ public class DistributionTest {
}
@Test
+ public void createAndGet_Exemplar() {
+ Exemplar exemplar = Exemplar.create(-9.9, TIMESTAMP_1, ATTACHMENTS);
+ assertThat(exemplar.getValue()).isEqualTo(-9.9);
+ assertThat(exemplar.getTimestamp()).isEqualTo(TIMESTAMP_1);
+ assertThat(exemplar.getAttachments()).isEqualTo(ATTACHMENTS);
+ }
+
+ @Test
public void createAndGet_Distribution() {
Range range = Range.create(-3.4, 5.6);
+ Exemplar exemplar = Exemplar.create(15.0, TIMESTAMP_1, ATTACHMENTS);
List<Double> bucketBounds = Arrays.asList(-1.0, 0.0, 1.0);
List<Bucket> buckets =
Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4));
- Distribution distribution = Distribution.create(6.6, 10, 678.54, range, bucketBounds, buckets);
+ Distribution distribution =
+ Distribution.create(
+ 6.6, 10, 678.54, range, bucketBounds, buckets, Collections.singletonList(exemplar));
assertThat(distribution.getMean()).isEqualTo(6.6);
assertThat(distribution.getCount()).isEqualTo(10);
assertThat(distribution.getSumOfSquaredDeviations()).isEqualTo(678.54);
@@ -63,6 +84,7 @@ public class DistributionTest {
.containsExactlyElementsIn(bucketBounds)
.inOrder();
assertThat(distribution.getBuckets()).containsExactlyElementsIn(buckets).inOrder();
+ assertThat(distribution.getExemplars()).containsExactly(exemplar);
}
@Test
@@ -80,6 +102,29 @@ public class DistributionTest {
}
@Test
+ public void createExemplar_PreventNullAttachments() {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("attachments");
+ Exemplar.create(15, TIMESTAMP_1, null);
+ }
+
+ @Test
+ public void createExemplar_PreventNullAttachmentKey() {
+ Map<String, String> attachments = Collections.singletonMap(null, "value");
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("key of attachment");
+ Exemplar.create(15, TIMESTAMP_1, attachments);
+ }
+
+ @Test
+ public void createExemplar_PreventNullAttachmentValue() {
+ Map<String, String> attachments = Collections.singletonMap("key", null);
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("value of attachment");
+ Exemplar.create(15, TIMESTAMP_1, attachments);
+ }
+
+ @Test
public void createDistribution_NegativeCount() {
Range range = Range.create(-3.4, 5.6);
List<Double> bucketBounds = Arrays.asList(-1.0, 0.0, 1.0);
@@ -87,7 +132,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("count should be non-negative.");
- Distribution.create(6.6, -10, 678.54, range, bucketBounds, buckets);
+ Distribution.create(6.6, -10, 678.54, range, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -97,7 +142,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("sum of squared deviations should be non-negative.");
- Distribution.create(6.6, 0, -678.54, null, bucketBounds, buckets);
+ Distribution.create(6.6, 0, -678.54, null, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -108,7 +153,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("range should not be present if count is 0.");
- Distribution.create(0, 0, 0, range, bucketBounds, buckets);
+ Distribution.create(0, 0, 0, range, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -118,7 +163,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("mean should be 0 if count is 0.");
- Distribution.create(6.6, 0, 0, null, bucketBounds, buckets);
+ Distribution.create(6.6, 0, 0, null, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -128,7 +173,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(0), Bucket.create(0), Bucket.create(0), Bucket.create(0));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("sum of squared deviations should be 0 if count is 0.");
- Distribution.create(0, 0, 678.54, null, bucketBounds, buckets);
+ Distribution.create(0, 0, 678.54, null, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -138,7 +183,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(0), Bucket.create(1), Bucket.create(0), Bucket.create(0));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("range should be present if count is not 0.");
- Distribution.create(6.6, 1, 0, null, bucketBounds, buckets);
+ Distribution.create(6.6, 1, 0, null, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -148,7 +193,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4));
thrown.expect(NullPointerException.class);
thrown.expectMessage("bucketBoundaries list should not be null.");
- Distribution.create(6.6, 10, 678.54, range, null, buckets);
+ Distribution.create(6.6, 10, 678.54, range, null, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -159,7 +204,7 @@ public class DistributionTest {
Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4));
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("bucket boundaries not sorted.");
- Distribution.create(6.6, 10, 678.54, range, bucketBounds, buckets);
+ Distribution.create(6.6, 10, 678.54, range, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -168,7 +213,7 @@ public class DistributionTest {
List<Double> bucketBounds = Arrays.asList(-1.0, 0.0, 1.0);
thrown.expect(NullPointerException.class);
thrown.expectMessage("bucket list should not be null.");
- Distribution.create(6.6, 10, 678.54, range, bucketBounds, null);
+ Distribution.create(6.6, 10, 678.54, range, bucketBounds, null, EMPTY_EXEMPLAR_LIST);
}
@Test
@@ -179,7 +224,30 @@ public class DistributionTest {
Arrays.asList(Bucket.create(3), Bucket.create(1), null, Bucket.create(4));
thrown.expect(NullPointerException.class);
thrown.expectMessage("bucket should not be null.");
- Distribution.create(6.6, 10, 678.54, range, bucketBounds, buckets);
+ Distribution.create(6.6, 10, 678.54, range, bucketBounds, buckets, EMPTY_EXEMPLAR_LIST);
+ }
+
+ @Test
+ public void preventNullExemplarList() {
+ Range range = Range.create(1, 1);
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("exemplar list should not be null.");
+ Distribution.create(1, 1, 1, range, Collections.<Double>emptyList(), EMPTY_BUCKET_LIST, null);
+ }
+
+ @Test
+ public void preventNullExemplar() {
+ Range range = Range.create(1, 1);
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("exemplar should not be null.");
+ Distribution.create(
+ 1,
+ 1,
+ 1,
+ range,
+ Collections.<Double>emptyList(),
+ EMPTY_BUCKET_LIST,
+ Collections.<Exemplar>singletonList(null));
}
@Test
@@ -193,7 +261,8 @@ public class DistributionTest {
Range.create(1, 5),
Arrays.asList(-5.0, 0.0, 5.0),
Arrays.asList(
- Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))),
+ Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ EMPTY_EXEMPLAR_LIST),
Distribution.create(
10,
10,
@@ -201,7 +270,18 @@ public class DistributionTest {
Range.create(1, 5),
Arrays.asList(-5.0, 0.0, 5.0),
Arrays.asList(
- Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))))
+ Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ EMPTY_EXEMPLAR_LIST))
+ .addEqualityGroup(
+ Distribution.create(
+ -7,
+ 10,
+ 23.456,
+ Range.create(-19.1, 19.2),
+ Arrays.asList(-5.0, 0.0, 5.0),
+ Arrays.asList(
+ Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ EMPTY_EXEMPLAR_LIST))
.addEqualityGroup(
Distribution.create(
-7,
@@ -210,7 +290,8 @@ public class DistributionTest {
Range.create(-19.1, 19.2),
Arrays.asList(-5.0, 0.0, 5.0),
Arrays.asList(
- Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))))
+ Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ Collections.singletonList(Exemplar.create(1.0, TIMESTAMP_2, ATTACHMENTS))))
.testEquals();
}
}
diff --git a/metrics/src/test/java/io/opencensus/metrics/PointTest.java b/metrics/src/test/java/io/opencensus/metrics/PointTest.java
index 2da74d38..27feffd8 100644
--- a/metrics/src/test/java/io/opencensus/metrics/PointTest.java
+++ b/metrics/src/test/java/io/opencensus/metrics/PointTest.java
@@ -21,8 +21,10 @@ import static com.google.common.truth.Truth.assertThat;
import com.google.common.testing.EqualsTester;
import io.opencensus.common.Timestamp;
import io.opencensus.metrics.Distribution.Bucket;
+import io.opencensus.metrics.Distribution.Exemplar;
import io.opencensus.metrics.Distribution.Range;
import java.util.Arrays;
+import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -41,8 +43,8 @@ public class PointTest {
678.54,
Range.create(-3.4, 5.6),
Arrays.asList(-1.0, 0.0, 1.0),
- Arrays.asList(
- Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4))));
+ Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ Collections.<Exemplar>emptyList()));
private static final Timestamp TIMESTAMP_1 = Timestamp.create(1, 2);
private static final Timestamp TIMESTAMP_2 = Timestamp.create(3, 4);
private static final Timestamp TIMESTAMP_3 = Timestamp.create(5, 6);
diff --git a/metrics/src/test/java/io/opencensus/metrics/ValueTest.java b/metrics/src/test/java/io/opencensus/metrics/ValueTest.java
index 4864f72f..ee79fa67 100644
--- a/metrics/src/test/java/io/opencensus/metrics/ValueTest.java
+++ b/metrics/src/test/java/io/opencensus/metrics/ValueTest.java
@@ -22,12 +22,14 @@ import com.google.common.testing.EqualsTester;
import io.opencensus.common.Function;
import io.opencensus.common.Functions;
import io.opencensus.metrics.Distribution.Bucket;
+import io.opencensus.metrics.Distribution.Exemplar;
import io.opencensus.metrics.Distribution.Range;
import io.opencensus.metrics.Value.ValueDistribution;
import io.opencensus.metrics.Value.ValueDouble;
import io.opencensus.metrics.Value.ValueLong;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,7 +46,8 @@ public class ValueTest {
1,
Range.create(1, 5),
Arrays.asList(-5.0, 0.0, 5.0),
- Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)));
+ Arrays.asList(Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ Collections.<Exemplar>emptyList());
@Test
public void createAndGet_ValueDouble() {
@@ -83,7 +86,8 @@ public class ValueTest {
Range.create(-19.1, 19.2),
Arrays.asList(-5.0, 0.0, 5.0),
Arrays.asList(
- Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)))))
+ Bucket.create(3), Bucket.create(1), Bucket.create(2), Bucket.create(4)),
+ Collections.<Exemplar>emptyList())))
.testEquals();
}