From 5923bdbee2ea12ad9c4fa962b5adf526d9fe839d Mon Sep 17 00:00:00 2001 From: Yang Song Date: Thu, 9 Nov 2017 13:59:08 -0800 Subject: Move implementation directories (#786) * Move directories: core_impl to impl_core, core_impl_java to impl, core_impl_android to impl_lite. --- all/build.gradle | 3 - core_impl/README.md | 5 - core_impl/build.gradle | 19 - .../implcore/stats/CurrentStatsState.java | 61 -- .../opencensus/implcore/stats/IntervalBucket.java | 86 -- .../opencensus/implcore/stats/MeasureMapImpl.java | 60 -- .../implcore/stats/MeasureMapInternal.java | 122 --- .../implcore/stats/MeasureToViewMap.java | 185 ----- .../implcore/stats/MutableAggregation.java | 361 -------- .../opencensus/implcore/stats/MutableViewData.java | 588 ------------- .../implcore/stats/StatsComponentImplBase.java | 72 -- .../io/opencensus/implcore/stats/StatsManager.java | 90 -- .../implcore/stats/StatsRecorderImpl.java | 36 - .../opencensus/implcore/stats/ViewManagerImpl.java | 48 -- .../implcore/tags/CurrentTagContextUtils.java | 73 -- .../implcore/tags/CurrentTaggingState.java | 41 - .../implcore/tags/NoopTagContextBuilder.java | 51 -- .../implcore/tags/TagContextBuilderImpl.java | 64 -- .../opencensus/implcore/tags/TagContextImpl.java | 84 -- .../opencensus/implcore/tags/TagContextUtils.java | 33 - .../io/opencensus/implcore/tags/TaggerImpl.java | 114 --- .../implcore/tags/TagsComponentImplBase.java | 56 -- .../tags/propagation/SerializationUtils.java | 171 ---- .../TagContextBinarySerializerImpl.java | 48 -- .../propagation/TagPropagationComponentImpl.java | 34 - .../implcore/stats/CurrentStatsStateTest.java | 65 -- .../implcore/stats/IntervalBucketTest.java | 120 --- .../implcore/stats/MeasureMapInternalTest.java | 147 ---- .../implcore/stats/MeasureToViewMapTest.java | 69 -- .../implcore/stats/MutableAggregationTest.java | 249 ------ .../implcore/stats/MutableViewDataTest.java | 147 ---- .../implcore/stats/StatsComponentImplBaseTest.java | 73 -- .../implcore/stats/StatsRecorderImplTest.java | 207 ----- .../opencensus/implcore/stats/StatsTestUtil.java | 183 ---- .../implcore/stats/ViewManagerImplTest.java | 924 --------------------- .../implcore/tags/CurrentTagContextUtilsTest.java | 103 --- .../implcore/tags/CurrentTaggingStateTest.java | 43 - .../implcore/tags/ScopedTagContextsTest.java | 110 --- .../implcore/tags/TagContextImplTest.java | 112 --- .../opencensus/implcore/tags/TaggerImplTest.java | 318 ------- .../implcore/tags/TagsComponentImplBaseTest.java | 49 -- .../io/opencensus/implcore/tags/TagsTestUtil.java | 32 - .../TagContextBinarySerializerImplTest.java | 91 -- .../propagation/TagContextDeserializationTest.java | 199 ----- .../tags/propagation/TagContextRoundtripTest.java | 63 -- .../propagation/TagContextSerializationTest.java | 118 --- core_impl_android/README.md | 6 - core_impl_android/build.gradle | 12 - .../impllite/stats/StatsComponentImplLite.java | 31 - .../impllite/tags/TagsComponentImplLite.java | 23 - .../io/opencensus/impllite/stats/StatsTest.java | 41 - .../java/io/opencensus/impllite/tags/TagsTest.java | 41 - core_impl_java/README.md | 5 - core_impl_java/build.gradle | 20 - .../opencensus/impl/stats/StatsComponentImpl.java | 31 - .../io/opencensus/impl/tags/TagsComponentImpl.java | 23 - .../java/io/opencensus/impl/stats/StatsTest.java | 41 - .../java/io/opencensus/impl/tags/TagsTest.java | 41 - examples/build.gradle | 3 +- .../opencensus/impl/stats/StatsComponentImpl.java | 31 + .../io/opencensus/impl/tags/TagsComponentImpl.java | 23 + .../java/io/opencensus/impl/stats/StatsTest.java | 41 + .../java/io/opencensus/impl/tags/TagsTest.java | 41 + .../implcore/stats/CurrentStatsState.java | 61 ++ .../opencensus/implcore/stats/IntervalBucket.java | 86 ++ .../opencensus/implcore/stats/MeasureMapImpl.java | 60 ++ .../implcore/stats/MeasureMapInternal.java | 122 +++ .../implcore/stats/MeasureToViewMap.java | 185 +++++ .../implcore/stats/MutableAggregation.java | 361 ++++++++ .../opencensus/implcore/stats/MutableViewData.java | 588 +++++++++++++ .../implcore/stats/StatsComponentImplBase.java | 72 ++ .../io/opencensus/implcore/stats/StatsManager.java | 90 ++ .../implcore/stats/StatsRecorderImpl.java | 36 + .../opencensus/implcore/stats/ViewManagerImpl.java | 48 ++ .../implcore/tags/CurrentTagContextUtils.java | 73 ++ .../implcore/tags/CurrentTaggingState.java | 41 + .../implcore/tags/NoopTagContextBuilder.java | 51 ++ .../implcore/tags/TagContextBuilderImpl.java | 64 ++ .../opencensus/implcore/tags/TagContextImpl.java | 84 ++ .../opencensus/implcore/tags/TagContextUtils.java | 33 + .../io/opencensus/implcore/tags/TaggerImpl.java | 114 +++ .../implcore/tags/TagsComponentImplBase.java | 56 ++ .../tags/propagation/SerializationUtils.java | 171 ++++ .../TagContextBinarySerializerImpl.java | 48 ++ .../propagation/TagPropagationComponentImpl.java | 34 + .../implcore/stats/CurrentStatsStateTest.java | 65 ++ .../implcore/stats/IntervalBucketTest.java | 120 +++ .../implcore/stats/MeasureMapInternalTest.java | 147 ++++ .../implcore/stats/MeasureToViewMapTest.java | 69 ++ .../implcore/stats/MutableAggregationTest.java | 249 ++++++ .../implcore/stats/MutableViewDataTest.java | 147 ++++ .../implcore/stats/StatsComponentImplBaseTest.java | 73 ++ .../implcore/stats/StatsRecorderImplTest.java | 207 +++++ .../opencensus/implcore/stats/StatsTestUtil.java | 183 ++++ .../implcore/stats/ViewManagerImplTest.java | 924 +++++++++++++++++++++ .../implcore/tags/CurrentTagContextUtilsTest.java | 103 +++ .../implcore/tags/CurrentTaggingStateTest.java | 43 + .../implcore/tags/ScopedTagContextsTest.java | 110 +++ .../implcore/tags/TagContextImplTest.java | 112 +++ .../opencensus/implcore/tags/TaggerImplTest.java | 318 +++++++ .../implcore/tags/TagsComponentImplBaseTest.java | 49 ++ .../io/opencensus/implcore/tags/TagsTestUtil.java | 32 + .../TagContextBinarySerializerImplTest.java | 91 ++ .../propagation/TagContextDeserializationTest.java | 199 +++++ .../tags/propagation/TagContextRoundtripTest.java | 63 ++ .../propagation/TagContextSerializationTest.java | 118 +++ .../impllite/stats/StatsComponentImplLite.java | 31 + .../impllite/tags/TagsComponentImplLite.java | 23 + .../io/opencensus/impllite/stats/StatsTest.java | 41 + .../java/io/opencensus/impllite/tags/TagsTest.java | 41 + settings.gradle | 3 - 111 files changed, 6173 insertions(+), 6247 deletions(-) delete mode 100644 core_impl/README.md delete mode 100644 core_impl/build.gradle delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/MutableViewData.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/StatsManager.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java delete mode 100644 core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java delete mode 100644 core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java delete mode 100644 core_impl_android/README.md delete mode 100644 core_impl_android/build.gradle delete mode 100644 core_impl_android/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java delete mode 100644 core_impl_android/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java delete mode 100644 core_impl_android/src/test/java/io/opencensus/impllite/stats/StatsTest.java delete mode 100644 core_impl_android/src/test/java/io/opencensus/impllite/tags/TagsTest.java delete mode 100644 core_impl_java/README.md delete mode 100644 core_impl_java/build.gradle delete mode 100644 core_impl_java/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java delete mode 100644 core_impl_java/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java delete mode 100644 core_impl_java/src/test/java/io/opencensus/impl/stats/StatsTest.java delete mode 100644 core_impl_java/src/test/java/io/opencensus/impl/tags/TagsTest.java create mode 100644 impl/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java create mode 100644 impl/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java create mode 100644 impl/src/test/java/io/opencensus/impl/stats/StatsTest.java create mode 100644 impl/src/test/java/io/opencensus/impl/tags/TagsTest.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/MutableViewData.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/StatsManager.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java create mode 100644 impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java create mode 100644 impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java create mode 100644 impl_lite/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java create mode 100644 impl_lite/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java create mode 100644 impl_lite/src/test/java/io/opencensus/impllite/stats/StatsTest.java create mode 100644 impl_lite/src/test/java/io/opencensus/impllite/tags/TagsTest.java diff --git a/all/build.gradle b/all/build.gradle index 76146322..58fdb52a 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -14,9 +14,6 @@ buildscript { def subprojects = [ project(':opencensus-api'), project(':opencensus-impl-core'), - project(':core_impl'), - project(':core_impl_android'), - project(':core_impl_java'), project(':opencensus-impl'), project(':opencensus-impl-lite'), project(':opencensus-testing'), diff --git a/core_impl/README.md b/core_impl/README.md deleted file mode 100644 index 4d4c64e7..00000000 --- a/core_impl/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Will be ported to io.opencensus soon in impl_core/. -====================================================== - -* The main implementation shared between Java and Android. -* Java 7 and Android compatible. diff --git a/core_impl/build.gradle b/core_impl/build.gradle deleted file mode 100644 index 5c36cadc..00000000 --- a/core_impl/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -description = 'OpenCensus Core Impl' - -dependencies { - compile project(':opencensus-api'), - project(':opencensus-impl-core'), - libraries.guava - - testCompile project(':opencensus-api'), - project(':opencensus-impl-core'), - project(':opencensus-testing') - - signature "org.codehaus.mojo.signature:java16:+@signature" -} - -// Disable javadoc because fails with the error: -// javadoc: error - No public or protected classes found to document. -javadoc { - enabled = false -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java b/core_impl/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java deleted file mode 100644 index 88a1f79a..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.StatsComponent; -import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.ThreadSafe; - -/** - * The current {@link StatsCollectionState} for a {@link StatsComponent}. - * - *

This class allows different stats classes to share the state in a thread-safe way. - */ -@ThreadSafe -public final class CurrentStatsState { - - @GuardedBy("this") - private StatsCollectionState currentState = StatsCollectionState.ENABLED; - - @GuardedBy("this") - private boolean isRead; - - public synchronized StatsCollectionState get() { - isRead = true; - return getInternal(); - } - - synchronized StatsCollectionState getInternal() { - return currentState; - } - - // Sets current state to the given state. Returns true if the current state is changed, false - // otherwise. - synchronized boolean set(StatsCollectionState state) { - checkState(!isRead, "State was already read, cannot set state."); - if (state == currentState) { - return false; - } else { - currentState = checkNotNull(state, "state"); - return true; - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java b/core_impl/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java deleted file mode 100644 index 68380791..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static io.opencensus.implcore.stats.MutableViewData.toMillis; - -import com.google.common.collect.Maps; -import io.opencensus.common.Duration; -import io.opencensus.common.Timestamp; -import io.opencensus.stats.Aggregation; -import io.opencensus.tags.TagValue; -import java.util.List; -import java.util.Map; - -/** The bucket with aggregated {@code MeasureValue}s used for {@code IntervalViewData}. */ -final class IntervalBucket { - - private static final Duration ZERO = Duration.create(0, 0); - - private final Timestamp start; - private final Duration duration; - private final Aggregation aggregation; - private final Map, MutableAggregation> tagValueAggregationMap = Maps.newHashMap(); - - IntervalBucket(Timestamp start, Duration duration, Aggregation aggregation) { - checkNotNull(start, "Start"); - checkNotNull(duration, "Duration"); - checkArgument(duration.compareTo(ZERO) > 0, "Duration must be positive"); - checkNotNull(aggregation, "Aggregation"); - this.start = start; - this.duration = duration; - this.aggregation = aggregation; - } - - Map, MutableAggregation> getTagValueAggregationMap() { - return tagValueAggregationMap; - } - - Timestamp getStart() { - return start; - } - - // Puts a new value into the internal MutableAggregations, based on the TagValues. - void record(List tagValues, double value) { - if (!tagValueAggregationMap.containsKey(tagValues)) { - tagValueAggregationMap.put(tagValues, MutableViewData.createMutableAggregation(aggregation)); - } - tagValueAggregationMap.get(tagValues).add(value); - } - - /* - * Returns how much fraction of duration has passed in this IntervalBucket. For example, if this - * bucket starts at 10s and has a duration of 20s, and now is 15s, then getFraction() should - * return (15 - 10) / 20 = 0.25. - * - * This IntervalBucket must be current, i.e. the current timestamp must be within - * [this.start, this.start + this.duration). - */ - double getFraction(Timestamp now) { - Duration elapsedTime = now.subtractTimestamp(start); - checkArgument( - elapsedTime.compareTo(ZERO) >= 0 && elapsedTime.compareTo(duration) < 0, - "This bucket must be current."); - return ((double) toMillis(elapsedTime)) / toMillis(duration); - } - - void clearStats() { - tagValueAggregationMap.clear(); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java b/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java deleted file mode 100644 index a156747f..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import io.opencensus.stats.Measure.MeasureDouble; -import io.opencensus.stats.Measure.MeasureLong; -import io.opencensus.stats.MeasureMap; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.unsafe.ContextUtils; - -/** Implementation of {@link MeasureMap}. */ -final class MeasureMapImpl extends MeasureMap { - private final StatsManager statsManager; - private final MeasureMapInternal.Builder builder = MeasureMapInternal.builder(); - - static MeasureMapImpl create(StatsManager statsManager) { - return new MeasureMapImpl(statsManager); - } - - private MeasureMapImpl(StatsManager statsManager) { - this.statsManager = statsManager; - } - - @Override - public MeasureMapImpl put(MeasureDouble measure, double value) { - builder.put(measure, value); - return this; - } - - @Override - public MeasureMapImpl put(MeasureLong measure, long value) { - builder.put(measure, value); - return this; - } - - @Override - public void record() { - // Use the context key directly, to avoid depending on the tags implementation. - record(ContextUtils.TAG_CONTEXT_KEY.get()); - } - - @Override - public void record(TagContext tags) { - statsManager.record(tags, builder.build()); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java b/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java deleted file mode 100644 index c68b4aff..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import io.opencensus.stats.Measure; -import io.opencensus.stats.Measure.MeasureDouble; -import io.opencensus.stats.Measure.MeasureLong; -import io.opencensus.stats.Measurement; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.NoSuchElementException; - -// TODO(songya): consider combining MeasureMapImpl and this class. -/** A map from {@link Measure}'s to measured values. */ -final class MeasureMapInternal { - - /** Returns a {@link Builder} for the {@link MeasureMapInternal} class. */ - static Builder builder() { - return new Builder(); - } - - /** - * Returns an {@link Iterator} over the measure/value mappings in this {@link MeasureMapInternal}. - * The {@code Iterator} does not support {@link Iterator#remove()}. - */ - Iterator iterator() { - return new MeasureMapInternalIterator(); - } - - private final ArrayList measurements; - - private MeasureMapInternal(ArrayList measurements) { - this.measurements = measurements; - } - - /** Builder for the {@link MeasureMapInternal} class. */ - static class Builder { - /** - * Associates the {@link MeasureDouble} with the given value. Subsequent updates to the same - * {@link MeasureDouble} will overwrite the previous value. - * - * @param measure the {@link MeasureDouble} - * @param value the value to be associated with {@code measure} - * @return this - */ - Builder put(MeasureDouble measure, double value) { - measurements.add(Measurement.MeasurementDouble.create(measure, value)); - return this; - } - - /** - * Associates the {@link MeasureLong} with the given value. Subsequent updates to the same - * {@link MeasureLong} will overwrite the previous value. - * - * @param measure the {@link MeasureLong} - * @param value the value to be associated with {@code measure} - * @return this - */ - Builder put(MeasureLong measure, long value) { - measurements.add(Measurement.MeasurementLong.create(measure, value)); - return this; - } - - /** Constructs a {@link MeasureMapInternal} from the current measurements. */ - MeasureMapInternal build() { - // Note: this makes adding measurements quadratic but is fastest for the sizes of - // MeasureMapInternals that we should see. We may want to go to a strategy of sort/eliminate - // for larger MeasureMapInternals. - for (int i = measurements.size() - 1; i >= 0; i--) { - for (int j = i - 1; j >= 0; j--) { - if (measurements.get(i).getMeasure() == measurements.get(j).getMeasure()) { - measurements.remove(j); - j--; - } - } - } - return new MeasureMapInternal(measurements); - } - - private final ArrayList measurements = new ArrayList(); - - private Builder() {} - } - - // Provides an unmodifiable Iterator over this instance's measurements. - private final class MeasureMapInternalIterator implements Iterator { - @Override - public boolean hasNext() { - return position < length; - } - - @Override - public Measurement next() { - if (position >= measurements.size()) { - throw new NoSuchElementException(); - } - return measurements.get(position++); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - private final int length = measurements.size(); - private int position = 0; - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java b/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java deleted file mode 100644 index 50cb236a..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Maps; -import com.google.common.collect.Multimap; -import io.opencensus.common.Clock; -import io.opencensus.common.Function; -import io.opencensus.common.Functions; -import io.opencensus.common.Timestamp; -import io.opencensus.stats.Measure; -import io.opencensus.stats.Measurement; -import io.opencensus.stats.Measurement.MeasurementDouble; -import io.opencensus.stats.Measurement.MeasurementLong; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.View; -import io.opencensus.stats.ViewData; -import io.opencensus.tags.TagContext; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import javax.annotation.Nullable; -import javax.annotation.concurrent.GuardedBy; - -/** A class that stores a singleton map from {@code MeasureName}s to {@link MutableViewData}s. */ -final class MeasureToViewMap { - - /* - * A synchronized singleton map that stores the one-to-many mapping from Measures - * to MutableViewDatas. - */ - @GuardedBy("this") - private final Multimap mutableMap = - HashMultimap.create(); - - @GuardedBy("this") - private final Map registeredViews = new HashMap(); - - // TODO(songya): consider adding a Measure.Name class - @GuardedBy("this") - private final Map registeredMeasures = Maps.newHashMap(); - - /** Returns a {@link ViewData} corresponding to the given {@link View.Name}. */ - synchronized ViewData getView(View.Name viewName, Clock clock, StatsCollectionState state) { - MutableViewData view = getMutableViewData(viewName); - return view == null ? null : view.toViewData(clock.now(), state); - } - - @Nullable - private synchronized MutableViewData getMutableViewData(View.Name viewName) { - View view = registeredViews.get(viewName); - if (view == null) { - return null; - } - Collection views = mutableMap.get(view.getMeasure().getName()); - for (MutableViewData viewData : views) { - if (viewData.getView().getName().equals(viewName)) { - return viewData; - } - } - throw new AssertionError( - "Internal error: Not recording stats for view: \"" - + viewName - + "\" registeredViews=" - + registeredViews - + ", mutableMap=" - + mutableMap); - } - - /** Enable stats collection for the given {@link View}. */ - synchronized void registerView(View view, Clock clock) { - View existing = registeredViews.get(view.getName()); - if (existing != null) { - if (existing.equals(view)) { - // Ignore views that are already registered. - return; - } else { - throw new IllegalArgumentException( - "A different view with the same name is already registered: " + existing); - } - } - Measure measure = view.getMeasure(); - Measure registeredMeasure = registeredMeasures.get(measure.getName()); - if (registeredMeasure != null && !registeredMeasure.equals(measure)) { - throw new IllegalArgumentException( - "A different measure with the same name is already registered: " + registeredMeasure); - } - registeredViews.put(view.getName(), view); - if (registeredMeasure == null) { - registeredMeasures.put(measure.getName(), measure); - } - mutableMap.put(view.getMeasure().getName(), MutableViewData.create(view, clock.now())); - } - - // Records stats with a set of tags. - synchronized void record(TagContext tags, MeasureMapInternal stats, Timestamp timestamp) { - Iterator iterator = stats.iterator(); - while (iterator.hasNext()) { - Measurement measurement = iterator.next(); - Measure measure = measurement.getMeasure(); - if (!measure.equals(registeredMeasures.get(measure.getName()))) { - // unregistered measures will be ignored. - return; - } - Collection views = mutableMap.get(measure.getName()); - for (MutableViewData view : views) { - measurement.match( - new RecordDoubleValueFunc(tags, view, timestamp), - new RecordLongValueFunc(tags, view, timestamp), - Functions.throwAssertionError()); - } - } - } - - // Clear stats for all the current MutableViewData - synchronized void clearStats() { - for (Entry> entry : mutableMap.asMap().entrySet()) { - for (MutableViewData mutableViewData : entry.getValue()) { - mutableViewData.clearStats(); - } - } - } - - // Resume stats collection for all MutableViewData. - synchronized void resumeStatsCollection(Timestamp now) { - for (Entry> entry : mutableMap.asMap().entrySet()) { - for (MutableViewData mutableViewData : entry.getValue()) { - mutableViewData.resumeStatsCollection(now); - } - } - } - - private static final class RecordDoubleValueFunc implements Function { - @Override - public Void apply(MeasurementDouble arg) { - view.record(tags, arg.getValue(), timestamp); - return null; - } - - private final TagContext tags; - private final MutableViewData view; - private final Timestamp timestamp; - - private RecordDoubleValueFunc(TagContext tags, MutableViewData view, Timestamp timestamp) { - this.tags = tags; - this.view = view; - this.timestamp = timestamp; - } - } - - private static final class RecordLongValueFunc implements Function { - @Override - public Void apply(MeasurementLong arg) { - view.record(tags, arg.getValue(), timestamp); - return null; - } - - private final TagContext tags; - private final MutableViewData view; - private final Timestamp timestamp; - - private RecordLongValueFunc(TagContext tags, MutableViewData view, Timestamp timestamp) { - this.tags = tags; - this.view = view; - this.timestamp = timestamp; - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java b/core_impl/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java deleted file mode 100644 index deabdce7..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import io.opencensus.common.Function; -import io.opencensus.stats.Aggregation; -import io.opencensus.stats.BucketBoundaries; - -/** Mutable version of {@link Aggregation} that supports adding values. */ -abstract class MutableAggregation { - - private MutableAggregation() {} - - // Tolerance for double comparison. - private static final double TOLERANCE = 1e-6; - - /** - * Put a new value into the MutableAggregation. - * - * @param value new value to be added to population - */ - abstract void add(double value); - - /** - * Combine the internal values of this MutableAggregation and value of the given - * MutableAggregation, with the given fraction. Then set the internal value of this - * MutableAggregation to the combined value. - * - * @param other the other {@code MutableAggregation}. The type of this and other {@code - * MutableAggregation} must match. - * @param fraction the fraction that the value in other {@code MutableAggregation} should - * contribute. Must be within [0.0, 1.0]. - */ - abstract void combine(MutableAggregation other, double fraction); - - /** Applies the given match function to the underlying data type. */ - abstract T match( - Function p0, - Function p1, - Function p2, - Function p3); - - /** Calculate sum on aggregated {@code MeasureValue}s. */ - static final class MutableSum extends MutableAggregation { - - private double sum = 0.0; - - private MutableSum() {} - - /** - * Construct a {@code MutableSum}. - * - * @return an empty {@code MutableSum}. - */ - static MutableSum create() { - return new MutableSum(); - } - - @Override - void add(double value) { - sum += value; - } - - @Override - void combine(MutableAggregation other, double fraction) { - checkArgument(other instanceof MutableSum, "MutableSum expected."); - this.sum += fraction * ((MutableSum) other).getSum(); - } - - /** - * Returns the aggregated sum. - * - * @return the aggregated sum. - */ - double getSum() { - return sum; - } - - @Override - final T match( - Function p0, - Function p1, - Function p2, - Function p3) { - return p0.apply(this); - } - } - - /** Calculate count on aggregated {@code MeasureValue}s. */ - static final class MutableCount extends MutableAggregation { - - private long count = 0; - - private MutableCount() {} - - /** - * Construct a {@code MutableCount}. - * - * @return an empty {@code MutableCount}. - */ - static MutableCount create() { - return new MutableCount(); - } - - @Override - void add(double value) { - count++; - } - - @Override - void combine(MutableAggregation other, double fraction) { - checkArgument(other instanceof MutableCount, "MutableCount expected."); - this.count += Math.round(fraction * ((MutableCount) other).getCount()); - } - - /** - * Returns the aggregated count. - * - * @return the aggregated count. - */ - long getCount() { - return count; - } - - @Override - final T match( - Function p0, - Function p1, - Function p2, - Function p3) { - return p1.apply(this); - } - } - - /** Calculate mean on aggregated {@code MeasureValue}s. */ - static final class MutableMean extends MutableAggregation { - - private double sum = 0.0; - private long count = 0; - - private MutableMean() {} - - /** - * Construct a {@code MutableMean}. - * - * @return an empty {@code MutableMean}. - */ - static MutableMean create() { - return new MutableMean(); - } - - @Override - void add(double value) { - count++; - sum += value; - } - - @Override - void combine(MutableAggregation other, double fraction) { - checkArgument(other instanceof MutableMean, "MutableMean expected."); - MutableMean mutableMean = (MutableMean) other; - this.count += Math.round(mutableMean.count * fraction); - this.sum += mutableMean.sum * fraction; - } - - /** - * Returns the aggregated mean. - * - * @return the aggregated mean. - */ - double getMean() { - return getCount() == 0 ? 0 : getSum() / getCount(); - } - - /** - * Returns the aggregated count. - * - * @return the aggregated count. - */ - long getCount() { - return count; - } - - /** - * Returns the aggregated sum. - * - * @return the aggregated sum. - */ - double getSum() { - return sum; - } - - @Override - final T match( - Function p0, - Function p1, - Function p2, - Function p3) { - return p2.apply(this); - } - } - - /** Calculate distribution stats on aggregated {@code MeasureValue}s. */ - static final class MutableDistribution extends MutableAggregation { - - private double sum = 0.0; - private double mean = 0.0; - private long count = 0; - private double sumOfSquaredDeviations = 0.0; - - // Initial "impossible" values, that will get reset as soon as first value is added. - private double min = Double.POSITIVE_INFINITY; - private double max = Double.NEGATIVE_INFINITY; - - private final BucketBoundaries bucketBoundaries; - private final long[] bucketCounts; - - private MutableDistribution(BucketBoundaries bucketBoundaries) { - this.bucketBoundaries = bucketBoundaries; - this.bucketCounts = new long[bucketBoundaries.getBoundaries().size() + 1]; - } - - /** - * Construct a {@code MutableDistribution}. - * - * @return an empty {@code MutableDistribution}. - */ - static MutableDistribution create(BucketBoundaries bucketBoundaries) { - checkNotNull(bucketBoundaries, "bucketBoundaries should not be null."); - return new MutableDistribution(bucketBoundaries); - } - - @Override - void add(double value) { - sum += value; - count++; - - /* - * Update the sum of squared deviations from the mean with the given value. For values - * x_i this is Sum[i=1..n]((x_i - mean)^2) - * - * Computed using Welfords method (see - * https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance, or Knuth, "The Art of - * Computer Programming", Vol. 2, page 323, 3rd edition) - */ - double deltaFromMean = value - mean; - mean += deltaFromMean / count; - double deltaFromMean2 = value - mean; - sumOfSquaredDeviations += deltaFromMean * deltaFromMean2; - - if (value < min) { - min = value; - } - if (value > max) { - max = value; - } - - for (int i = 0; i < bucketBoundaries.getBoundaries().size(); i++) { - if (value < bucketBoundaries.getBoundaries().get(i)) { - bucketCounts[i]++; - return; - } - } - bucketCounts[bucketCounts.length - 1]++; - } - - // We don't compute fractional MutableDistribution, it's either whole or none. - @Override - void combine(MutableAggregation other, double fraction) { - checkArgument(other instanceof MutableDistribution, "MutableDistribution expected."); - if (Math.abs(1.0 - fraction) > TOLERANCE) { - return; - } - - MutableDistribution mutableDistribution = (MutableDistribution) other; - checkArgument( - this.bucketBoundaries.equals(mutableDistribution.bucketBoundaries), - "Bucket boundaries should match."); - - // Algorithm for calculating the combination of sum of squared deviations: - // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm. - if (this.count + mutableDistribution.count > 0) { - double delta = mutableDistribution.mean - this.mean; - this.sumOfSquaredDeviations = - this.sumOfSquaredDeviations - + mutableDistribution.sumOfSquaredDeviations - + Math.pow(delta, 2) - * this.count - * mutableDistribution.count - / (this.count + mutableDistribution.count); - } - - this.count += mutableDistribution.count; - this.sum += mutableDistribution.sum; - this.mean = this.sum / this.count; - - if (mutableDistribution.min < this.min) { - this.min = mutableDistribution.min; - } - if (mutableDistribution.max > this.max) { - this.max = mutableDistribution.max; - } - - long[] bucketCounts = mutableDistribution.getBucketCounts(); - for (int i = 0; i < bucketCounts.length; i++) { - this.bucketCounts[i] += bucketCounts[i]; - } - } - - double getMean() { - return mean; - } - - long getCount() { - return count; - } - - double getMin() { - return min; - } - - double getMax() { - return max; - } - - // Returns the aggregated sum of squared deviations. - double getSumOfSquaredDeviations() { - return sumOfSquaredDeviations; - } - - long[] getBucketCounts() { - return bucketCounts; - } - - @Override - final T match( - Function p0, - Function p1, - Function p2, - Function p3) { - return p3.apply(this); - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/MutableViewData.java b/core_impl/src/main/java/io/opencensus/implcore/stats/MutableViewData.java deleted file mode 100644 index 1347a721..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/MutableViewData.java +++ /dev/null @@ -1,588 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.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.Maps; -import com.google.common.collect.Multimap; -import io.opencensus.common.Duration; -import io.opencensus.common.Function; -import io.opencensus.common.Functions; -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.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.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.MeanData; -import io.opencensus.stats.AggregationData.SumDataDouble; -import io.opencensus.stats.AggregationData.SumDataLong; -import io.opencensus.stats.Measure; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.View; -import io.opencensus.stats.View.AggregationWindow.Cumulative; -import io.opencensus.stats.View.AggregationWindow.Interval; -import io.opencensus.stats.ViewData; -import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; -import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData; -import io.opencensus.tags.InternalUtils; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** A mutable version of {@link ViewData}, used for recording stats and start/end time. */ -abstract class MutableViewData { - - private static final long MILLIS_PER_SECOND = 1000L; - private static final long NANOS_PER_MILLI = 1000 * 1000; - - @VisibleForTesting static final TagValue UNKNOWN_TAG_VALUE = null; - @VisibleForTesting static final Timestamp ZERO_TIMESTAMP = Timestamp.create(0, 0); - - private final View view; - - private MutableViewData(View view) { - this.view = view; - } - - /** - * Constructs a new {@link MutableViewData}. - * - * @param view the {@code View} linked with this {@code MutableViewData}. - * @param start the start {@code Timestamp}. - * @return a {@code MutableViewData}. - */ - static MutableViewData create(final View view, final Timestamp start) { - return view.getWindow() - .match( - new CreateCumulative(view, start), - new CreateInterval(view, start), - Functions.throwAssertionError()); - } - - /** The {@link View} associated with this {@link ViewData}. */ - View getView() { - return view; - } - - /** Record double stats with the given tags. */ - abstract void record(TagContext context, double value, Timestamp timestamp); - - /** Record long stats with the given tags. */ - void record(TagContext tags, long value, Timestamp timestamp) { - // TODO(songya): shall we check for precision loss here? - record(tags, (double) value, timestamp); - } - - /** Convert this {@link MutableViewData} to {@link ViewData}. */ - abstract ViewData toViewData(Timestamp now, StatsCollectionState state); - - // Clear recorded stats. - abstract void clearStats(); - - // Resume stats collection, and reset Start Timestamp (for CumulativeMutableViewData), or refresh - // bucket list (for InternalMutableViewData). - abstract void resumeStatsCollection(Timestamp now); - - private static Map getTagMap(TagContext ctx) { - if (ctx instanceof TagContextImpl) { - return ((TagContextImpl) ctx).getTags(); - } else { - Map tags = Maps.newHashMap(); - for (Iterator i = InternalUtils.getTags(ctx); i.hasNext(); ) { - Tag tag = i.next(); - tags.put(tag.getKey(), tag.getValue()); - } - return tags; - } - } - - @VisibleForTesting - static List getTagValues( - Map tags, List columns) { - List tagValues = new ArrayList(columns.size()); - // Record all the measures in a "Greedy" way. - // Every view aggregates every measure. This is similar to doing a GROUPBY view’s keys. - for (int i = 0; i < columns.size(); ++i) { - TagKey tagKey = columns.get(i); - if (!tags.containsKey(tagKey)) { - // replace not found key values by “unknown/not set”. - tagValues.add(UNKNOWN_TAG_VALUE); - } else { - tagValues.add(tags.get(tagKey)); - } - } - return tagValues; - } - - // Returns the milliseconds representation of a Duration. - static long toMillis(Duration duration) { - return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos() / NANOS_PER_MILLI; - } - - /** - * Create an empty {@link MutableAggregation} based on the given {@link Aggregation}. - * - * @param aggregation {@code Aggregation}. - * @return an empty {@code MutableAggregation}. - */ - @VisibleForTesting - static MutableAggregation createMutableAggregation(Aggregation aggregation) { - return aggregation.match( - CreateMutableSum.INSTANCE, - CreateMutableCount.INSTANCE, - CreateMutableMean.INSTANCE, - CreateMutableDistribution.INSTANCE, - Functions.throwIllegalArgumentException()); - } - - /** - * Create an {@link AggregationData} snapshot based on the given {@link MutableAggregation}. - * - * @param aggregation {@code MutableAggregation} - * @param measure {@code Measure} - * @return an {@code AggregationData} which is the snapshot of current summary statistics. - */ - @VisibleForTesting - static AggregationData createAggregationData(MutableAggregation aggregation, Measure measure) { - return aggregation.match( - new CreateSumData(measure), - CreateCountData.INSTANCE, - CreateMeanData.INSTANCE, - CreateDistributionData.INSTANCE); - } - - // Covert a mapping from TagValues to MutableAggregation, to a mapping from TagValues to - // AggregationData. - private static Map createAggregationMap( - Map tagValueAggregationMap, Measure measure) { - Map map = Maps.newHashMap(); - for (Entry entry : tagValueAggregationMap.entrySet()) { - map.put(entry.getKey(), createAggregationData(entry.getValue(), measure)); - } - return map; - } - - private static final class CumulativeMutableViewData extends MutableViewData { - - private Timestamp start; - private final Map, MutableAggregation> tagValueAggregationMap = - Maps.newHashMap(); - - private CumulativeMutableViewData(View view, Timestamp start) { - super(view); - this.start = start; - } - - @Override - void record(TagContext context, double value, Timestamp timestamp) { - List tagValues = getTagValues(getTagMap(context), super.view.getColumns()); - if (!tagValueAggregationMap.containsKey(tagValues)) { - tagValueAggregationMap.put( - tagValues, createMutableAggregation(super.view.getAggregation())); - } - tagValueAggregationMap.get(tagValues).add(value); - } - - @Override - ViewData toViewData(Timestamp now, StatsCollectionState state) { - if (state == StatsCollectionState.ENABLED) { - return ViewData.create( - super.view, - createAggregationMap(tagValueAggregationMap, super.view.getMeasure()), - CumulativeData.create(start, now)); - } else { - // If Stats state is DISABLED, return an empty ViewData. - return ViewData.create( - super.view, - Collections., AggregationData>emptyMap(), - CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)); - } - } - - @Override - void clearStats() { - tagValueAggregationMap.clear(); - } - - @Override - void resumeStatsCollection(Timestamp now) { - start = now; - } - } - - /* - * For each IntervalView, we always keep a queue of N + 1 buckets (by default N is 4). - * Each bucket has a duration which is interval duration / N. - * Ideally: - * 1. the buckets should always be up-to-date, - * 2. current time should always be within the latest bucket, currently recorded stats should fall - * into the latest bucket, - * 3. there are always N buckets before the current one, which holds the stats in the past - * interval duration. - * - * When getView() is called, we will extract and combine the stats from the current and past - * buckets (part of the stats from the oldest bucket could have expired). - * - * However, in reality, we couldn't track the status of buckets all the time (keep monitoring and - * updating the bucket queue will be expensive). When we call record() or getView(), some or all - * of the buckets might be outdated, and we will need to "pad" new buckets to the queue and remove - * outdated ones. After refreshing buckets, the bucket queue will able to maintain the three - * invariants in the ideal situation. - * - * For example: - * 1. We have an IntervalView which has a duration of 8 seconds, we register this view at 10s. - * 2. Initially there will be 5 buckets: [2.0, 4.0), [4.0, 6.0), ..., [10.0, 12.0). - * 3. If users don't call record() or getView(), bucket queue will remain as it is, and some - * buckets could expire. - * 4. Suppose record() is called at 15s, now we need to refresh the bucket queue. We need to add - * two new buckets [12.0, 14.0) and [14.0, 16.0), and remove two expired buckets [2.0, 4.0) - * and [4.0, 6.0) - * 5. Suppose record() is called again at 30s, all the current buckets should have expired. We add - * 5 new buckets [22.0, 24.0) ... [30.0, 32.0) and remove all the previous buckets. - * 6. Suppose users call getView() at 35s, again we need to add two new buckets and remove two - * expired one, so that bucket queue is up-to-date. Now we combine stats from all buckets and - * return the combined IntervalViewData. - */ - private static final class IntervalMutableViewData extends MutableViewData { - - // TODO(songya): allow customizable bucket size in the future. - private static final int N = 4; // IntervalView has N + 1 buckets - - private final LinkedList buckets = new LinkedList(); - private final Duration totalDuration; // Duration of the whole interval. - private final Duration bucketDuration; // Duration of a single bucket (totalDuration / N) - - private IntervalMutableViewData(View view, Timestamp start) { - super(view); - Duration totalDuration = ((Interval) view.getWindow()).getDuration(); - this.totalDuration = totalDuration; - this.bucketDuration = Duration.fromMillis(toMillis(totalDuration) / N); - - // When initializing. add N empty buckets prior to the start timestamp of this - // IntervalMutableViewData, so that the last bucket will be the current one in effect. - shiftBucketList(N + 1, start); - } - - @Override - void record(TagContext context, double value, Timestamp timestamp) { - List tagValues = getTagValues(getTagMap(context), super.view.getColumns()); - refreshBucketList(timestamp); - // It is always the last bucket that does the recording. - buckets.peekLast().record(tagValues, value); - } - - @Override - ViewData toViewData(Timestamp now, StatsCollectionState state) { - refreshBucketList(now); - if (state == StatsCollectionState.ENABLED) { - return ViewData.create( - super.view, combineBucketsAndGetAggregationMap(now), IntervalData.create(now)); - } else { - // If Stats state is DISABLED, return an empty ViewData. - return ViewData.create( - super.view, - Collections., AggregationData>emptyMap(), - IntervalData.create(ZERO_TIMESTAMP)); - } - } - - @Override - void clearStats() { - for (IntervalBucket bucket : buckets) { - bucket.clearStats(); - } - } - - @Override - void resumeStatsCollection(Timestamp now) { - // Refresh bucket list to be ready for stats recording, so that if record() is called right - // after stats state is turned back on, record() will be faster. - refreshBucketList(now); - } - - // Add new buckets and remove expired buckets by comparing the current timestamp with - // timestamp of the last bucket. - private void refreshBucketList(Timestamp now) { - if (buckets.size() != N + 1) { - throw new AssertionError("Bucket list must have exactly " + (N + 1) + " buckets."); - } - Timestamp startOfLastBucket = buckets.peekLast().getStart(); - // TODO(songya): decide what to do when time goes backwards - checkArgument( - now.compareTo(startOfLastBucket) >= 0, - "Current time must be within or after the last bucket."); - long elapsedTimeMillis = toMillis(now.subtractTimestamp(startOfLastBucket)); - long numOfPadBuckets = elapsedTimeMillis / toMillis(bucketDuration); - - shiftBucketList(numOfPadBuckets, now); - } - - // Add specified number of new buckets, and remove expired buckets - private void shiftBucketList(long numOfPadBuckets, Timestamp now) { - Timestamp startOfNewBucket; - - if (!buckets.isEmpty()) { - startOfNewBucket = buckets.peekLast().getStart().addDuration(bucketDuration); - } else { - // Initialize bucket list. Should only enter this block once. - startOfNewBucket = subtractDuration(now, totalDuration); - } - - if (numOfPadBuckets > N + 1) { - // All current buckets expired, need to add N + 1 new buckets. The start time of the latest - // bucket will be current time. - startOfNewBucket = subtractDuration(now, totalDuration); - numOfPadBuckets = N + 1; - } - - for (int i = 0; i < numOfPadBuckets; i++) { - buckets.add( - new IntervalBucket(startOfNewBucket, bucketDuration, super.view.getAggregation())); - startOfNewBucket = startOfNewBucket.addDuration(bucketDuration); - } - - // removed expired buckets - while (buckets.size() > N + 1) { - buckets.pollFirst(); - } - } - - // Combine stats within each bucket, aggregate stats by tag values, and return the mapping from - // tag values to aggregation data. - private Map, AggregationData> combineBucketsAndGetAggregationMap(Timestamp now) { - Multimap, MutableAggregation> multimap = HashMultimap.create(); - LinkedList shallowCopy = new LinkedList(buckets); - Aggregation aggregation = super.view.getAggregation(); - putBucketsIntoMultiMap(shallowCopy, multimap, aggregation, now); - Map, MutableAggregation> singleMap = - aggregateOnEachTagValueList(multimap, aggregation); - return createAggregationMap(singleMap, super.getView().getMeasure()); - } - - // Put stats within each bucket to a multimap. Each tag value list (map key) could have multiple - // mutable aggregations (map value) from different buckets. - private static void putBucketsIntoMultiMap( - LinkedList buckets, - Multimap, MutableAggregation> multimap, - Aggregation aggregation, - Timestamp now) { - // Put fractional stats of the head (oldest) bucket. - IntervalBucket head = buckets.peekFirst(); - IntervalBucket tail = buckets.peekLast(); - double fractionTail = tail.getFraction(now); - // TODO(songya): decide what to do when time goes backwards - checkArgument( - 0.0 <= fractionTail && fractionTail <= 1.0, - "Fraction " + fractionTail + " should be within [0.0, 1.0]."); - double fractionHead = 1.0 - fractionTail; - putFractionalMutableAggregationsToMultiMap( - head.getTagValueAggregationMap(), multimap, aggregation, fractionHead); - - // Put whole data of other buckets. - boolean shouldSkipFirst = true; - for (IntervalBucket bucket : buckets) { - if (shouldSkipFirst) { - shouldSkipFirst = false; - continue; // skip the first bucket - } - for (Entry, MutableAggregation> entry : - bucket.getTagValueAggregationMap().entrySet()) { - multimap.put(entry.getKey(), entry.getValue()); - } - } - } - - // Put stats within one bucket into multimap, multiplied by a given fraction. - private static void putFractionalMutableAggregationsToMultiMap( - Map mutableAggrMap, - Multimap multimap, - Aggregation aggregation, - double fraction) { - for (Entry entry : mutableAggrMap.entrySet()) { - // Initially empty MutableAggregations. - MutableAggregation fractionalMutableAgg = createMutableAggregation(aggregation); - fractionalMutableAgg.combine(entry.getValue(), fraction); - multimap.put(entry.getKey(), fractionalMutableAgg); - } - } - - // For each tag value list (key of AggregationMap), combine mutable aggregations into one - // mutable aggregation, thus convert the multimap into a single map. - private static Map aggregateOnEachTagValueList( - Multimap multimap, Aggregation aggregation) { - Map map = Maps.newHashMap(); - for (T tagValues : multimap.keySet()) { - // Initially empty MutableAggregations. - MutableAggregation combinedAggregation = createMutableAggregation(aggregation); - for (MutableAggregation mutableAggregation : multimap.get(tagValues)) { - combinedAggregation.combine(mutableAggregation, 1.0); - } - map.put(tagValues, combinedAggregation); - } - return map; - } - - // Subtract a Duration from a Timestamp, and return a new Timestamp. - private static Timestamp subtractDuration(Timestamp timestamp, Duration duration) { - return timestamp.addDuration(Duration.create(-duration.getSeconds(), -duration.getNanos())); - } - } - - // static inner Function classes - - private static final class CreateMutableSum implements Function { - @Override - public MutableAggregation apply(Sum arg) { - return MutableSum.create(); - } - - private static final CreateMutableSum INSTANCE = new CreateMutableSum(); - } - - private static final class CreateMutableCount implements Function { - @Override - public MutableAggregation apply(Count arg) { - return MutableCount.create(); - } - - private static final CreateMutableCount INSTANCE = new CreateMutableCount(); - } - - private static final class CreateMutableMean implements Function { - @Override - public MutableAggregation apply(Mean arg) { - return MutableMean.create(); - } - - private static final CreateMutableMean INSTANCE = new CreateMutableMean(); - } - - private static final class CreateMutableDistribution - implements Function { - @Override - public MutableAggregation apply(Distribution arg) { - return MutableDistribution.create(arg.getBucketBoundaries()); - } - - private static final CreateMutableDistribution INSTANCE = new CreateMutableDistribution(); - } - - private static final class CreateSumData implements Function { - - private final Measure measure; - - private CreateSumData(Measure measure) { - this.measure = measure; - } - - @Override - public AggregationData apply(final MutableSum arg) { - return measure.match( - Functions.returnConstant(SumDataDouble.create(arg.getSum())), - Functions.returnConstant(SumDataLong.create(Math.round(arg.getSum()))), - Functions.throwAssertionError()); - } - } - - private static final class CreateCountData implements Function { - @Override - public AggregationData apply(MutableCount arg) { - return CountData.create(arg.getCount()); - } - - private static final CreateCountData INSTANCE = new CreateCountData(); - } - - private static final class CreateMeanData implements Function { - @Override - public AggregationData apply(MutableMean arg) { - return MeanData.create(arg.getMean(), arg.getCount()); - } - - private static final CreateMeanData INSTANCE = new CreateMeanData(); - } - - private static final class CreateDistributionData - implements Function { - @Override - public AggregationData apply(MutableDistribution arg) { - List boxedBucketCounts = new ArrayList(); - for (long bucketCount : arg.getBucketCounts()) { - boxedBucketCounts.add(bucketCount); - } - return DistributionData.create( - arg.getMean(), - arg.getCount(), - arg.getMin(), - arg.getMax(), - arg.getSumOfSquaredDeviations(), - boxedBucketCounts); - } - - private static final CreateDistributionData INSTANCE = new CreateDistributionData(); - } - - private static final class CreateCumulative implements Function { - @Override - public MutableViewData apply(Cumulative arg) { - return new CumulativeMutableViewData(view, start); - } - - private final View view; - private final Timestamp start; - - private CreateCumulative(View view, Timestamp start) { - this.view = view; - this.start = start; - } - } - - private static final class CreateInterval implements Function { - @Override - public MutableViewData apply(Interval arg) { - return new IntervalMutableViewData(view, start); - } - - private final View view; - private final Timestamp start; - - private CreateInterval(View view, Timestamp start) { - this.view = view; - this.start = start; - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java b/core_impl/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java deleted file mode 100644 index 5079e27c..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import com.google.common.base.Preconditions; -import io.opencensus.common.Clock; -import io.opencensus.implcore.internal.EventQueue; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.StatsComponent; - -/** Base implementation of {@link StatsComponent}. */ -public class StatsComponentImplBase extends StatsComponent { - - // The StatsCollectionState shared between the StatsComponent, StatsRecorder and ViewManager. - private final CurrentStatsState state = new CurrentStatsState(); - - private final ViewManagerImpl viewManager; - private final StatsRecorderImpl statsRecorder; - - /** - * Creates a new {@code StatsComponentImplBase}. - * - * @param queue the queue implementation. - * @param clock the clock to use when recording stats. - */ - public StatsComponentImplBase(EventQueue queue, Clock clock) { - StatsManager statsManager = new StatsManager(queue, clock, state); - this.viewManager = new ViewManagerImpl(statsManager); - this.statsRecorder = new StatsRecorderImpl(statsManager); - } - - @Override - public ViewManagerImpl getViewManager() { - return viewManager; - } - - @Override - public StatsRecorderImpl getStatsRecorder() { - return statsRecorder; - } - - @Override - public StatsCollectionState getState() { - return state.get(); - } - - @Override - public void setState(StatsCollectionState newState) { - boolean stateChanged = state.set(Preconditions.checkNotNull(newState, "newState")); - if (stateChanged) { - if (newState == StatsCollectionState.DISABLED) { - viewManager.clearStats(); - } else { - viewManager.resumeStatsCollection(); - } - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/StatsManager.java b/core_impl/src/main/java/io/opencensus/implcore/stats/StatsManager.java deleted file mode 100644 index 63fcd587..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/StatsManager.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.opencensus.common.Clock; -import io.opencensus.implcore.internal.EventQueue; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.View; -import io.opencensus.stats.ViewData; -import io.opencensus.tags.TagContext; - -/** Object that stores all views and stats. */ -final class StatsManager { - - private final EventQueue queue; - - // clock used throughout the stats implementation - private final Clock clock; - - private final CurrentStatsState state; - private final MeasureToViewMap measureToViewMap = new MeasureToViewMap(); - - StatsManager(EventQueue queue, Clock clock, CurrentStatsState state) { - checkNotNull(queue, "EventQueue"); - checkNotNull(clock, "Clock"); - checkNotNull(state, "state"); - this.queue = queue; - this.clock = clock; - this.state = state; - } - - void registerView(View view) { - measureToViewMap.registerView(view, clock); - } - - ViewData getView(View.Name viewName) { - return measureToViewMap.getView(viewName, clock, state.getInternal()); - } - - void record(TagContext tags, MeasureMapInternal measurementValues) { - // TODO(songya): consider exposing No-op MeasureMap and use it when stats state is DISABLED, so - // that we don't need to create actual MeasureMapImpl. - if (state.getInternal() == StatsCollectionState.ENABLED) { - queue.enqueue(new StatsEvent(this, tags, measurementValues)); - } - } - - void clearStats() { - measureToViewMap.clearStats(); - } - - void resumeStatsCollection() { - measureToViewMap.resumeStatsCollection(clock.now()); - } - - // An EventQueue entry that records the stats from one call to StatsManager.record(...). - private static final class StatsEvent implements EventQueue.Entry { - private final TagContext tags; - private final MeasureMapInternal stats; - private final StatsManager statsManager; - - StatsEvent(StatsManager statsManager, TagContext tags, MeasureMapInternal stats) { - this.statsManager = statsManager; - this.tags = tags; - this.stats = stats; - } - - @Override - public void process() { - // Add Timestamp to value after it went through the DisruptorQueue. - statsManager.measureToViewMap.record(tags, stats, statsManager.clock.now()); - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java b/core_impl/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java deleted file mode 100644 index f9ebea41..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.opencensus.stats.StatsRecorder; - -/** Implementation of {@link StatsRecorder}. */ -public final class StatsRecorderImpl extends StatsRecorder { - private final StatsManager statsManager; - - StatsRecorderImpl(StatsManager statsManager) { - checkNotNull(statsManager, "StatsManager"); - this.statsManager = statsManager; - } - - @Override - public MeasureMapImpl newMeasureMap() { - return MeasureMapImpl.create(statsManager); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java b/core_impl/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java deleted file mode 100644 index eb716689..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import io.opencensus.stats.View; -import io.opencensus.stats.ViewData; -import io.opencensus.stats.ViewManager; - -/** Implementation of {@link ViewManager}. */ -public final class ViewManagerImpl extends ViewManager { - private final StatsManager statsManager; - - ViewManagerImpl(StatsManager statsManager) { - this.statsManager = statsManager; - } - - @Override - public void registerView(View view) { - statsManager.registerView(view); - } - - @Override - public ViewData getView(View.Name viewName) { - return statsManager.getView(viewName); - } - - void clearStats() { - statsManager.clearStats(); - } - - void resumeStatsCollection() { - statsManager.resumeStatsCollection(); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java b/core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java deleted file mode 100644 index 1a4ef81b..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import io.grpc.Context; -import io.opencensus.common.Scope; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.unsafe.ContextUtils; -import javax.annotation.Nullable; - -/** - * Utility methods for accessing the {@link TagContext} contained in the {@link io.grpc.Context}. - */ -final class CurrentTagContextUtils { - - private CurrentTagContextUtils() {} - - /** - * Returns the {@link TagContext} from the current context. - * - * @return the {@code TagContext} from the current context. - */ - @Nullable - static TagContext getCurrentTagContext() { - return ContextUtils.TAG_CONTEXT_KEY.get(); - } - - /** - * Enters the scope of code where the given {@link TagContext} is in the current context and - * returns an object that represents that scope. The scope is exited when the returned object is - * closed. - * - * @param tags the {@code TagContext} to be set to the current context. - * @return an object that defines a scope where the given {@code TagContext} is set to the current - * context. - */ - static Scope withTagContext(TagContext tags) { - return new WithTagContext(tags); - } - - private static final class WithTagContext implements Scope { - - private final Context orig; - - /** - * Constructs a new {@link WithTagContext}. - * - * @param tags the {@code TagContext} to be added to the current {@code Context}. - */ - private WithTagContext(TagContext tags) { - orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tags).attach(); - } - - @Override - public void close() { - Context.current().detach(orig); - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java b/core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java deleted file mode 100644 index ab60ffa1..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.opencensus.tags.TaggingState; -import io.opencensus.tags.TagsComponent; -import javax.annotation.concurrent.ThreadSafe; - -/** - * The current {@link TaggingState} for a {@link TagsComponent}. - * - *

This class allows different tagging classes to share the state in a thread-safe way. - */ -@ThreadSafe -public final class CurrentTaggingState { - private volatile TaggingState currentState = TaggingState.ENABLED; - - public TaggingState get() { - return currentState; - } - - void set(TaggingState state) { - currentState = checkNotNull(state, "state"); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java b/core_impl/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java deleted file mode 100644 index eae54c5d..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import io.opencensus.common.Scope; -import io.opencensus.implcore.internal.NoopScope; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagContextBuilder; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; - -/** {@link TagContextBuilder} that is used when tagging is disabled. */ -final class NoopTagContextBuilder extends TagContextBuilder { - static final NoopTagContextBuilder INSTANCE = new NoopTagContextBuilder(); - - private NoopTagContextBuilder() {} - - @Override - public TagContextBuilder put(TagKey key, TagValue value) { - return this; - } - - @Override - public TagContextBuilder remove(TagKey key) { - return this; - } - - @Override - public TagContext build() { - return TagContextImpl.EMPTY; - } - - @Override - public Scope buildScoped() { - return NoopScope.getInstance(); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java b/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java deleted file mode 100644 index 1f473454..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.opencensus.common.Scope; -import io.opencensus.tags.TagContextBuilder; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import java.util.HashMap; -import java.util.Map; - -final class TagContextBuilderImpl extends TagContextBuilder { - private final Map tags; - - TagContextBuilderImpl(Map tags) { - this.tags = new HashMap(tags); - } - - TagContextBuilderImpl() { - this.tags = new HashMap(); - } - - @Override - public TagContextBuilderImpl put(TagKey key, TagValue value) { - return setInternal(key, checkNotNull(value, "value")); - } - - private TagContextBuilderImpl setInternal(TagKey key, TagValue value) { - tags.put(checkNotNull(key), value); - return this; - } - - @Override - public TagContextBuilderImpl remove(TagKey key) { - tags.remove(key); - return this; - } - - @Override - public TagContextImpl build() { - return new TagContextImpl(tags); - } - - @Override - public Scope buildScoped() { - return CurrentTagContextUtils.withTagContext(build()); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java b/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java deleted file mode 100644 index 177ce639..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import javax.annotation.concurrent.Immutable; - -@Immutable -public final class TagContextImpl extends TagContext { - - public static final TagContextImpl EMPTY = - new TagContextImpl(Collections.emptyMap()); - - // The types of the TagKey and value must match for each entry. - private final Map tags; - - public TagContextImpl(Map tags) { - this.tags = Collections.unmodifiableMap(new HashMap(tags)); - } - - public Map getTags() { - return tags; - } - - @Override - protected Iterator getIterator() { - return new TagIterator(tags); - } - - @Override - public boolean equals(Object other) { - // Directly compare the tags when both objects are TagContextImpls, for efficiency. - if (other instanceof TagContextImpl) { - return getTags().equals(((TagContextImpl) other).getTags()); - } - return super.equals(other); - } - - private static final class TagIterator implements Iterator { - Iterator> iterator; - - TagIterator(Map tags) { - iterator = tags.entrySet().iterator(); - } - - @Override - public boolean hasNext() { - return iterator.hasNext(); - } - - @Override - public Tag next() { - final Entry next = iterator.next(); - return Tag.create(next.getKey(), next.getValue()); - } - - @Override - public void remove() { - throw new UnsupportedOperationException("TagIterator.remove()"); - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java b/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java deleted file mode 100644 index 5fbc5050..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import io.opencensus.tags.Tag; - -final class TagContextUtils { - private TagContextUtils() {} - - /** - * Add a {@code Tag} of any type to a builder. - * - * @param tag tag containing the key and value to set. - * @param builder the builder to update. - */ - static void addTagToBuilder(Tag tag, TagContextBuilderImpl builder) { - builder.put(tag.getKey(), tag.getValue()); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java b/core_impl/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java deleted file mode 100644 index 82c1d8cf..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import io.opencensus.common.Scope; -import io.opencensus.implcore.internal.NoopScope; -import io.opencensus.tags.InternalUtils; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagContextBuilder; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TaggingState; -import java.util.Iterator; - -public final class TaggerImpl extends Tagger { - // All methods in this class use TagContextImpl and TagContextBuilderImpl. For example, - // withTagContext(...) always puts a TagContextImpl into scope, even if the argument is another - // TagContext subclass. - - private final CurrentTaggingState state; - - TaggerImpl(CurrentTaggingState state) { - this.state = state; - } - - @Override - public TagContextImpl empty() { - return TagContextImpl.EMPTY; - } - - @Override - public TagContextImpl getCurrentTagContext() { - return state.get() == TaggingState.DISABLED - ? TagContextImpl.EMPTY - : toTagContextImpl(CurrentTagContextUtils.getCurrentTagContext()); - } - - @Override - public TagContextBuilder emptyBuilder() { - return state.get() == TaggingState.DISABLED - ? NoopTagContextBuilder.INSTANCE - : new TagContextBuilderImpl(); - } - - @Override - public TagContextBuilder currentBuilder() { - return state.get() == TaggingState.DISABLED - ? NoopTagContextBuilder.INSTANCE - : toBuilder(CurrentTagContextUtils.getCurrentTagContext()); - } - - @Override - public TagContextBuilder toBuilder(TagContext tags) { - return state.get() == TaggingState.DISABLED - ? NoopTagContextBuilder.INSTANCE - : toTagContextBuilderImpl(tags); - } - - @Override - public Scope withTagContext(TagContext tags) { - return state.get() == TaggingState.DISABLED - ? NoopScope.getInstance() - : CurrentTagContextUtils.withTagContext(toTagContextImpl(tags)); - } - - private static TagContextImpl toTagContextImpl(TagContext tags) { - if (tags instanceof TagContextImpl) { - return (TagContextImpl) tags; - } else { - Iterator i = InternalUtils.getTags(tags); - if (!i.hasNext()) { - return TagContextImpl.EMPTY; - } - TagContextBuilderImpl builder = new TagContextBuilderImpl(); - while (i.hasNext()) { - Tag tag = i.next(); - if (tag != null) { - TagContextUtils.addTagToBuilder(tag, builder); - } - } - return builder.build(); - } - } - - private static TagContextBuilderImpl toTagContextBuilderImpl(TagContext tags) { - // Copy the tags more efficiently in the expected case, when the TagContext is a TagContextImpl. - if (tags instanceof TagContextImpl) { - return new TagContextBuilderImpl(((TagContextImpl) tags).getTags()); - } else { - TagContextBuilderImpl builder = new TagContextBuilderImpl(); - for (Iterator i = InternalUtils.getTags(tags); i.hasNext(); ) { - Tag tag = i.next(); - if (tag != null) { - TagContextUtils.addTagToBuilder(tag, builder); - } - } - return builder; - } - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java b/core_impl/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java deleted file mode 100644 index 216afdc9..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TaggingState; -import io.opencensus.tags.TagsComponent; -import io.opencensus.tags.propagation.TagPropagationComponent; - -/** Base implementation of {@link TagsComponent}. */ -public class TagsComponentImplBase extends TagsComponent { - - // The TaggingState shared between the TagsComponent, Tagger, and TagPropagationComponent - private final CurrentTaggingState state = new CurrentTaggingState(); - - private final Tagger tagger = new TaggerImpl(state); - private final TagPropagationComponent tagPropagationComponent = - new TagPropagationComponentImpl(state); - - @Override - public Tagger getTagger() { - return tagger; - } - - @Override - public TagPropagationComponent getTagPropagationComponent() { - return tagPropagationComponent; - } - - @Override - public TaggingState getState() { - return state.get(); - } - - @Override - public void setState(TaggingState newState) { - state.set(checkNotNull(newState, "newState")); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java b/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java deleted file mode 100644 index d889a4b8..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; -import io.opencensus.implcore.internal.VarInt; -import io.opencensus.implcore.tags.TagContextImpl; -import io.opencensus.tags.InternalUtils; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.propagation.TagContextDeserializationException; -import java.nio.BufferUnderflowException; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -/** - * Methods for serializing and deserializing {@link TagContext}s. - * - *

The format defined in this class is shared across all implementations of OpenCensus. It allows - * tags to propagate across requests. - * - *

OpenCensus tag context encoding: - * - *

- */ -final class SerializationUtils { - private SerializationUtils() {} - - @VisibleForTesting static final int VERSION_ID = 0; - @VisibleForTesting static final int TAG_FIELD_ID = 0; - - // Serializes a TagContext to the on-the-wire format. - // Encoded tags are of the form: - static byte[] serializeBinary(TagContext tags) { - // Use a ByteArrayDataOutput to avoid needing to handle IOExceptions. - final ByteArrayDataOutput byteArrayDataOutput = ByteStreams.newDataOutput(); - byteArrayDataOutput.write(VERSION_ID); - for (Iterator i = InternalUtils.getTags(tags); i.hasNext(); ) { - Tag tag = i.next(); - encodeTag(tag, byteArrayDataOutput); - } - return byteArrayDataOutput.toByteArray(); - } - - // Deserializes input to TagContext based on the binary format standard. - // The encoded tags are of the form: - static TagContextImpl deserializeBinary(byte[] bytes) throws TagContextDeserializationException { - try { - if (bytes.length == 0) { - // Does not allow empty byte array. - throw new TagContextDeserializationException("Input byte[] can not be empty."); - } - - ByteBuffer buffer = ByteBuffer.wrap(bytes).asReadOnlyBuffer(); - int versionId = buffer.get(); - if (versionId != VERSION_ID) { - throw new TagContextDeserializationException( - "Wrong Version ID: " + versionId + ". Currently supported version is: " + VERSION_ID); - } - return new TagContextImpl(parseTags(buffer)); - } catch (BufferUnderflowException exn) { - throw new TagContextDeserializationException(exn.toString()); // byte array format error. - } - } - - private static Map parseTags(ByteBuffer buffer) - throws TagContextDeserializationException { - Map tags = new HashMap(); - int limit = buffer.limit(); - while (buffer.position() < limit) { - int type = buffer.get(); - if (type == TAG_FIELD_ID) { - TagKey key = createTagKey(decodeString(buffer)); - TagValue val = createTagValue(key, decodeString(buffer)); - tags.put(key, val); - } else { - // Stop parsing at the first unknown field ID, since there is no way to know its length. - // TODO(sebright): Consider storing the rest of the byte array in the TagContext. - return tags; - } - } - return tags; - } - - // TODO(sebright): Consider exposing a TagKey name validation method to avoid needing to catch an - // IllegalArgumentException here. - private static final TagKey createTagKey(String name) throws TagContextDeserializationException { - try { - return TagKey.create(name); - } catch (IllegalArgumentException e) { - throw new TagContextDeserializationException("Invalid tag key: " + name, e); - } - } - - // TODO(sebright): Consider exposing a TagValue validation method to avoid needing to catch - // an IllegalArgumentException here. - private static final TagValue createTagValue(TagKey key, String value) - throws TagContextDeserializationException { - try { - return TagValue.create(value); - } catch (IllegalArgumentException e) { - throw new TagContextDeserializationException( - "Invalid tag value for key " + key + ": " + value, e); - } - } - - private static final void encodeTag(Tag tag, ByteArrayDataOutput byteArrayDataOutput) { - byteArrayDataOutput.write(TAG_FIELD_ID); - encodeString(tag.getKey().getName(), byteArrayDataOutput); - encodeString(tag.getValue().asString(), byteArrayDataOutput); - } - - private static final void encodeString(String input, ByteArrayDataOutput byteArrayDataOutput) { - putVarInt(input.length(), byteArrayDataOutput); - byteArrayDataOutput.write(input.getBytes(Charsets.UTF_8)); - } - - private static final void putVarInt(int input, ByteArrayDataOutput byteArrayDataOutput) { - byte[] output = new byte[VarInt.varIntSize(input)]; - VarInt.putVarInt(input, output, 0); - byteArrayDataOutput.write(output); - } - - private static final String decodeString(ByteBuffer buffer) { - int length = VarInt.getVarInt(buffer); - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < length; i++) { - builder.append((char) buffer.get()); - } - return builder.toString(); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java b/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java deleted file mode 100644 index eea24a33..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import io.opencensus.implcore.tags.CurrentTaggingState; -import io.opencensus.implcore.tags.TagContextImpl; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TaggingState; -import io.opencensus.tags.propagation.TagContextBinarySerializer; -import io.opencensus.tags.propagation.TagContextDeserializationException; - -final class TagContextBinarySerializerImpl extends TagContextBinarySerializer { - private static final byte[] EMPTY_BYTE_ARRAY = {}; - - private final CurrentTaggingState state; - - TagContextBinarySerializerImpl(CurrentTaggingState state) { - this.state = state; - } - - @Override - public byte[] toByteArray(TagContext tags) { - return state.get() == TaggingState.DISABLED - ? EMPTY_BYTE_ARRAY - : SerializationUtils.serializeBinary(tags); - } - - @Override - public TagContext fromByteArray(byte[] bytes) throws TagContextDeserializationException { - return state.get() == TaggingState.DISABLED - ? TagContextImpl.EMPTY - : SerializationUtils.deserializeBinary(bytes); - } -} diff --git a/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java b/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java deleted file mode 100644 index 5def0758..00000000 --- a/core_impl/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import io.opencensus.implcore.tags.CurrentTaggingState; -import io.opencensus.tags.propagation.TagContextBinarySerializer; -import io.opencensus.tags.propagation.TagPropagationComponent; - -public final class TagPropagationComponentImpl extends TagPropagationComponent { - private final TagContextBinarySerializer tagContextBinarySerializer; - - public TagPropagationComponentImpl(CurrentTaggingState state) { - tagContextBinarySerializer = new TagContextBinarySerializerImpl(state); - } - - @Override - public TagContextBinarySerializer getBinarySerializer() { - return tagContextBinarySerializer; - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java deleted file mode 100644 index 2fd1ddc7..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.stats.StatsCollectionState; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link CurrentStatsState}. */ -@RunWith(JUnit4.class) -public final class CurrentStatsStateTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - @Test - public void defaultState() { - assertThat(new CurrentStatsState().get()).isEqualTo(StatsCollectionState.ENABLED); - } - - @Test - public void setState() { - CurrentStatsState state = new CurrentStatsState(); - assertThat(state.set(StatsCollectionState.DISABLED)).isTrue(); - assertThat(state.getInternal()).isEqualTo(StatsCollectionState.DISABLED); - assertThat(state.set(StatsCollectionState.ENABLED)).isTrue(); - assertThat(state.getInternal()).isEqualTo(StatsCollectionState.ENABLED); - assertThat(state.set(StatsCollectionState.ENABLED)).isFalse(); - } - - @Test - public void preventNull() { - CurrentStatsState state = new CurrentStatsState(); - thrown.expect(NullPointerException.class); - thrown.expectMessage("state"); - state.set(null); - } - - @Test - public void preventSettingStateAfterReadingState() { - CurrentStatsState state = new CurrentStatsState(); - state.get(); - thrown.expect(IllegalStateException.class); - thrown.expectMessage("State was already read, cannot set state."); - state.set(StatsCollectionState.DISABLED); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java deleted file mode 100644 index 10bce262..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.common.Duration; -import io.opencensus.common.Timestamp; -import io.opencensus.implcore.stats.MutableAggregation.MutableMean; -import io.opencensus.stats.Aggregation.Mean; -import io.opencensus.tags.TagValue; -import java.util.Arrays; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link IntervalBucket}. */ -@RunWith(JUnit4.class) -public class IntervalBucketTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private static final double TOLERANCE = 1e-6; - private static final Duration MINUTE = Duration.create(60, 0); - private static final Duration NEGATIVE_TEN_SEC = Duration.create(-10, 0); - private static final Timestamp START = Timestamp.create(60, 0); - private static final Mean MEAN = Mean.create(); - - @Test - public void preventNullStartTime() { - thrown.expect(NullPointerException.class); - new IntervalBucket(null, MINUTE, MEAN); - } - - @Test - public void preventNullDuration() { - thrown.expect(NullPointerException.class); - new IntervalBucket(START, null, MEAN); - } - - @Test - public void preventNegativeDuration() { - thrown.expect(IllegalArgumentException.class); - new IntervalBucket(START, NEGATIVE_TEN_SEC, MEAN); - } - - @Test - public void preventNullAggregationList() { - thrown.expect(NullPointerException.class); - new IntervalBucket(START, MINUTE, null); - } - - @Test - public void testGetTagValueAggregationMap_empty() { - assertThat(new IntervalBucket(START, MINUTE, MEAN).getTagValueAggregationMap()).isEmpty(); - } - - @Test - public void testGetStart() { - assertThat(new IntervalBucket(START, MINUTE, MEAN).getStart()).isEqualTo(START); - } - - @Test - public void testRecord() { - IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN); - List tagValues1 = Arrays.asList(TagValue.create("VALUE1")); - List tagValues2 = Arrays.asList(TagValue.create("VALUE2")); - bucket.record(tagValues1, 5.0); - bucket.record(tagValues1, 15.0); - bucket.record(tagValues2, 10.0); - assertThat(bucket.getTagValueAggregationMap().keySet()).containsExactly(tagValues1, tagValues2); - MutableMean mutableMean1 = (MutableMean) bucket.getTagValueAggregationMap().get(tagValues1); - MutableMean mutableMean2 = (MutableMean) bucket.getTagValueAggregationMap().get(tagValues2); - assertThat(mutableMean1.getSum()).isWithin(TOLERANCE).of(20); - assertThat(mutableMean2.getSum()).isWithin(TOLERANCE).of(10); - assertThat(mutableMean1.getCount()).isEqualTo(2); - assertThat(mutableMean2.getCount()).isEqualTo(1); - } - - @Test - public void testGetFraction() { - Timestamp thirtySecondsAfterStart = Timestamp.create(90, 0); - assertThat(new IntervalBucket(START, MINUTE, MEAN).getFraction(thirtySecondsAfterStart)) - .isWithin(TOLERANCE) - .of(0.5); - } - - @Test - public void preventCallingGetFractionOnPastBuckets() { - IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN); - Timestamp twoMinutesAfterStart = Timestamp.create(180, 0); - thrown.expect(IllegalArgumentException.class); - bucket.getFraction(twoMinutesAfterStart); - } - - @Test - public void preventCallingGetFractionOnFutureBuckets() { - IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN); - Timestamp thirtySecondsBeforeStart = Timestamp.create(30, 0); - thrown.expect(IllegalArgumentException.class); - bucket.getFraction(thirtySecondsBeforeStart); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java deleted file mode 100644 index c57baa0b..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.Lists; -import io.opencensus.stats.Measure; -import io.opencensus.stats.Measure.MeasureDouble; -import io.opencensus.stats.Measure.MeasureLong; -import io.opencensus.stats.Measurement; -import io.opencensus.stats.Measurement.MeasurementDouble; -import io.opencensus.stats.Measurement.MeasurementLong; -import java.util.ArrayList; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link MeasureMapInternal}. */ -@RunWith(JUnit4.class) -public class MeasureMapInternalTest { - - @Test - public void testPutDouble() { - MeasureMapInternal metrics = MeasureMapInternal.builder().put(M1, 44.4).build(); - assertContains(metrics, MeasurementDouble.create(M1, 44.4)); - } - - @Test - public void testPutLong() { - MeasureMapInternal metrics = MeasureMapInternal.builder().put(M3, 9999L).put(M4, 8888L).build(); - assertContains(metrics, MeasurementLong.create(M3, 9999L), MeasurementLong.create(M4, 8888L)); - } - - @Test - public void testCombination() { - MeasureMapInternal metrics = - MeasureMapInternal.builder() - .put(M1, 44.4) - .put(M2, 66.6) - .put(M3, 9999L) - .put(M4, 8888L) - .build(); - assertContains( - metrics, - MeasurementDouble.create(M1, 44.4), - MeasurementDouble.create(M2, 66.6), - MeasurementLong.create(M3, 9999L), - MeasurementLong.create(M4, 8888L)); - } - - @Test - public void testBuilderEmpty() { - MeasureMapInternal metrics = MeasureMapInternal.builder().build(); - assertContains(metrics); - } - - @Test - public void testBuilder() { - ArrayList expected = new ArrayList(10); - MeasureMapInternal.Builder builder = MeasureMapInternal.builder(); - for (int i = 1; i <= 10; i++) { - expected.add(MeasurementDouble.create(makeSimpleMeasureDouble("m" + i), i * 11.1)); - builder.put(makeSimpleMeasureDouble("m" + i), i * 11.1); - assertContains(builder.build(), expected.toArray(new Measurement[i])); - } - } - - @Test - public void testDuplicateMeasureDoubles() { - assertContains( - MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).build(), - MeasurementDouble.create(M1, 2.0)); - assertContains( - MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).put(M1, 3.0).build(), - MeasurementDouble.create(M1, 3.0)); - assertContains( - MeasureMapInternal.builder().put(M1, 1.0).put(M2, 2.0).put(M1, 3.0).build(), - MeasurementDouble.create(M1, 3.0), - MeasurementDouble.create(M2, 2.0)); - assertContains( - MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).put(M2, 2.0).build(), - MeasurementDouble.create(M1, 2.0), - MeasurementDouble.create(M2, 2.0)); - } - - @Test - public void testDuplicateMeasureLongs() { - assertContains( - MeasureMapInternal.builder().put(M3, 100L).put(M3, 100L).build(), - MeasurementLong.create(M3, 100L)); - assertContains( - MeasureMapInternal.builder().put(M3, 100L).put(M3, 200L).put(M3, 300L).build(), - MeasurementLong.create(M3, 300L)); - assertContains( - MeasureMapInternal.builder().put(M3, 100L).put(M4, 200L).put(M3, 300L).build(), - MeasurementLong.create(M3, 300L), - MeasurementLong.create(M4, 200L)); - assertContains( - MeasureMapInternal.builder().put(M3, 100L).put(M3, 200L).put(M4, 200L).build(), - MeasurementLong.create(M3, 200L), - MeasurementLong.create(M4, 200L)); - } - - @Test - public void testDuplicateMeasures() { - assertContains( - MeasureMapInternal.builder().put(M3, 100L).put(M1, 1.0).put(M3, 300L).build(), - MeasurementLong.create(M3, 300L), - MeasurementDouble.create(M1, 1.0)); - assertContains( - MeasureMapInternal.builder().put(M2, 2.0).put(M3, 100L).put(M2, 3.0).build(), - MeasurementDouble.create(M2, 3.0), - MeasurementLong.create(M3, 100L)); - } - - private static final MeasureDouble M1 = makeSimpleMeasureDouble("m1"); - private static final MeasureDouble M2 = makeSimpleMeasureDouble("m2"); - private static final MeasureLong M3 = makeSimpleMeasureLong("m3"); - private static final MeasureLong M4 = makeSimpleMeasureLong("m4"); - - private static MeasureDouble makeSimpleMeasureDouble(String measure) { - return Measure.MeasureDouble.create(measure, measure + " description", "1"); - } - - private static MeasureLong makeSimpleMeasureLong(String measure) { - return Measure.MeasureLong.create(measure, measure + " description", "1"); - } - - private static void assertContains(MeasureMapInternal metrics, Measurement... measurements) { - assertThat(Lists.newArrayList(metrics.iterator())).containsExactly((Object[]) measurements); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java deleted file mode 100644 index 0a198b0c..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.common.Timestamp; -import io.opencensus.stats.Aggregation.Mean; -import io.opencensus.stats.Measure; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.View; -import io.opencensus.stats.View.AggregationWindow.Cumulative; -import io.opencensus.stats.View.Name; -import io.opencensus.stats.ViewData; -import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; -import io.opencensus.tags.TagKey; -import io.opencensus.testing.common.TestClock; -import java.util.Arrays; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link MeasureToViewMap}. */ -@RunWith(JUnit4.class) -public class MeasureToViewMapTest { - - private static final Measure MEASURE = - Measure.MeasureDouble.create("my measurement", "measurement description", "By"); - - private static final Name VIEW_NAME = View.Name.create("my view"); - - private static final Cumulative CUMULATIVE = Cumulative.create(); - - private static final View VIEW = - View.create( - VIEW_NAME, - "view description", - MEASURE, - Mean.create(), - Arrays.asList(TagKey.create("my key")), - CUMULATIVE); - - @Test - public void testRegisterAndGetView() { - MeasureToViewMap measureToViewMap = new MeasureToViewMap(); - TestClock clock = TestClock.create(Timestamp.create(10, 20)); - measureToViewMap.registerView(VIEW, clock); - clock.setTime(Timestamp.create(30, 40)); - ViewData viewData = measureToViewMap.getView(VIEW_NAME, clock, StatsCollectionState.ENABLED); - assertThat(viewData.getView()).isEqualTo(VIEW); - assertThat(viewData.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(10, 20), Timestamp.create(30, 40))); - assertThat(viewData.getAggregationMap()).isEmpty(); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java deleted file mode 100644 index 054a5b44..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.common.Function; -import io.opencensus.implcore.stats.MutableAggregation.MutableCount; -import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution; -import io.opencensus.implcore.stats.MutableAggregation.MutableMean; -import io.opencensus.implcore.stats.MutableAggregation.MutableSum; -import io.opencensus.stats.BucketBoundaries; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link io.opencensus.implcore.stats.MutableAggregation}. */ -@RunWith(JUnit4.class) -public class MutableAggregationTest { - - @Rule public ExpectedException thrown = ExpectedException.none(); - - private static final double TOLERANCE = 1e-6; - private static final BucketBoundaries BUCKET_BOUNDARIES = - BucketBoundaries.create(Arrays.asList(-10.0, 0.0, 10.0)); - - @Test - public void testCreateEmpty() { - assertThat(MutableSum.create().getSum()).isWithin(TOLERANCE).of(0); - assertThat(MutableCount.create().getCount()).isEqualTo(0); - assertThat(MutableMean.create().getMean()).isWithin(TOLERANCE).of(0); - - BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(0.1, 2.2, 33.3)); - MutableDistribution mutableDistribution = MutableDistribution.create(bucketBoundaries); - assertThat(mutableDistribution.getMean()).isWithin(TOLERANCE).of(0); - assertThat(mutableDistribution.getCount()).isEqualTo(0); - assertThat(mutableDistribution.getMin()).isPositiveInfinity(); - assertThat(mutableDistribution.getMax()).isNegativeInfinity(); - assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(TOLERANCE).of(0); - assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]); - } - - @Test - public void testNullBucketBoundaries() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("bucketBoundaries should not be null."); - MutableDistribution.create(null); - } - - @Test - public void testNoBoundaries() { - List buckets = Arrays.asList(); - MutableDistribution noBoundaries = MutableDistribution.create(BucketBoundaries.create(buckets)); - assertThat(noBoundaries.getBucketCounts().length).isEqualTo(1); - assertThat(noBoundaries.getBucketCounts()[0]).isEqualTo(0); - } - - @Test - public void testAdd() { - List aggregations = - Arrays.asList( - MutableSum.create(), - MutableCount.create(), - MutableMean.create(), - MutableDistribution.create(BUCKET_BOUNDARIES)); - - List values = Arrays.asList(-1.0, 1.0, -5.0, 20.0, 5.0); - - for (double value : values) { - for (MutableAggregation aggregation : aggregations) { - aggregation.add(value); - } - } - - for (MutableAggregation aggregation : aggregations) { - aggregation.match( - new Function() { - @Override - public Void apply(MutableSum arg) { - assertThat(arg.getSum()).isWithin(TOLERANCE).of(20.0); - return null; - } - }, - new Function() { - @Override - public Void apply(MutableCount arg) { - assertThat(arg.getCount()).isEqualTo(5); - return null; - } - }, - new Function() { - @Override - public Void apply(MutableMean arg) { - assertThat(arg.getMean()).isWithin(TOLERANCE).of(4.0); - return null; - } - }, - new Function() { - @Override - public Void apply(MutableDistribution arg) { - assertThat(arg.getBucketCounts()).isEqualTo(new long[] {0, 2, 2, 1}); - return null; - } - }); - } - } - - @Test - public void testMatch() { - List aggregations = - Arrays.asList( - MutableSum.create(), - MutableCount.create(), - MutableMean.create(), - MutableDistribution.create(BUCKET_BOUNDARIES)); - - List actual = new ArrayList(); - for (MutableAggregation aggregation : aggregations) { - actual.add( - aggregation.match( - new Function() { - @Override - public String apply(MutableSum arg) { - return "SUM"; - } - }, - new Function() { - @Override - public String apply(MutableCount arg) { - return "COUNT"; - } - }, - new Function() { - @Override - public String apply(MutableMean arg) { - return "MEAN"; - } - }, - new Function() { - @Override - public String apply(MutableDistribution arg) { - return "DISTRIBUTION"; - } - })); - } - - assertThat(actual).isEqualTo(Arrays.asList("SUM", "COUNT", "MEAN", "DISTRIBUTION")); - } - - @Test - public void testCombine_SumCountMean() { - // combine() for Mutable Sum, Count and Mean will pick up fractional stats - List aggregations1 = - Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create()); - List aggregations2 = - Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create()); - - for (double val : Arrays.asList(-1.0, -5.0)) { - for (MutableAggregation aggregation : aggregations1) { - aggregation.add(val); - } - } - for (double val : Arrays.asList(10.0, 50.0)) { - for (MutableAggregation aggregation : aggregations2) { - aggregation.add(val); - } - } - - List combined = - Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create()); - double fraction1 = 1.0; - double fraction2 = 0.6; - for (int i = 0; i < combined.size(); i++) { - combined.get(i).combine(aggregations1.get(i), fraction1); - combined.get(i).combine(aggregations2.get(i), fraction2); - } - - assertThat(((MutableSum) combined.get(0)).getSum()).isWithin(TOLERANCE).of(30); - assertThat(((MutableCount) combined.get(1)).getCount()).isEqualTo(3); - assertThat(((MutableMean) combined.get(2)).getMean()).isWithin(TOLERANCE).of(10); - } - - @Test - public void testCombine_Distribution() { - // combine() for Mutable Distribution will ignore fractional stats - MutableDistribution distribution1 = MutableDistribution.create(BUCKET_BOUNDARIES); - MutableDistribution distribution2 = MutableDistribution.create(BUCKET_BOUNDARIES); - MutableDistribution distribution3 = MutableDistribution.create(BUCKET_BOUNDARIES); - - for (double val : Arrays.asList(5.0, -5.0)) { - distribution1.add(val); - } - for (double val : Arrays.asList(10.0, 20.0)) { - distribution2.add(val); - } - for (double val : Arrays.asList(-10.0, 15.0, -15.0, -20.0)) { - distribution3.add(val); - } - - MutableDistribution combined = MutableDistribution.create(BUCKET_BOUNDARIES); - combined.combine(distribution1, 1.0); // distribution1 will be combined - combined.combine(distribution2, 0.6); // distribution2 will be ignored - verifyMutableDistribution(combined, 0, 2, -5, 5, 50.0, new long[] {0, 1, 1, 0}, TOLERANCE); - - combined.combine(distribution2, 1.0); // distribution2 will be combined - verifyMutableDistribution(combined, 7.5, 4, -5, 20, 325.0, new long[] {0, 1, 1, 2}, TOLERANCE); - - combined.combine(distribution3, 1.0); // distribution3 will be combined - verifyMutableDistribution(combined, 0, 8, -20, 20, 1500.0, new long[] {2, 2, 1, 3}, TOLERANCE); - } - - private static void verifyMutableDistribution( - MutableDistribution mutableDistribution, - double mean, - long count, - double min, - double max, - double sumOfSquaredDeviations, - long[] bucketCounts, - double tolerance) { - assertThat(mutableDistribution.getMean()).isWithin(tolerance).of(mean); - assertThat(mutableDistribution.getCount()).isEqualTo(count); - assertThat(mutableDistribution.getMin()).isWithin(tolerance).of(min); - assertThat(mutableDistribution.getMax()).isWithin(tolerance).of(max); - assertThat(mutableDistribution.getSumOfSquaredDeviations()) - .isWithin(tolerance) - .of(sumOfSquaredDeviations); - assertThat(mutableDistribution.getBucketCounts()).isEqualTo(bucketCounts); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java deleted file mode 100644 index b4b4c85b..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.stats.MutableViewData.toMillis; - -import com.google.common.collect.ImmutableMap; -import io.opencensus.common.Duration; -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.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.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.MeanData; -import io.opencensus.stats.AggregationData.SumDataDouble; -import io.opencensus.stats.AggregationData.SumDataLong; -import io.opencensus.stats.BucketBoundaries; -import io.opencensus.stats.Measure.MeasureDouble; -import io.opencensus.stats.Measure.MeasureLong; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link MutableViewData}. */ -@RunWith(JUnit4.class) -public class MutableViewDataTest { - - private static final double EPSILON = 1e-7; - - private static final TagKey ORIGINATOR = TagKey.create("originator"); - private static final TagKey CALLER = TagKey.create("caller"); - private static final TagKey METHOD = TagKey.create("method"); - private static final TagValue CALLER_V = TagValue.create("some caller"); - private static final TagValue METHOD_V = TagValue.create("some method"); - private static final MeasureDouble MEASURE_DOUBLE = - MeasureDouble.create("measure1", "description", "1"); - private static final MeasureLong MEASURE_LONG = - MeasureLong.create("measure2", "description", "1"); - - @Test - public void testConstants() { - assertThat(MutableViewData.UNKNOWN_TAG_VALUE).isNull(); - assertThat(MutableViewData.ZERO_TIMESTAMP).isEqualTo(Timestamp.create(0, 0)); - } - - @Test - public void testGetTagValues() { - List columns = Arrays.asList(CALLER, METHOD, ORIGINATOR); - Map tags = ImmutableMap.of(CALLER, CALLER_V, METHOD, METHOD_V); - - assertThat(MutableViewData.getTagValues(tags, columns)) - .containsExactly(CALLER_V, METHOD_V, MutableViewData.UNKNOWN_TAG_VALUE) - .inOrder(); - } - - @Test - public void createMutableAggregation() { - BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0)); - - assertThat(((MutableSum) MutableViewData.createMutableAggregation(Sum.create())).getSum()) - .isWithin(EPSILON) - .of(0.0); - assertThat(((MutableCount) MutableViewData.createMutableAggregation(Count.create())).getCount()) - .isEqualTo(0L); - assertThat(((MutableMean) MutableViewData.createMutableAggregation(Mean.create())).getMean()) - .isWithin(EPSILON) - .of(0D); - - MutableDistribution mutableDistribution = - (MutableDistribution) - MutableViewData.createMutableAggregation(Distribution.create(bucketBoundaries)); - assertThat(mutableDistribution.getMin()).isPositiveInfinity(); - assertThat(mutableDistribution.getMax()).isNegativeInfinity(); - assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(EPSILON).of(0); - assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]); - } - - @Test - public void createAggregationData() { - BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0)); - List mutableAggregations = - Arrays.asList( - MutableCount.create(), - MutableMean.create(), - MutableDistribution.create(bucketBoundaries)); - List aggregates = new ArrayList(); - - 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)); - } - - assertThat(aggregates) - .containsExactly( - SumDataDouble.create(0), - SumDataLong.create(0), - CountData.create(0), - MeanData.create(0, 0), - DistributionData.create( - 0, - 0, - Double.POSITIVE_INFINITY, - Double.NEGATIVE_INFINITY, - 0, - Arrays.asList(new Long[] {0L, 0L, 0L, 0L}))) - .inOrder(); - } - - @Test - public void testDurationToMillis() { - assertThat(toMillis(Duration.create(0, 0))).isEqualTo(0); - assertThat(toMillis(Duration.create(0, 987000000))).isEqualTo(987); - assertThat(toMillis(Duration.create(3, 456000000))).isEqualTo(3456); - assertThat(toMillis(Duration.create(0, -1000000))).isEqualTo(-1); - assertThat(toMillis(Duration.create(-1, 0))).isEqualTo(-1000); - assertThat(toMillis(Duration.create(-3, -456000000))).isEqualTo(-3456); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java deleted file mode 100644 index 49131d8a..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.implcore.internal.SimpleEventQueue; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.StatsComponent; -import io.opencensus.testing.common.TestClock; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link StatsComponentImplBase}. */ -@RunWith(JUnit4.class) -public final class StatsComponentImplBaseTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private final StatsComponent statsComponent = - new StatsComponentImplBase(new SimpleEventQueue(), TestClock.create()); - - @Test - public void defaultState() { - assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.ENABLED); - } - - @Test - public void setState_Disabled() { - statsComponent.setState(StatsCollectionState.DISABLED); - assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.DISABLED); - } - - @Test - public void setState_Enabled() { - statsComponent.setState(StatsCollectionState.DISABLED); - statsComponent.setState(StatsCollectionState.ENABLED); - assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.ENABLED); - } - - @Test - public void setState_DisallowsNull() { - thrown.expect(NullPointerException.class); - thrown.expectMessage("newState"); - statsComponent.setState(null); - } - - @Test - public void preventSettingStateAfterGettingState() { - statsComponent.setState(StatsCollectionState.DISABLED); - statsComponent.getState(); - thrown.expect(IllegalStateException.class); - thrown.expectMessage("State was already read, cannot set state."); - statsComponent.setState(StatsCollectionState.ENABLED); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java deleted file mode 100644 index b0533d0d..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.stats.MutableViewData.ZERO_TIMESTAMP; -import static io.opencensus.implcore.stats.StatsTestUtil.createEmptyViewData; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import io.grpc.Context; -import io.opencensus.implcore.internal.SimpleEventQueue; -import io.opencensus.stats.Aggregation.Sum; -import io.opencensus.stats.Measure.MeasureDouble; -import io.opencensus.stats.MeasureMap; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.StatsComponent; -import io.opencensus.stats.StatsRecorder; -import io.opencensus.stats.View; -import io.opencensus.stats.View.AggregationWindow.Cumulative; -import io.opencensus.stats.ViewData; -import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; -import io.opencensus.stats.ViewManager; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.unsafe.ContextUtils; -import io.opencensus.testing.common.TestClock; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link StatsRecorderImpl}. */ -@RunWith(JUnit4.class) -public final class StatsRecorderImplTest { - private static final TagKey KEY = TagKey.create("KEY"); - private static final TagValue VALUE = TagValue.create("VALUE"); - private static final TagValue VALUE_2 = TagValue.create("VALUE_2"); - private static final MeasureDouble MEASURE_DOUBLE = - MeasureDouble.create("my measurement", "description", "us"); - private static final View.Name VIEW_NAME = View.Name.create("my view"); - - private final StatsComponent statsComponent = - new StatsComponentImplBase(new SimpleEventQueue(), TestClock.create()); - - private final ViewManager viewManager = statsComponent.getViewManager(); - private final StatsRecorder statsRecorder = statsComponent.getStatsRecorder(); - - @Test - public void record_CurrentContextNotSet() { - View view = - View.create( - VIEW_NAME, - "description", - MEASURE_DOUBLE, - Sum.create(), - Arrays.asList(KEY), - Cumulative.create()); - viewManager.registerView(view); - statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0).record(); - ViewData viewData = viewManager.getView(VIEW_NAME); - - // record() should have used the default TagContext, so the tag value should be null. - assertThat(viewData.getAggregationMap().keySet()) - .containsExactly(Arrays.asList((TagValue) null)); - } - - @Test - public void record_CurrentContextSet() { - View view = - View.create( - VIEW_NAME, - "description", - MEASURE_DOUBLE, - Sum.create(), - Arrays.asList(KEY), - Cumulative.create()); - viewManager.registerView(view); - Context orig = - Context.current() - .withValue(ContextUtils.TAG_CONTEXT_KEY, new SimpleTagContext(Tag.create(KEY, VALUE))) - .attach(); - try { - statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0).record(); - } finally { - Context.current().detach(orig); - } - ViewData viewData = viewManager.getView(VIEW_NAME); - - // record() should have used the given TagContext. - assertThat(viewData.getAggregationMap().keySet()).containsExactly(Arrays.asList(VALUE)); - } - - @Test - public void recordTwice() { - View view = - View.create( - VIEW_NAME, - "description", - MEASURE_DOUBLE, - Sum.create(), - Arrays.asList(KEY), - Cumulative.create()); - viewManager.registerView(view); - MeasureMap statsRecord = statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0); - statsRecord.record(new SimpleTagContext(Tag.create(KEY, VALUE))); - statsRecord.record(new SimpleTagContext(Tag.create(KEY, VALUE_2))); - ViewData viewData = viewManager.getView(VIEW_NAME); - - // There should be two entries. - StatsTestUtil.assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 1.0), - Arrays.asList(VALUE_2), - StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 1.0)), - 1e-6); - } - - @Test - public void record_StatsDisabled() { - View view = - View.create( - VIEW_NAME, - "description", - MEASURE_DOUBLE, - Sum.create(), - Arrays.asList(KEY), - Cumulative.create()); - - viewManager.registerView(view); - statsComponent.setState(StatsCollectionState.DISABLED); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.0) - .record(new SimpleTagContext(Tag.create(KEY, VALUE))); - assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view)); - } - - @Test - public void record_StatsReenabled() { - View view = - View.create( - VIEW_NAME, - "description", - MEASURE_DOUBLE, - Sum.create(), - Arrays.asList(KEY), - Cumulative.create()); - viewManager.registerView(view); - - statsComponent.setState(StatsCollectionState.DISABLED); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.0) - .record(new SimpleTagContext(Tag.create(KEY, VALUE))); - assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view)); - - statsComponent.setState(StatsCollectionState.ENABLED); - assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); - assertThat(viewManager.getView(VIEW_NAME).getWindowData()) - .isNotEqualTo(CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 4.0) - .record(new SimpleTagContext(Tag.create(KEY, VALUE))); - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 4.0)), - 1e-6); - } - - private static final class SimpleTagContext extends TagContext { - private final List tags; - - SimpleTagContext(Tag... tags) { - this.tags = Collections.unmodifiableList(Lists.newArrayList(tags)); - } - - @Override - protected Iterator getIterator() { - return tags.iterator(); - } - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java b/core_impl/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java deleted file mode 100644 index 3a714af4..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.stats.MutableViewData.ZERO_TIMESTAMP; - -import com.google.common.collect.Iterables; -import io.opencensus.common.Function; -import io.opencensus.common.Functions; -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.MeanData; -import io.opencensus.stats.AggregationData.SumDataDouble; -import io.opencensus.stats.AggregationData.SumDataLong; -import io.opencensus.stats.Measure; -import io.opencensus.stats.View; -import io.opencensus.stats.ViewData; -import io.opencensus.stats.ViewData.AggregationWindowData; -import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; -import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData; -import io.opencensus.tags.TagValue; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -/** Stats test utilities. */ -final class StatsTestUtil { - - private StatsTestUtil() {} - - /** - * Creates an {@link AggregationData} by adding the given sequence of values, based on the - * definition of the given {@link Aggregation}. - * - * @param aggregation the {@code Aggregation} to apply the values to. - * @param values the values to add to the {@code MutableAggregation}s. - * @return an {@code AggregationData}. - */ - static AggregationData createAggregationData( - Aggregation aggregation, Measure measure, double... values) { - MutableAggregation mutableAggregation = MutableViewData.createMutableAggregation(aggregation); - for (double value : values) { - mutableAggregation.add(value); - } - return MutableViewData.createAggregationData(mutableAggregation, measure); - } - - /** - * Compare the actual and expected AggregationMap within the given tolerance. - * - * @param expected the expected map. - * @param actual the actual mapping from {@code List} to {@code AggregationData}. - * @param tolerance the tolerance used for {@code double} comparison. - */ - static void assertAggregationMapEquals( - Map, ? extends AggregationData> actual, - Map, ? extends AggregationData> expected, - double tolerance) { - assertThat(actual.keySet()).containsExactlyElementsIn(expected.keySet()); - for (List tagValues : actual.keySet()) { - assertAggregationDataEquals(expected.get(tagValues), actual.get(tagValues), tolerance); - } - } - - /** - * Compare the expected and actual {@code AggregationData} within the given tolerance. - * - * @param expected the expected {@code AggregationData}. - * @param actual the actual {@code AggregationData}. - * @param tolerance the tolerance used for {@code double} comparison. - */ - static void assertAggregationDataEquals( - AggregationData expected, final AggregationData actual, final double tolerance) { - expected.match( - new Function() { - @Override - public Void apply(SumDataDouble arg) { - assertThat(actual).isInstanceOf(SumDataDouble.class); - assertThat(((SumDataDouble) actual).getSum()).isWithin(tolerance).of(arg.getSum()); - return null; - } - }, - new Function() { - @Override - public Void apply(SumDataLong arg) { - assertThat(actual).isInstanceOf(SumDataLong.class); - assertThat(((SumDataLong) actual).getSum()).isEqualTo(arg.getSum()); - return null; - } - }, - new Function() { - @Override - public Void apply(CountData arg) { - assertThat(actual).isInstanceOf(CountData.class); - assertThat(((CountData) actual).getCount()).isEqualTo(arg.getCount()); - return null; - } - }, - new Function() { - @Override - public Void apply(MeanData arg) { - assertThat(actual).isInstanceOf(MeanData.class); - assertThat(((MeanData) actual).getMean()).isWithin(tolerance).of(arg.getMean()); - return null; - } - }, - new Function() { - @Override - public Void apply(DistributionData arg) { - assertThat(actual).isInstanceOf(DistributionData.class); - assertDistributionDataEquals(arg, (DistributionData) actual, tolerance); - return null; - } - }, - Functions.throwIllegalArgumentException()); - } - - // Create an empty ViewData with the given View. - static ViewData createEmptyViewData(View view) { - return ViewData.create( - view, - Collections., AggregationData>emptyMap(), - view.getWindow() - .match( - Functions.returnConstant( - CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)), - Functions.returnConstant( - IntervalData.create(ZERO_TIMESTAMP)), - Functions.throwAssertionError())); - } - - // Compare the expected and actual DistributionData within the given tolerance. - private static void assertDistributionDataEquals( - DistributionData expected, DistributionData actual, double tolerance) { - assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean()); - assertThat(actual.getCount()).isEqualTo(expected.getCount()); - assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean()); - assertThat(actual.getSumOfSquaredDeviations()) - .isWithin(tolerance) - .of(expected.getSumOfSquaredDeviations()); - - if (expected.getMax() == Double.NEGATIVE_INFINITY - && expected.getMin() == Double.POSITIVE_INFINITY) { - assertThat(actual.getMax()).isNegativeInfinity(); - assertThat(actual.getMin()).isPositiveInfinity(); - } else { - assertThat(actual.getMax()).isWithin(tolerance).of(expected.getMax()); - assertThat(actual.getMin()).isWithin(tolerance).of(expected.getMin()); - } - - assertThat(removeTrailingZeros((actual).getBucketCounts())) - .isEqualTo(removeTrailingZeros(expected.getBucketCounts())); - } - - private static List removeTrailingZeros(List longs) { - if (longs == null) { - return null; - } - List truncated = new ArrayList(longs); - while (!truncated.isEmpty() && Iterables.getLast(truncated) == 0) { - truncated.remove(truncated.size() - 1); - } - return truncated; - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java b/core_impl/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java deleted file mode 100644 index 5eaa34e5..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.stats; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.stats.StatsTestUtil.assertAggregationMapEquals; -import static io.opencensus.implcore.stats.StatsTestUtil.createAggregationData; -import static io.opencensus.implcore.stats.StatsTestUtil.createEmptyViewData; - -import com.google.common.collect.ImmutableMap; -import io.opencensus.common.Duration; -import io.opencensus.common.Timestamp; -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.Mean; -import io.opencensus.stats.Aggregation.Sum; -import io.opencensus.stats.AggregationData; -import io.opencensus.stats.AggregationData.MeanData; -import io.opencensus.stats.AggregationData.SumDataDouble; -import io.opencensus.stats.AggregationData.SumDataLong; -import io.opencensus.stats.BucketBoundaries; -import io.opencensus.stats.Measure; -import io.opencensus.stats.Measure.MeasureDouble; -import io.opencensus.stats.Measure.MeasureLong; -import io.opencensus.stats.MeasureMap; -import io.opencensus.stats.StatsCollectionState; -import io.opencensus.stats.View; -import io.opencensus.stats.View.AggregationWindow.Cumulative; -import io.opencensus.stats.View.AggregationWindow.Interval; -import io.opencensus.stats.View.Name; -import io.opencensus.stats.ViewData; -import io.opencensus.stats.ViewData.AggregationWindowData; -import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; -import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TagsComponent; -import io.opencensus.testing.common.TestClock; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link ViewManagerImpl}. */ -@RunWith(JUnit4.class) -public class ViewManagerImplTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private static final TagKey KEY = TagKey.create("KEY"); - - private static final TagValue VALUE = TagValue.create("VALUE"); - private static final TagValue VALUE_2 = TagValue.create("VALUE_2"); - - private static final String MEASURE_NAME = "my measurement"; - - private static final String MEASURE_NAME_2 = "my measurement 2"; - - private static final String MEASURE_UNIT = "us"; - - private static final String MEASURE_DESCRIPTION = "measure description"; - - private static final MeasureDouble MEASURE_DOUBLE = - MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT); - - private static final MeasureLong MEASURE_LONG = - MeasureLong.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT); - - private static final Name VIEW_NAME = Name.create("my view"); - private static final Name VIEW_NAME_2 = Name.create("my view 2"); - - private static final String VIEW_DESCRIPTION = "view description"; - - private static final Cumulative CUMULATIVE = Cumulative.create(); - - private static final double EPSILON = 1e-7; - private static final int MILLIS_PER_SECOND = 1000; - private static final Duration TEN_SECONDS = Duration.create(10, 0); - - private static final BucketBoundaries BUCKET_BOUNDARIES = - BucketBoundaries.create( - Arrays.asList( - 0.0, 0.2, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0)); - - private static final Sum SUM = Sum.create(); - private static final Mean MEAN = Mean.create(); - private static final Distribution DISTRIBUTION = Distribution.create(BUCKET_BOUNDARIES); - - private final TestClock clock = TestClock.create(); - - private final StatsComponentImplBase statsComponent = - new StatsComponentImplBase(new SimpleEventQueue(), clock); - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - - private final Tagger tagger = tagsComponent.getTagger(); - private final ViewManagerImpl viewManager = statsComponent.getViewManager(); - private final StatsRecorderImpl statsRecorder = statsComponent.getStatsRecorder(); - - private static View createCumulativeView() { - return createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); - } - - private static View createCumulativeView( - View.Name name, Measure measure, Aggregation aggregation, List keys) { - return View.create(name, VIEW_DESCRIPTION, measure, aggregation, keys, CUMULATIVE); - } - - @Test - public void testRegisterAndGetCumulativeView() { - View view = createCumulativeView(); - viewManager.registerView(view); - assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view); - assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); - assertThat(viewManager.getView(VIEW_NAME).getWindowData()).isInstanceOf(CumulativeData.class); - } - - @Test - public void testRegisterAndGetIntervalView() { - View intervalView = - View.create( - VIEW_NAME, - VIEW_DESCRIPTION, - MEASURE_DOUBLE, - DISTRIBUTION, - Arrays.asList(KEY), - Interval.create(Duration.create(60, 0))); - viewManager.registerView(intervalView); - assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(intervalView); - assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); - assertThat(viewManager.getView(VIEW_NAME).getWindowData()).isInstanceOf(IntervalData.class); - } - - @Test - public void allowRegisteringSameViewTwice() { - View view = createCumulativeView(); - viewManager.registerView(view); - viewManager.registerView(view); - assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view); - } - - @Test - public void preventRegisteringDifferentViewWithSameName() { - View view1 = - View.create( - VIEW_NAME, - "View description.", - MEASURE_DOUBLE, - DISTRIBUTION, - Arrays.asList(KEY), - CUMULATIVE); - View view2 = - View.create( - VIEW_NAME, - "This is a different description.", - MEASURE_DOUBLE, - DISTRIBUTION, - Arrays.asList(KEY), - CUMULATIVE); - testFailedToRegisterView( - view1, view2, "A different view with the same name is already registered"); - } - - @Test - public void preventRegisteringDifferentMeasureWithSameName() { - MeasureDouble measure1 = MeasureDouble.create("measure", "description", "1"); - MeasureLong measure2 = MeasureLong.create("measure", "description", "1"); - View view1 = - View.create( - VIEW_NAME, VIEW_DESCRIPTION, measure1, DISTRIBUTION, Arrays.asList(KEY), CUMULATIVE); - View view2 = - View.create( - VIEW_NAME_2, VIEW_DESCRIPTION, measure2, DISTRIBUTION, Arrays.asList(KEY), CUMULATIVE); - testFailedToRegisterView( - view1, view2, "A different measure with the same name is already registered"); - } - - private void testFailedToRegisterView(View view1, View view2, String message) { - viewManager.registerView(view1); - try { - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage(message); - viewManager.registerView(view2); - } finally { - assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view1); - } - } - - @Test - public void returnNullWhenGettingNonexistentViewData() { - assertThat(viewManager.getView(VIEW_NAME)).isNull(); - } - - @Test - public void testRecordDouble_distribution_cumulative() { - testRecordCumulative(MEASURE_DOUBLE, DISTRIBUTION, 10.0, 20.0, 30.0, 40.0); - } - - @Test - public void testRecordLong_distribution_cumulative() { - testRecordCumulative(MEASURE_LONG, DISTRIBUTION, 1000, 2000, 3000, 4000); - } - - @Test - public void testRecordDouble_sum_cumulative() { - testRecordCumulative(MEASURE_DOUBLE, SUM, 11.1, 22.2, 33.3, 44.4); - } - - @Test - public void testRecordLong_sum_cumulative() { - testRecordCumulative(MEASURE_LONG, SUM, 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)); - viewManager.registerView(view); - TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); - for (double val : values) { - putToMeasureMap(statsRecorder.newMeasureMap(), measure, val).record(tags); - } - clock.setTime(Timestamp.create(3, 4)); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertThat(viewData.getView()).isEqualTo(view); - assertThat(viewData.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(1, 2), Timestamp.create(3, 4))); - StatsTestUtil.assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(aggregation, measure, values)), - EPSILON); - } - - @Test - public void testRecordDouble_mean_interval() { - testRecordInterval( - MEASURE_DOUBLE, - MEAN, - new double[] {20.0, -1.0, 1.0, -5.0, 5.0}, - 9.0, - 30.0, - MeanData.create((19 * 0.6 + 1) / 4, 4), - MeanData.create(0.2 * 5 + 9, 1), - MeanData.create(30.0, 1)); - } - - @Test - public void testRecordLong_mean_interval() { - testRecordInterval( - MEASURE_LONG, - MEAN, - new double[] {1000, 2000, 3000, 4000, 5000}, - -5000, - 30, - MeanData.create((3000 * 0.6 + 12000) / 4, 4), - MeanData.create(-4000, 1), - MeanData.create(30, 1)); - } - - @Test - public void testRecordDouble_sum_interval() { - testRecordInterval( - MEASURE_DOUBLE, - SUM, - new double[] {20.0, -1.0, 1.0, -5.0, 5.0}, - 9.0, - 30.0, - SumDataDouble.create(19 * 0.6 + 1), - SumDataDouble.create(0.2 * 5 + 9), - SumDataDouble.create(30.0)); - } - - @Test - public void testRecordLong_sum_interval() { - testRecordInterval( - MEASURE_LONG, - SUM, - new double[] {1000, 2000, 3000, 4000, 5000}, - -5000, - 30, - SumDataLong.create(Math.round(3000 * 0.6 + 12000)), - SumDataLong.create(-4000), - SumDataLong.create(30)); - } - - private void testRecordInterval( - Measure measure, - Aggregation aggregation, - double[] initialValues, /* There are 5 initial values recorded before we call getView(). */ - double value6, - double value7, - AggregationData expectedValues1, - AggregationData expectedValues2, - AggregationData expectedValues3) { - // The interval is 10 seconds, i.e. values should expire after 10 seconds. - // Each bucket has a duration of 2.5 seconds. - View view = - View.create( - VIEW_NAME, - VIEW_DESCRIPTION, - measure, - aggregation, - Arrays.asList(KEY), - Interval.create(TEN_SECONDS)); - long startTimeMillis = 30 * MILLIS_PER_SECOND; // start at 30s - clock.setTime(Timestamp.fromMillis(startTimeMillis)); - viewManager.registerView(view); - - TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); - - for (int i = 1; i <= 5; i++) { - /* - * Add each value in sequence, at 31s, 32s, 33s, etc. - * 1st and 2nd values should fall into the first bucket [30.0, 32.5), - * 3rd and 4th values should fall into the second bucket [32.5, 35.0), - * 5th value should fall into the third bucket [35.0, 37.5). - */ - clock.setTime(Timestamp.fromMillis(startTimeMillis + i * MILLIS_PER_SECOND)); - putToMeasureMap(statsRecorder.newMeasureMap(), measure, initialValues[i - 1]).record(tags); - } - - clock.setTime(Timestamp.fromMillis(startTimeMillis + 8 * MILLIS_PER_SECOND)); - // 38s, no values should have expired - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(aggregation, measure, initialValues)), - EPSILON); - - clock.setTime(Timestamp.fromMillis(startTimeMillis + 11 * MILLIS_PER_SECOND)); - // 41s, 40% of the values in the first bucket should have expired (1 / 2.5 = 0.4). - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of(Arrays.asList(VALUE), expectedValues1), - EPSILON); - - clock.setTime(Timestamp.fromMillis(startTimeMillis + 12 * MILLIS_PER_SECOND)); - // 42s, add a new value value1, should fall into bucket [40.0, 42.5) - putToMeasureMap(statsRecorder.newMeasureMap(), measure, value6).record(tags); - - clock.setTime(Timestamp.fromMillis(startTimeMillis + 17 * MILLIS_PER_SECOND)); - // 47s, values in the first and second bucket should have expired, and 80% of values in the - // third bucket should have expired. The new value should persist. - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of(Arrays.asList(VALUE), expectedValues2), - EPSILON); - - clock.setTime(Timestamp.fromMillis(60 * MILLIS_PER_SECOND)); - // 60s, all previous values should have expired, add another value value2 - putToMeasureMap(statsRecorder.newMeasureMap(), measure, value7).record(tags); - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of(Arrays.asList(VALUE), expectedValues3), - EPSILON); - - clock.setTime(Timestamp.fromMillis(100 * MILLIS_PER_SECOND)); - // 100s, all values should have expired - assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); - } - - @Test - public void getViewDoesNotClearStats() { - View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); - clock.setTime(Timestamp.create(10, 0)); - viewManager.registerView(view); - TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); - statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 0.1).record(tags); - clock.setTime(Timestamp.create(11, 0)); - ViewData viewData1 = viewManager.getView(VIEW_NAME); - assertThat(viewData1.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(10, 0), Timestamp.create(11, 0))); - StatsTestUtil.assertAggregationMapEquals( - viewData1.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 0.1)), - EPSILON); - - statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 0.2).record(tags); - clock.setTime(Timestamp.create(12, 0)); - ViewData viewData2 = viewManager.getView(VIEW_NAME); - - // The second view should have the same start time as the first view, and it should include both - // recorded values: - assertThat(viewData2.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(10, 0), Timestamp.create(12, 0))); - StatsTestUtil.assertAggregationMapEquals( - viewData2.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 0.1, 0.2)), - EPSILON); - } - - @Test - public void testRecordCumulativeMultipleTagValues() { - viewManager.registerView( - createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY))); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 10.0) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 30.0) - .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 50.0) - .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0), - Arrays.asList(VALUE_2), - createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0)), - EPSILON); - } - - @Test - public void testRecordIntervalMultipleTagValues() { - // The interval is 10 seconds, i.e. values should expire after 10 seconds. - View view = - View.create( - VIEW_NAME, - VIEW_DESCRIPTION, - MEASURE_DOUBLE, - DISTRIBUTION, - Arrays.asList(KEY), - Interval.create(TEN_SECONDS)); - clock.setTime(Timestamp.create(10, 0)); // Start at 10s - viewManager.registerView(view); - - // record for TagValue1 at 11s - clock.setTime(Timestamp.fromMillis(11 * MILLIS_PER_SECOND)); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 10.0) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - - // record for TagValue2 at 15s - clock.setTime(Timestamp.fromMillis(15 * MILLIS_PER_SECOND)); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 30.0) - .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 50.0) - .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); - - // get ViewData at 19s, no stats should have expired. - clock.setTime(Timestamp.fromMillis(19 * MILLIS_PER_SECOND)); - ViewData viewData1 = viewManager.getView(VIEW_NAME); - StatsTestUtil.assertAggregationMapEquals( - viewData1.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0), - Arrays.asList(VALUE_2), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0)), - EPSILON); - - // record for TagValue2 again at 20s - clock.setTime(Timestamp.fromMillis(20 * MILLIS_PER_SECOND)); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 40.0) - .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); - - // get ViewData at 25s, stats for TagValue1 should have expired. - clock.setTime(Timestamp.fromMillis(25 * MILLIS_PER_SECOND)); - ViewData viewData2 = viewManager.getView(VIEW_NAME); - StatsTestUtil.assertAggregationMapEquals( - viewData2.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE_2), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0, 40.0)), - EPSILON); - - // get ViewData at 30s, the first two values for TagValue2 should have expired. - clock.setTime(Timestamp.fromMillis(30 * MILLIS_PER_SECOND)); - ViewData viewData3 = viewManager.getView(VIEW_NAME); - StatsTestUtil.assertAggregationMapEquals( - viewData3.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE_2), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 40.0)), - EPSILON); - - // get ViewData at 40s, all stats should have expired. - clock.setTime(Timestamp.fromMillis(40 * MILLIS_PER_SECOND)); - ViewData viewData4 = viewManager.getView(VIEW_NAME); - assertThat(viewData4.getAggregationMap()).isEmpty(); - } - - // This test checks that MeasureMaper.record(...) does not throw an exception when no views are - // registered. - @Test - public void allowRecordingWithoutRegisteringMatchingViewData() { - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 10) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - } - - @Test - public void testRecordWithEmptyStatsContext() { - viewManager.registerView( - createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY))); - // DEFAULT doesn't have tags, but the view has tag key "KEY". - statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 10.0).record(tagger.empty()); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - // Tag is missing for associated measureValues, should use default tag value - // "unknown/not set". - Arrays.asList(MutableViewData.UNKNOWN_TAG_VALUE), - // Should record stats with default tag value: "KEY" : "unknown/not set". - createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0)), - EPSILON); - } - - @Test - public void testRecord_MeasureNameNotMatch() { - testRecord_MeasureNotMatch( - MeasureDouble.create(MEASURE_NAME, "measure", MEASURE_UNIT), - MeasureDouble.create(MEASURE_NAME_2, "measure", MEASURE_UNIT), - 10.0); - } - - @Test - public void testRecord_MeasureTypeNotMatch() { - testRecord_MeasureNotMatch( - MeasureLong.create(MEASURE_NAME, "measure", MEASURE_UNIT), - MeasureDouble.create(MEASURE_NAME, "measure", MEASURE_UNIT), - 10.0); - } - - private void testRecord_MeasureNotMatch(Measure measure1, Measure measure2, double value) { - viewManager.registerView(createCumulativeView(VIEW_NAME, measure1, MEAN, Arrays.asList(KEY))); - TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); - putToMeasureMap(statsRecorder.newMeasureMap(), measure2, value).record(tags); - ViewData view = viewManager.getView(VIEW_NAME); - assertThat(view.getAggregationMap()).isEmpty(); - } - - @Test - public void testRecordWithTagsThatDoNotMatchViewData() { - viewManager.registerView( - createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY))); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 10.0) - .record(tagger.emptyBuilder().put(TagKey.create("wrong key"), VALUE).build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 50.0) - .record(tagger.emptyBuilder().put(TagKey.create("another wrong key"), VALUE).build()); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - // Won't record the unregistered tag key, for missing registered keys will use default - // tag value : "unknown/not set". - Arrays.asList(MutableViewData.UNKNOWN_TAG_VALUE), - // Should record stats with default tag value: "KEY" : "unknown/not set". - createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0, 50.0)), - EPSILON); - } - - @Test - public void testViewDataWithMultipleTagKeys() { - TagKey key1 = TagKey.create("Key-1"); - TagKey key2 = TagKey.create("Key-2"); - viewManager.registerView( - createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(key1, key2))); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record( - tagger - .emptyBuilder() - .put(key1, TagValue.create("v1")) - .put(key2, TagValue.create("v10")) - .build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 2.2) - .record( - tagger - .emptyBuilder() - .put(key1, TagValue.create("v1")) - .put(key2, TagValue.create("v20")) - .build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 3.3) - .record( - tagger - .emptyBuilder() - .put(key1, TagValue.create("v2")) - .put(key2, TagValue.create("v10")) - .build()); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 4.4) - .record( - tagger - .emptyBuilder() - .put(key1, TagValue.create("v1")) - .put(key2, TagValue.create("v10")) - .build()); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(TagValue.create("v1"), TagValue.create("v10")), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 1.1, 4.4), - Arrays.asList(TagValue.create("v1"), TagValue.create("v20")), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 2.2), - Arrays.asList(TagValue.create("v2"), TagValue.create("v10")), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 3.3)), - EPSILON); - } - - @Test - public void testMultipleViewSameMeasure() { - final View view1 = - createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); - final View view2 = - createCumulativeView(VIEW_NAME_2, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); - clock.setTime(Timestamp.create(1, 1)); - viewManager.registerView(view1); - clock.setTime(Timestamp.create(2, 2)); - viewManager.registerView(view2); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 5.0) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - clock.setTime(Timestamp.create(3, 3)); - ViewData viewData1 = viewManager.getView(VIEW_NAME); - clock.setTime(Timestamp.create(4, 4)); - ViewData viewData2 = viewManager.getView(VIEW_NAME_2); - assertThat(viewData1.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(1, 1), Timestamp.create(3, 3))); - StatsTestUtil.assertAggregationMapEquals( - viewData1.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 5.0)), - EPSILON); - assertThat(viewData2.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(2, 2), Timestamp.create(4, 4))); - StatsTestUtil.assertAggregationMapEquals( - viewData2.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 5.0)), - EPSILON); - } - - @Test - public void testMultipleViews_DifferentMeasureNames() { - testMultipleViews_DifferentMeasures( - MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT), - MeasureDouble.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT), - 1.1, - 2.2); - } - - @Test - public void testMultipleViews_DifferentMeasureTypes() { - testMultipleViews_DifferentMeasures( - MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT), - MeasureLong.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT), - 1.1, - 5000); - } - - private void testMultipleViews_DifferentMeasures( - Measure measure1, Measure measure2, double value1, double value2) { - final View view1 = createCumulativeView(VIEW_NAME, measure1, DISTRIBUTION, Arrays.asList(KEY)); - final View view2 = - createCumulativeView(VIEW_NAME_2, measure2, DISTRIBUTION, Arrays.asList(KEY)); - clock.setTime(Timestamp.create(1, 0)); - viewManager.registerView(view1); - clock.setTime(Timestamp.create(2, 0)); - viewManager.registerView(view2); - TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); - MeasureMap measureMap = statsRecorder.newMeasureMap(); - putToMeasureMap(measureMap, measure1, value1); - putToMeasureMap(measureMap, measure2, value2); - measureMap.record(tags); - clock.setTime(Timestamp.create(3, 0)); - ViewData viewData1 = viewManager.getView(VIEW_NAME); - clock.setTime(Timestamp.create(4, 0)); - ViewData viewData2 = viewManager.getView(VIEW_NAME_2); - assertThat(viewData1.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0))); - StatsTestUtil.assertAggregationMapEquals( - viewData1.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, measure1, value1)), - EPSILON); - assertThat(viewData2.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(2, 0), Timestamp.create(4, 0))); - StatsTestUtil.assertAggregationMapEquals( - viewData2.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(DISTRIBUTION, measure2, value2)), - EPSILON); - } - - @Test - public void testGetCumulativeViewDataWithEmptyBucketBoundaries() { - Aggregation noHistogram = - Distribution.create(BucketBoundaries.create(Collections.emptyList())); - View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, noHistogram, Arrays.asList(KEY)); - clock.setTime(Timestamp.create(1, 0)); - viewManager.registerView(view); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - clock.setTime(Timestamp.create(3, 0)); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertThat(viewData.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0))); - StatsTestUtil.assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(noHistogram, MEASURE_DOUBLE, 1.1)), - EPSILON); - } - - @Test - public void testGetCumulativeViewDataWithoutBucketBoundaries() { - View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); - clock.setTime(Timestamp.create(1, 0)); - viewManager.registerView(view); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - clock.setTime(Timestamp.create(3, 0)); - ViewData viewData = viewManager.getView(VIEW_NAME); - assertThat(viewData.getWindowData()) - .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0))); - StatsTestUtil.assertAggregationMapEquals( - viewData.getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)), - EPSILON); - } - - @Test - public void registerRecordAndGetView_StatsDisabled() { - statsComponent.setState(StatsCollectionState.DISABLED); - View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); - viewManager.registerView(view); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view)); - } - - @Test - public void registerRecordAndGetView_StatsReenabled() { - statsComponent.setState(StatsCollectionState.DISABLED); - statsComponent.setState(StatsCollectionState.ENABLED); - View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); - viewManager.registerView(view); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)), - EPSILON); - } - - @Test - public void registerViewWithStatsDisabled_RecordAndGetViewWithStatsEnabled() { - statsComponent.setState(StatsCollectionState.DISABLED); - View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); - viewManager.registerView(view); // view will still be registered. - - statsComponent.setState(StatsCollectionState.ENABLED); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(VIEW_NAME).getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)), - EPSILON); - } - - @Test - public void registerDifferentViewWithSameNameWithStatsDisabled() { - statsComponent.setState(StatsCollectionState.DISABLED); - View view1 = - View.create( - VIEW_NAME, - "View description.", - MEASURE_DOUBLE, - DISTRIBUTION, - Arrays.asList(KEY), - CUMULATIVE); - View view2 = - View.create( - VIEW_NAME, - "This is a different description.", - MEASURE_DOUBLE, - DISTRIBUTION, - Arrays.asList(KEY), - CUMULATIVE); - testFailedToRegisterView( - view1, view2, "A different view with the same name is already registered"); - } - - @Test - public void settingStateToDisabledWillClearStats_Cumulative() { - View cumulativeView = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); - settingStateToDisabledWillClearStats(cumulativeView); - } - - @Test - public void settingStateToDisabledWillClearStats_Interval() { - View intervalView = - View.create( - VIEW_NAME_2, - VIEW_DESCRIPTION, - MEASURE_DOUBLE, - MEAN, - Arrays.asList(KEY), - Interval.create(Duration.create(60, 0))); - settingStateToDisabledWillClearStats(intervalView); - } - - private void settingStateToDisabledWillClearStats(View view) { - Timestamp timestamp1 = Timestamp.create(1, 0); - clock.setTime(timestamp1); - viewManager.registerView(view); - statsRecorder - .newMeasureMap() - .put(MEASURE_DOUBLE, 1.1) - .record(tagger.emptyBuilder().put(KEY, VALUE).build()); - StatsTestUtil.assertAggregationMapEquals( - viewManager.getView(view.getName()).getAggregationMap(), - ImmutableMap.of( - Arrays.asList(VALUE), - StatsTestUtil.createAggregationData(view.getAggregation(), view.getMeasure(), 1.1)), - EPSILON); - - Timestamp timestamp2 = Timestamp.create(2, 0); - clock.setTime(timestamp2); - statsComponent.setState(StatsCollectionState.DISABLED); // This will clear stats. - assertThat(viewManager.getView(view.getName())).isEqualTo(createEmptyViewData(view)); - - Timestamp timestamp3 = Timestamp.create(3, 0); - clock.setTime(timestamp3); - statsComponent.setState(StatsCollectionState.ENABLED); - - Timestamp timestamp4 = Timestamp.create(4, 0); - clock.setTime(timestamp4); - // This ViewData does not have any stats, but it should not be an empty ViewData, since it has - // non-zero TimeStamps. - ViewData viewData = viewManager.getView(view.getName()); - assertThat(viewData.getAggregationMap()).isEmpty(); - AggregationWindowData windowData = viewData.getWindowData(); - if (windowData instanceof CumulativeData) { - assertThat(windowData).isEqualTo(CumulativeData.create(timestamp3, timestamp4)); - } else { - assertThat(windowData).isEqualTo(IntervalData.create(timestamp4)); - } - } - - private static MeasureMap putToMeasureMap(MeasureMap measureMap, Measure measure, double value) { - if (measure instanceof MeasureDouble) { - return measureMap.put((MeasureDouble) measure, value); - } else if (measure instanceof MeasureLong) { - return measureMap.put((MeasureLong) measure, Math.round(value)); - } else { - // Future measures. - throw new AssertionError(); - } - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java deleted file mode 100644 index 1a14ac6e..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; - -import com.google.common.collect.ImmutableSet; -import io.grpc.Context; -import io.opencensus.common.Scope; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.unsafe.ContextUtils; -import java.util.Iterator; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link CurrentTagContextUtils}. */ -@RunWith(JUnit4.class) -public class CurrentTagContextUtilsTest { - private static final Tag TAG = Tag.create(TagKey.create("key"), TagValue.create("value")); - - private final TagContext tagContext = - new TagContext() { - - @Override - protected Iterator getIterator() { - return ImmutableSet.of(TAG).iterator(); - } - }; - - @Test - public void testGetCurrentTagContext_DefaultContext() { - TagContext tags = CurrentTagContextUtils.getCurrentTagContext(); - assertThat(tags).isNotNull(); - assertThat(tagContextToList(tags)).isEmpty(); - } - - @Test - public void testGetCurrentTagContext_ContextSetToNull() { - Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, null).attach(); - try { - TagContext tags = CurrentTagContextUtils.getCurrentTagContext(); - assertThat(tags).isNotNull(); - assertThat(tagContextToList(tags)).isEmpty(); - } finally { - Context.current().detach(orig); - } - } - - @Test - public void testWithTagContext() { - assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty(); - Scope scopedTags = CurrentTagContextUtils.withTagContext(tagContext); - try { - assertThat(CurrentTagContextUtils.getCurrentTagContext()).isSameAs(tagContext); - } finally { - scopedTags.close(); - } - assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty(); - } - - @Test - public void testWithTagContextUsingWrap() { - Runnable runnable; - Scope scopedTags = CurrentTagContextUtils.withTagContext(tagContext); - try { - assertThat(CurrentTagContextUtils.getCurrentTagContext()).isSameAs(tagContext); - runnable = - Context.current() - .wrap( - new Runnable() { - @Override - public void run() { - assertThat(CurrentTagContextUtils.getCurrentTagContext()) - .isSameAs(tagContext); - } - }); - } finally { - scopedTags.close(); - } - assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty(); - // When we run the runnable we will have the TagContext in the current Context. - runnable.run(); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java deleted file mode 100644 index 244b6711..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.tags.TaggingState; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link CurrentTaggingState}. */ -@RunWith(JUnit4.class) -public final class CurrentTaggingStateTest { - - @Test - public void defaultState() { - assertThat(new CurrentTaggingState().get()).isEqualTo(TaggingState.ENABLED); - } - - @Test - public void setState() { - CurrentTaggingState state = new CurrentTaggingState(); - state.set(TaggingState.DISABLED); - assertThat(state.get()).isEqualTo(TaggingState.DISABLED); - state.set(TaggingState.ENABLED); - assertThat(state.get()).isEqualTo(TaggingState.ENABLED); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java deleted file mode 100644 index c24cccb9..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; - -import io.opencensus.common.Scope; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Unit tests for the methods in {@link TaggerImpl} and {@link TagContextBuilderImpl} that interact - * with the current {@link TagContext}. - */ -@RunWith(JUnit4.class) -public class ScopedTagContextsTest { - private static final TagKey KEY_1 = TagKey.create("key 1"); - private static final TagKey KEY_2 = TagKey.create("key 2"); - - private static final TagValue VALUE_1 = TagValue.create("value 1"); - private static final TagValue VALUE_2 = TagValue.create("value 2"); - - private final Tagger tagger = new TaggerImpl(new CurrentTaggingState()); - - @Test - public void defaultTagContext() { - TagContext defaultTagContext = tagger.getCurrentTagContext(); - assertThat(tagContextToList(defaultTagContext)).isEmpty(); - assertThat(defaultTagContext).isInstanceOf(TagContextImpl.class); - } - - @Test - public void withTagContext() { - assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); - TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build(); - Scope scope = tagger.withTagContext(scopedTags); - try { - assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags); - } finally { - scope.close(); - } - assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); - } - - @Test - public void createBuilderFromCurrentTags() { - TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build(); - Scope scope = tagger.withTagContext(scopedTags); - try { - TagContext newTags = tagger.currentBuilder().put(KEY_2, VALUE_2).build(); - assertThat(tagContextToList(newTags)) - .containsExactly(Tag.create(KEY_1, VALUE_1), Tag.create(KEY_2, VALUE_2)); - assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags); - } finally { - scope.close(); - } - } - - @Test - public void setCurrentTagsWithBuilder() { - assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); - Scope scope = tagger.emptyBuilder().put(KEY_1, VALUE_1).buildScoped(); - try { - assertThat(tagContextToList(tagger.getCurrentTagContext())) - .containsExactly(Tag.create(KEY_1, VALUE_1)); - } finally { - scope.close(); - } - assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); - } - - @Test - public void addToCurrentTagsWithBuilder() { - TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build(); - Scope scope1 = tagger.withTagContext(scopedTags); - try { - Scope scope2 = tagger.currentBuilder().put(KEY_2, VALUE_2).buildScoped(); - try { - assertThat(tagContextToList(tagger.getCurrentTagContext())) - .containsExactly(Tag.create(KEY_1, VALUE_1), Tag.create(KEY_2, VALUE_2)); - } finally { - scope2.close(); - } - assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags); - } finally { - scope1.close(); - } - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java deleted file mode 100644 index b70d8b4e..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import com.google.common.collect.Lists; -import com.google.common.testing.EqualsTester; -import io.opencensus.tags.InternalUtils; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import java.util.Arrays; -import java.util.Iterator; -import java.util.NoSuchElementException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link TagContextImpl} and {@link TagContextBuilderImpl}. */ -// TODO(sebright): Add more tests once the API is finalized. -@RunWith(JUnit4.class) -public class TagContextImplTest { - private final Tagger tagger = new TaggerImpl(new CurrentTaggingState()); - - private static final TagKey KS1 = TagKey.create("k1"); - private static final TagKey KS2 = TagKey.create("k2"); - - private static final TagValue V1 = TagValue.create("v1"); - private static final TagValue V2 = TagValue.create("v2"); - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - @Test - public void testSet() { - TagContext tags = tagger.emptyBuilder().put(KS1, V1).build(); - assertThat(tagContextToList(tagger.toBuilder(tags).put(KS1, V2).build())) - .containsExactly(Tag.create(KS1, V2)); - assertThat(tagContextToList(tagger.toBuilder(tags).put(KS2, V2).build())) - .containsExactly(Tag.create(KS1, V1), Tag.create(KS2, V2)); - } - - @Test - public void testClear() { - TagContext tags = tagger.emptyBuilder().put(KS1, V1).build(); - assertThat(tagContextToList(tagger.toBuilder(tags).remove(KS1).build())).isEmpty(); - assertThat(tagContextToList(tagger.toBuilder(tags).remove(KS2).build())) - .containsExactly(Tag.create(KS1, V1)); - } - - @Test - public void testIterator() { - TagContext tags = tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(); - Iterator i = InternalUtils.getTags(tags); - assertTrue(i.hasNext()); - Tag tag1 = i.next(); - assertTrue(i.hasNext()); - Tag tag2 = i.next(); - assertFalse(i.hasNext()); - assertThat(Arrays.asList(tag1, tag2)).containsExactly(Tag.create(KS1, V1), Tag.create(KS2, V2)); - thrown.expect(NoSuchElementException.class); - i.next(); - } - - @Test - public void disallowCallingRemoveOnIterator() { - TagContext tags = tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(); - Iterator i = InternalUtils.getTags(tags); - i.next(); - thrown.expect(UnsupportedOperationException.class); - i.remove(); - } - - @Test - public void testEquals() { - new EqualsTester() - .addEqualityGroup( - tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(), - tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(), - tagger.emptyBuilder().put(KS2, V2).put(KS1, V1).build(), - new TagContext() { - @Override - protected Iterator getIterator() { - return Lists.newArrayList(Tag.create(KS1, V1), Tag.create(KS2, V2)).iterator(); - } - }) - .addEqualityGroup(tagger.emptyBuilder().put(KS1, V1).put(KS2, V1).build()) - .addEqualityGroup(tagger.emptyBuilder().put(KS1, V2).put(KS2, V1).build()) - .testEquals(); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java deleted file mode 100644 index 4ca2ae76..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.truth.Truth.assertThat; -import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; - -import com.google.common.collect.Lists; -import io.grpc.Context; -import io.opencensus.common.Scope; -import io.opencensus.implcore.internal.NoopScope; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagContextBuilder; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TaggingState; -import io.opencensus.tags.TagsComponent; -import io.opencensus.tags.unsafe.ContextUtils; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link TaggerImpl}. */ -@RunWith(JUnit4.class) -public class TaggerImplTest { - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - private final Tagger tagger = tagsComponent.getTagger(); - - private static final TagKey K1 = TagKey.create("k1"); - private static final TagKey K2 = TagKey.create("k2"); - private static final TagKey K3 = TagKey.create("k3"); - - private static final TagValue V1 = TagValue.create("v1"); - private static final TagValue V2 = TagValue.create("v2"); - private static final TagValue V3 = TagValue.create("v3"); - - private static final Tag TAG1 = Tag.create(K1, V1); - private static final Tag TAG2 = Tag.create(K2, V2); - private static final Tag TAG3 = Tag.create(K3, V3); - - @Test - public void empty() { - assertThat(tagContextToList(tagger.empty())).isEmpty(); - assertThat(tagger.empty()).isInstanceOf(TagContextImpl.class); - } - - @Test - public void empty_TaggingDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagContextToList(tagger.empty())).isEmpty(); - assertThat(tagger.empty()).isInstanceOf(TagContextImpl.class); - } - - @Test - public void emptyBuilder() { - TagContextBuilder builder = tagger.emptyBuilder(); - assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); - assertThat(tagContextToList(builder.build())).isEmpty(); - } - - @Test - public void emptyBuilder_TaggingDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagger.emptyBuilder()).isSameAs(NoopTagContextBuilder.INSTANCE); - } - - @Test - public void emptyBuilder_TaggingReenabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagger.emptyBuilder()).isSameAs(NoopTagContextBuilder.INSTANCE); - tagsComponent.setState(TaggingState.ENABLED); - TagContextBuilder builder = tagger.emptyBuilder(); - assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); - assertThat(tagContextToList(builder.put(K1, V1).build())).containsExactly(Tag.create(K1, V1)); - } - - @Test - public void currentBuilder() { - TagContext tags = new SimpleTagContext(TAG1, TAG2, TAG3); - TagContextBuilder result = getResultOfCurrentBuilder(tags); - assertThat(result).isInstanceOf(TagContextBuilderImpl.class); - assertThat(tagContextToList(result.build())).containsExactly(TAG1, TAG2, TAG3); - } - - @Test - public void currentBuilder_DefaultIsEmpty() { - TagContextBuilder currentBuilder = tagger.currentBuilder(); - assertThat(currentBuilder).isInstanceOf(TagContextBuilderImpl.class); - assertThat(tagContextToList(currentBuilder.build())).isEmpty(); - } - - @Test - public void currentBuilder_RemoveDuplicateTags() { - Tag tag1 = Tag.create(K1, V1); - Tag tag2 = Tag.create(K1, V2); - TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); - TagContextBuilder result = getResultOfCurrentBuilder(tagContextWithDuplicateTags); - assertThat(tagContextToList(result.build())).containsExactly(tag2); - } - - @Test - public void currentBuilder_SkipNullTag() { - TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); - TagContextBuilder result = getResultOfCurrentBuilder(tagContextWithNullTag); - assertThat(tagContextToList(result.build())).containsExactly(TAG1, TAG2); - } - - @Test - public void currentBuilder_TaggingDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(getResultOfCurrentBuilder(new SimpleTagContext(TAG1))) - .isSameAs(NoopTagContextBuilder.INSTANCE); - } - - @Test - public void currentBuilder_TaggingReenabled() { - TagContext tags = new SimpleTagContext(TAG1); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(getResultOfCurrentBuilder(tags)).isSameAs(NoopTagContextBuilder.INSTANCE); - tagsComponent.setState(TaggingState.ENABLED); - TagContextBuilder builder = getResultOfCurrentBuilder(tags); - assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); - assertThat(tagContextToList(builder.build())).containsExactly(TAG1); - } - - private TagContextBuilder getResultOfCurrentBuilder(TagContext tagsToSet) { - Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tagsToSet).attach(); - try { - return tagger.currentBuilder(); - } finally { - Context.current().detach(orig); - } - } - - @Test - public void toBuilder_ConvertUnknownTagContextToTagContextImpl() { - TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3); - TagContext newTagContext = tagger.toBuilder(unknownTagContext).build(); - assertThat(tagContextToList(newTagContext)).containsExactly(TAG1, TAG2, TAG3); - assertThat(newTagContext).isInstanceOf(TagContextImpl.class); - } - - @Test - public void toBuilder_RemoveDuplicatesFromUnknownTagContext() { - Tag tag1 = Tag.create(K1, V1); - Tag tag2 = Tag.create(K1, V2); - TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); - TagContext newTagContext = tagger.toBuilder(tagContextWithDuplicateTags).build(); - assertThat(tagContextToList(newTagContext)).containsExactly(tag2); - } - - @Test - public void toBuilder_SkipNullTag() { - TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); - TagContext newTagContext = tagger.toBuilder(tagContextWithNullTag).build(); - assertThat(tagContextToList(newTagContext)).containsExactly(TAG1, TAG2); - } - - @Test - public void toBuilder_TaggingDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagger.toBuilder(new SimpleTagContext(TAG1))) - .isSameAs(NoopTagContextBuilder.INSTANCE); - } - - @Test - public void toBuilder_TaggingReenabled() { - TagContext tags = new SimpleTagContext(TAG1); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagger.toBuilder(tags)).isSameAs(NoopTagContextBuilder.INSTANCE); - tagsComponent.setState(TaggingState.ENABLED); - TagContextBuilder builder = tagger.toBuilder(tags); - assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); - assertThat(tagContextToList(builder.build())).containsExactly(TAG1); - } - - @Test - public void getCurrentTagContext_DefaultIsEmptyTagContextImpl() { - TagContext currentTagContext = tagger.getCurrentTagContext(); - assertThat(tagContextToList(currentTagContext)).isEmpty(); - assertThat(currentTagContext).isInstanceOf(TagContextImpl.class); - } - - @Test - public void getCurrentTagContext_ConvertUnknownTagContextToTagContextImpl() { - TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3); - TagContext result = getResultOfGetCurrentTagContext(unknownTagContext); - assertThat(result).isInstanceOf(TagContextImpl.class); - assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2, TAG3); - } - - @Test - public void getCurrentTagContext_RemoveDuplicatesFromUnknownTagContext() { - Tag tag1 = Tag.create(K1, V1); - Tag tag2 = Tag.create(K1, V2); - TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); - TagContext result = getResultOfGetCurrentTagContext(tagContextWithDuplicateTags); - assertThat(tagContextToList(result)).containsExactly(tag2); - } - - @Test - public void getCurrentTagContext_SkipNullTag() { - TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); - TagContext result = getResultOfGetCurrentTagContext(tagContextWithNullTag); - assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2); - } - - @Test - public void getCurrentTagContext_TaggingDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagContextToList(getResultOfGetCurrentTagContext(new SimpleTagContext(TAG1)))) - .isEmpty(); - } - - @Test - public void getCurrentTagContext_TaggingReenabled() { - TagContext tags = new SimpleTagContext(TAG1); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagContextToList(getResultOfGetCurrentTagContext(tags))).isEmpty(); - tagsComponent.setState(TaggingState.ENABLED); - assertThat(tagContextToList(getResultOfGetCurrentTagContext(tags))).containsExactly(TAG1); - } - - private TagContext getResultOfGetCurrentTagContext(TagContext tagsToSet) { - Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tagsToSet).attach(); - try { - return tagger.getCurrentTagContext(); - } finally { - Context.current().detach(orig); - } - } - - @Test - public void withTagContext_ConvertUnknownTagContextToTagContextImpl() { - TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3); - TagContext result = getResultOfWithTagContext(unknownTagContext); - assertThat(result).isInstanceOf(TagContextImpl.class); - assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2, TAG3); - } - - @Test - public void withTagContext_RemoveDuplicatesFromUnknownTagContext() { - Tag tag1 = Tag.create(K1, V1); - Tag tag2 = Tag.create(K1, V2); - TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); - TagContext result = getResultOfWithTagContext(tagContextWithDuplicateTags); - assertThat(tagContextToList(result)).containsExactly(tag2); - } - - @Test - public void withTagContext_SkipNullTag() { - TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); - TagContext result = getResultOfWithTagContext(tagContextWithNullTag); - assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2); - } - - @Test - public void withTagContext_ReturnsNoopScopeWhenTaggingIsDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagger.withTagContext(new SimpleTagContext(TAG1))).isSameAs(NoopScope.getInstance()); - } - - @Test - public void withTagContext_TaggingDisabled() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagContextToList(getResultOfWithTagContext(new SimpleTagContext(TAG1)))).isEmpty(); - } - - @Test - public void withTagContext_TaggingReenabled() { - TagContext tags = new SimpleTagContext(TAG1); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagContextToList(getResultOfWithTagContext(tags))).isEmpty(); - tagsComponent.setState(TaggingState.ENABLED); - assertThat(tagContextToList(getResultOfWithTagContext(tags))).containsExactly(TAG1); - } - - private TagContext getResultOfWithTagContext(TagContext tagsToSet) { - Scope scope = tagger.withTagContext(tagsToSet); - try { - return ContextUtils.TAG_CONTEXT_KEY.get(); - } finally { - scope.close(); - } - } - - private static final class SimpleTagContext extends TagContext { - private final List tags; - - SimpleTagContext(Tag... tags) { - this.tags = Collections.unmodifiableList(Lists.newArrayList(tags)); - } - - @Override - protected Iterator getIterator() { - return tags.iterator(); - } - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java deleted file mode 100644 index e75a86d0..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.tags.TaggingState; -import io.opencensus.tags.TagsComponent; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for {@link TagsComponentImplBase}. */ -@RunWith(JUnit4.class) -public class TagsComponentImplBaseTest { - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - - @Test - public void defaultState() { - assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED); - } - - @Test - public void setState() { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(tagsComponent.getState()).isEqualTo(TaggingState.DISABLED); - tagsComponent.setState(TaggingState.ENABLED); - assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED); - } - - @Test(expected = NullPointerException.class) - public void setState_DisallowsNull() { - tagsComponent.setState(null); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java b/core_impl/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java deleted file mode 100644 index c64eced1..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags; - -import com.google.common.collect.Lists; -import io.opencensus.tags.InternalUtils; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import java.util.Collection; - -/** Test utilities for tagging. */ -public class TagsTestUtil { - - /** Returns a collection of all tags in a {@link TagContext}. */ - public static Collection tagContextToList(TagContext tags) { - return Lists.newArrayList(InternalUtils.getTags(tags)); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java deleted file mode 100644 index 7e9bead1..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.collect.ImmutableSet; -import io.opencensus.implcore.tags.TagsComponentImplBase; -import io.opencensus.implcore.tags.TagsTestUtil; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.TaggingState; -import io.opencensus.tags.TagsComponent; -import io.opencensus.tags.propagation.TagContextBinarySerializer; -import io.opencensus.tags.propagation.TagContextDeserializationException; -import io.opencensus.tags.propagation.TagContextSerializationException; -import java.util.Iterator; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Tests for {@link TagContextBinarySerializerImpl}. - * - *

Thorough serialization/deserialization tests are in {@link TagContextSerializationTest}, - * {@link TagContextDeserializationTest}, and {@link TagContextRoundtripTest}. - */ -@RunWith(JUnit4.class) -public final class TagContextBinarySerializerImplTest { - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - private final TagContextBinarySerializer serializer = - tagsComponent.getTagPropagationComponent().getBinarySerializer(); - - private final TagContext tagContext = - new TagContext() { - @Override - public Iterator getIterator() { - return ImmutableSet.of(Tag.create(TagKey.create("key"), TagValue.create("value"))) - .iterator(); - } - }; - - @Test - public void toByteArray_TaggingDisabled() throws TagContextSerializationException { - tagsComponent.setState(TaggingState.DISABLED); - assertThat(serializer.toByteArray(tagContext)).isEmpty(); - } - - @Test - public void toByteArray_TaggingReenabled() throws TagContextSerializationException { - final byte[] serialized = serializer.toByteArray(tagContext); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(serializer.toByteArray(tagContext)).isEmpty(); - tagsComponent.setState(TaggingState.ENABLED); - assertThat(serializer.toByteArray(tagContext)).isEqualTo(serialized); - } - - @Test - public void fromByteArray_TaggingDisabled() - throws TagContextDeserializationException, TagContextSerializationException { - byte[] serialized = serializer.toByteArray(tagContext); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(TagsTestUtil.tagContextToList(serializer.fromByteArray(serialized))).isEmpty(); - } - - @Test - public void fromByteArray_TaggingReenabled() - throws TagContextDeserializationException, TagContextSerializationException { - byte[] serialized = serializer.toByteArray(tagContext); - tagsComponent.setState(TaggingState.DISABLED); - assertThat(TagsTestUtil.tagContextToList(serializer.fromByteArray(serialized))).isEmpty(); - tagsComponent.setState(TaggingState.ENABLED); - assertThat(serializer.fromByteArray(serialized)).isEqualTo(tagContext); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java deleted file mode 100644 index 14118be0..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.base.Charsets; -import com.google.common.io.ByteArrayDataOutput; -import com.google.common.io.ByteStreams; -import io.opencensus.implcore.internal.VarInt; -import io.opencensus.implcore.tags.TagsComponentImplBase; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TagsComponent; -import io.opencensus.tags.propagation.TagContextBinarySerializer; -import io.opencensus.tags.propagation.TagContextDeserializationException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Tests for deserializing tags with {@link SerializationUtils} and {@link - * TagContextBinarySerializerImpl}. - */ -@RunWith(JUnit4.class) -public class TagContextDeserializationTest { - - @Rule public final ExpectedException thrown = ExpectedException.none(); - - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - private final TagContextBinarySerializer serializer = - tagsComponent.getTagPropagationComponent().getBinarySerializer(); - private final Tagger tagger = tagsComponent.getTagger(); - - @Test - public void testVersionAndValueTypeConstants() { - // Refer to the JavaDoc on SerializationUtils for the definitions on these constants. - assertThat(SerializationUtils.VERSION_ID).isEqualTo(0); - assertThat(SerializationUtils.TAG_FIELD_ID).isEqualTo(0); - } - - @Test - public void testDeserializeNoTags() throws TagContextDeserializationException { - TagContext expected = tagger.empty(); - TagContext actual = - serializer.fromByteArray( - new byte[] {SerializationUtils.VERSION_ID}); // One byte that represents Version ID. - assertThat(actual).isEqualTo(expected); - } - - @Test - public void testDeserializeEmptyByteArrayThrowException() - throws TagContextDeserializationException { - thrown.expect(TagContextDeserializationException.class); - thrown.expectMessage("Input byte[] can not be empty."); - serializer.fromByteArray(new byte[0]); - } - - @Test - public void testDeserializeInvalidTagKey() throws TagContextDeserializationException { - ByteArrayDataOutput output = ByteStreams.newDataOutput(); - output.write(SerializationUtils.VERSION_ID); - - // Encode an invalid tag key and a valid tag value: - encodeTagToOutput("\2key", "value", output); - final byte[] bytes = output.toByteArray(); - - thrown.expect(TagContextDeserializationException.class); - thrown.expectMessage("Invalid tag key: \2key"); - serializer.fromByteArray(bytes); - } - - @Test - public void testDeserializeInvalidTagValue() throws TagContextDeserializationException { - ByteArrayDataOutput output = ByteStreams.newDataOutput(); - output.write(SerializationUtils.VERSION_ID); - - // Encode a valid tag key and an invalid tag value: - encodeTagToOutput("my key", "val\3", output); - final byte[] bytes = output.toByteArray(); - - thrown.expect(TagContextDeserializationException.class); - thrown.expectMessage("Invalid tag value for key TagKey{name=my key}: val\3"); - serializer.fromByteArray(bytes); - } - - @Test - public void testDeserializeOneTag() throws TagContextDeserializationException { - ByteArrayDataOutput output = ByteStreams.newDataOutput(); - output.write(SerializationUtils.VERSION_ID); - encodeTagToOutput("Key", "Value", output); - TagContext expected = - tagger.emptyBuilder().put(TagKey.create("Key"), TagValue.create("Value")).build(); - assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); - } - - @Test - public void testDeserializeMultipleTags() throws TagContextDeserializationException { - ByteArrayDataOutput output = ByteStreams.newDataOutput(); - output.write(SerializationUtils.VERSION_ID); - encodeTagToOutput("Key1", "Value1", output); - encodeTagToOutput("Key2", "Value2", output); - TagContext expected = - tagger - .emptyBuilder() - .put(TagKey.create("Key1"), TagValue.create("Value1")) - .put(TagKey.create("Key2"), TagValue.create("Value2")) - .build(); - assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); - } - - @Test - public void stopParsingAtUnknownField() throws TagContextDeserializationException { - ByteArrayDataOutput output = ByteStreams.newDataOutput(); - output.write(SerializationUtils.VERSION_ID); - encodeTagToOutput("Key1", "Value1", output); - encodeTagToOutput("Key2", "Value2", output); - - // Write unknown field ID 1. - output.write(1); - output.write(new byte[] {1, 2, 3, 4}); - - encodeTagToOutput("Key3", "Value3", output); - - // key 3 should not be included - TagContext expected = - tagger - .emptyBuilder() - .put(TagKey.create("Key1"), TagValue.create("Value1")) - .put(TagKey.create("Key2"), TagValue.create("Value2")) - .build(); - assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); - } - - @Test - public void stopParsingAtUnknownTagAtStart() throws TagContextDeserializationException { - ByteArrayDataOutput output = ByteStreams.newDataOutput(); - output.write(SerializationUtils.VERSION_ID); - - // Write unknown field ID 1. - output.write(1); - output.write(new byte[] {1, 2, 3, 4}); - - encodeTagToOutput("Key", "Value", output); - assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(tagger.empty()); - } - - @Test - public void testDeserializeWrongFormat() throws TagContextDeserializationException { - // encoded tags should follow the format ()* - thrown.expect(TagContextDeserializationException.class); - serializer.fromByteArray(new byte[3]); - } - - @Test - public void testDeserializeWrongVersionId() throws TagContextDeserializationException { - thrown.expect(TagContextDeserializationException.class); - thrown.expectMessage("Wrong Version ID: 1. Currently supported version is: 0"); - serializer.fromByteArray(new byte[] {(byte) (SerializationUtils.VERSION_ID + 1)}); - } - - // == - // - // == varint encoded integer - // == tag_key_len bytes comprising tag key name - // == varint encoded integer - // == tag_val_len bytes comprising UTF-8 string - private static void encodeTagToOutput(String key, String value, ByteArrayDataOutput output) { - output.write(SerializationUtils.TAG_FIELD_ID); - encodeString(key, output); - encodeString(value, output); - } - - private static void encodeString(String input, ByteArrayDataOutput output) { - int length = input.length(); - byte[] bytes = new byte[VarInt.varIntSize(length)]; - VarInt.putVarInt(length, bytes, 0); - output.write(bytes); - output.write(input.getBytes(Charsets.UTF_8)); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java deleted file mode 100644 index 88abcc1d..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.implcore.tags.TagsComponentImplBase; -import io.opencensus.tags.TagContext; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TagsComponent; -import io.opencensus.tags.propagation.TagContextBinarySerializer; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Tests for roundtrip serialization with {@link TagContextBinarySerializerImpl}. */ -@RunWith(JUnit4.class) -public class TagContextRoundtripTest { - - private static final TagKey K1 = TagKey.create("k1"); - private static final TagKey K2 = TagKey.create("k2"); - private static final TagKey K3 = TagKey.create("k3"); - - private static final TagValue V_EMPTY = TagValue.create(""); - private static final TagValue V1 = TagValue.create("v1"); - private static final TagValue V2 = TagValue.create("v2"); - private static final TagValue V3 = TagValue.create("v3"); - - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - private final TagContextBinarySerializer serializer = - tagsComponent.getTagPropagationComponent().getBinarySerializer(); - private final Tagger tagger = tagsComponent.getTagger(); - - @Test - public void testRoundtripSerialization() throws Exception { - testRoundtripSerialization(tagger.empty()); - testRoundtripSerialization(tagger.emptyBuilder().put(K1, V1).build()); - testRoundtripSerialization(tagger.emptyBuilder().put(K1, V1).put(K2, V2).put(K3, V3).build()); - testRoundtripSerialization(tagger.emptyBuilder().put(K1, V_EMPTY).build()); - } - - private void testRoundtripSerialization(TagContext expected) throws Exception { - byte[] bytes = serializer.toByteArray(expected); - TagContext actual = serializer.fromByteArray(bytes); - assertThat(actual).isEqualTo(expected); - } -} diff --git a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java b/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java deleted file mode 100644 index 6227fe54..00000000 --- a/core_impl/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.implcore.tags.propagation; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.base.Charsets; -import com.google.common.collect.Collections2; -import io.opencensus.implcore.internal.VarInt; -import io.opencensus.implcore.tags.TagsComponentImplBase; -import io.opencensus.tags.Tag; -import io.opencensus.tags.TagContextBuilder; -import io.opencensus.tags.TagKey; -import io.opencensus.tags.TagValue; -import io.opencensus.tags.Tagger; -import io.opencensus.tags.TagsComponent; -import io.opencensus.tags.propagation.TagContextBinarySerializer; -import io.opencensus.tags.propagation.TagContextSerializationException; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Tests for serializing tags with {@link SerializationUtils} and {@link - * TagContextBinarySerializerImpl}. - */ -@RunWith(JUnit4.class) -public class TagContextSerializationTest { - - private static final int VERSION_ID = 0; - private static final int TAG_FIELD_ID = 0; - - private static final TagKey K1 = TagKey.create("k1"); - private static final TagKey K2 = TagKey.create("k2"); - private static final TagKey K3 = TagKey.create("k3"); - private static final TagKey K4 = TagKey.create("k4"); - - private static final TagValue V1 = TagValue.create("v1"); - private static final TagValue V2 = TagValue.create("v2"); - private static final TagValue V3 = TagValue.create("v3"); - private static final TagValue V4 = TagValue.create("v4"); - - private static final Tag T1 = Tag.create(K1, V1); - private static final Tag T2 = Tag.create(K2, V2); - private static final Tag T3 = Tag.create(K3, V3); - private static final Tag T4 = Tag.create(K4, V4); - - private final TagsComponent tagsComponent = new TagsComponentImplBase(); - private final TagContextBinarySerializer serializer = - tagsComponent.getTagPropagationComponent().getBinarySerializer(); - private final Tagger tagger = tagsComponent.getTagger(); - - @Test - public void testSerializeDefault() throws Exception { - testSerialize(); - } - - @Test - public void testSerializeWithOneTag() throws Exception { - testSerialize(T1); - } - - @Test - public void testSerializeWithMultipleTags() throws Exception { - testSerialize(T1, T2, T3, T4); - } - - private void testSerialize(Tag... tags) throws IOException, TagContextSerializationException { - TagContextBuilder builder = tagger.emptyBuilder(); - for (Tag tag : tags) { - builder.put(tag.getKey(), tag.getValue()); - } - - byte[] actual = serializer.toByteArray(builder.build()); - - Collection> tagPermutation = Collections2.permutations(Arrays.asList(tags)); - Set possibleOutputs = new HashSet(); - for (List list : tagPermutation) { - ByteArrayOutputStream expected = new ByteArrayOutputStream(); - expected.write(VERSION_ID); - for (Tag tag : list) { - expected.write(TAG_FIELD_ID); - encodeString(tag.getKey().getName(), expected); - encodeString(tag.getValue().asString(), expected); - } - possibleOutputs.add(expected.toString()); - } - - assertThat(possibleOutputs).contains(new String(actual, Charsets.UTF_8)); - } - - private static void encodeString(String input, ByteArrayOutputStream byteArrayOutputStream) - throws IOException { - VarInt.putVarInt(input.length(), byteArrayOutputStream); - byteArrayOutputStream.write(input.getBytes(Charsets.UTF_8)); - } -} diff --git a/core_impl_android/README.md b/core_impl_android/README.md deleted file mode 100644 index f7ec5cdd..00000000 --- a/core_impl_android/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Will be ported to io.opencensus soon in impl_lite/. -====================================================== - -* Android compatible. -* StatsManager specifies the stats implementation classes that should be used - with Android. diff --git a/core_impl_android/build.gradle b/core_impl_android/build.gradle deleted file mode 100644 index 2d48b7bf..00000000 --- a/core_impl_android/build.gradle +++ /dev/null @@ -1,12 +0,0 @@ -description = 'OpenCensus Core Impl Android' - -dependencies { - compile project(':core_impl') - - testCompile project(':core_impl'), - project(':opencensus-api'), - project(':opencensus-impl-core'), - project(':opencensus-impl-lite') - - signature "net.sf.androidscents.signature:android-api-level-14:+@signature" -} diff --git a/core_impl_android/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java b/core_impl_android/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java deleted file mode 100644 index a58a9d3e..00000000 --- a/core_impl_android/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impllite.stats; - -import io.opencensus.implcore.common.MillisClock; -import io.opencensus.implcore.internal.SimpleEventQueue; -import io.opencensus.implcore.stats.StatsComponentImplBase; -import io.opencensus.stats.StatsComponent; - -/** Android-compatible implementation of {@link StatsComponent}. */ -public final class StatsComponentImplLite extends StatsComponentImplBase { - - public StatsComponentImplLite() { - // TODO(sebright): Use a more efficient queue implementation. - super(new SimpleEventQueue(), MillisClock.getInstance()); - } -} diff --git a/core_impl_android/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java b/core_impl_android/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java deleted file mode 100644 index dc0d900c..00000000 --- a/core_impl_android/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impllite.tags; - -import io.opencensus.implcore.tags.TagsComponentImplBase; -import io.opencensus.tags.TagsComponent; - -/** Android-compatible implementation of {@link TagsComponent}. */ -public final class TagsComponentImplLite extends TagsComponentImplBase {} diff --git a/core_impl_android/src/test/java/io/opencensus/impllite/stats/StatsTest.java b/core_impl_android/src/test/java/io/opencensus/impllite/stats/StatsTest.java deleted file mode 100644 index 313f8916..00000000 --- a/core_impl_android/src/test/java/io/opencensus/impllite/stats/StatsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impllite.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.implcore.stats.StatsRecorderImpl; -import io.opencensus.implcore.stats.ViewManagerImpl; -import io.opencensus.stats.Stats; -import io.opencensus.stats.StatsComponent; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test for accessing the {@link StatsComponent} through the {@link Stats} class. */ -@RunWith(JUnit4.class) -public final class StatsTest { - @Test - public void getStatsRecorder() { - assertThat(Stats.getStatsRecorder()).isInstanceOf(StatsRecorderImpl.class); - } - - @Test - public void getViewManager() { - assertThat(Stats.getViewManager()).isInstanceOf(ViewManagerImpl.class); - } -} diff --git a/core_impl_android/src/test/java/io/opencensus/impllite/tags/TagsTest.java b/core_impl_android/src/test/java/io/opencensus/impllite/tags/TagsTest.java deleted file mode 100644 index 890cdb15..00000000 --- a/core_impl_android/src/test/java/io/opencensus/impllite/tags/TagsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impllite.tags; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.implcore.tags.TaggerImpl; -import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl; -import io.opencensus.tags.Tags; -import io.opencensus.tags.TagsComponent; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test for accessing the {@link TagsComponent} through the {@link Tags} class. */ -@RunWith(JUnit4.class) -public final class TagsTest { - @Test - public void getTagger() { - assertThat(Tags.getTagger()).isInstanceOf(TaggerImpl.class); - } - - @Test - public void getTagContextSerializer() { - assertThat(Tags.getTagPropagationComponent()).isInstanceOf(TagPropagationComponentImpl.class); - } -} diff --git a/core_impl_java/README.md b/core_impl_java/README.md deleted file mode 100644 index 0a33eee1..00000000 --- a/core_impl_java/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Will be ported to io.opencensus soon in impl/. -====================================================== - -* Java 7 compatible. -* Contains any classes not compatible with Android. diff --git a/core_impl_java/build.gradle b/core_impl_java/build.gradle deleted file mode 100644 index 3370511a..00000000 --- a/core_impl_java/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -description = 'OpenCensus Core Impl Java' - -apply plugin: 'java' - -[compileJava, compileTestJava].each() { - it.sourceCompatibility = 1.7 - it.targetCompatibility = 1.7 -} - -dependencies { - compile project(':core_impl'), - project(':opencensus-impl') - - testCompile project(':core_impl'), - project(':opencensus-api'), - project(':opencensus-impl-core'), - project(':opencensus-impl') - - signature "org.codehaus.mojo.signature:java17:+@signature" -} diff --git a/core_impl_java/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java b/core_impl_java/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java deleted file mode 100644 index 6b9fe69a..00000000 --- a/core_impl_java/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impl.stats; - -import io.opencensus.impl.internal.DisruptorEventQueue; -import io.opencensus.implcore.common.MillisClock; -import io.opencensus.implcore.stats.StatsComponentImplBase; -import io.opencensus.stats.StatsComponent; - -/** Java 7 and 8 implementation of {@link StatsComponent}. */ -public final class StatsComponentImpl extends StatsComponentImplBase { - - /** Public constructor to be used with reflection loading. */ - public StatsComponentImpl() { - super(DisruptorEventQueue.getInstance(), MillisClock.getInstance()); - } -} diff --git a/core_impl_java/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java b/core_impl_java/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java deleted file mode 100644 index 8dd1f373..00000000 --- a/core_impl_java/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impl.tags; - -import io.opencensus.implcore.tags.TagsComponentImplBase; -import io.opencensus.tags.TagsComponent; - -/** Java 7 and 8 implementation of {@link TagsComponent}. */ -public final class TagsComponentImpl extends TagsComponentImplBase {} diff --git a/core_impl_java/src/test/java/io/opencensus/impl/stats/StatsTest.java b/core_impl_java/src/test/java/io/opencensus/impl/stats/StatsTest.java deleted file mode 100644 index 23606a48..00000000 --- a/core_impl_java/src/test/java/io/opencensus/impl/stats/StatsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2016-17, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impl.stats; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.implcore.stats.StatsRecorderImpl; -import io.opencensus.implcore.stats.ViewManagerImpl; -import io.opencensus.stats.Stats; -import io.opencensus.stats.StatsComponent; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test for accessing the {@link StatsComponent} through the {@link Stats} class. */ -@RunWith(JUnit4.class) -public final class StatsTest { - @Test - public void getStatsRecorder() { - assertThat(Stats.getStatsRecorder()).isInstanceOf(StatsRecorderImpl.class); - } - - @Test - public void getViewManager() { - assertThat(Stats.getViewManager()).isInstanceOf(ViewManagerImpl.class); - } -} diff --git a/core_impl_java/src/test/java/io/opencensus/impl/tags/TagsTest.java b/core_impl_java/src/test/java/io/opencensus/impl/tags/TagsTest.java deleted file mode 100644 index e94cf254..00000000 --- a/core_impl_java/src/test/java/io/opencensus/impl/tags/TagsTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2017, OpenCensus Authors - * - * 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 - * - * http://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.opencensus.impl.tags; - -import static com.google.common.truth.Truth.assertThat; - -import io.opencensus.implcore.tags.TaggerImpl; -import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl; -import io.opencensus.tags.Tags; -import io.opencensus.tags.TagsComponent; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test for accessing the {@link TagsComponent} through the {@link Tags} class. */ -@RunWith(JUnit4.class) -public final class TagsTest { - @Test - public void getTagger() { - assertThat(Tags.getTagger()).isInstanceOf(TaggerImpl.class); - } - - @Test - public void getTagContextSerializer() { - assertThat(Tags.getTagPropagationComponent()).isInstanceOf(TagPropagationComponentImpl.class); - } -} diff --git a/examples/build.gradle b/examples/build.gradle index c56c616c..b4bb6fa5 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -10,8 +10,7 @@ dependencies { project(':opencensus-contrib-zpages'), project(':opencensus-exporter-trace-logging') - runtime project(':core_impl_java'), - project(':opencensus-impl') + runtime project(':opencensus-impl') } // Provide convenience executables for trying out the examples. diff --git a/impl/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java b/impl/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java new file mode 100644 index 00000000..6b9fe69a --- /dev/null +++ b/impl/src/main/java/io/opencensus/impl/stats/StatsComponentImpl.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impl.stats; + +import io.opencensus.impl.internal.DisruptorEventQueue; +import io.opencensus.implcore.common.MillisClock; +import io.opencensus.implcore.stats.StatsComponentImplBase; +import io.opencensus.stats.StatsComponent; + +/** Java 7 and 8 implementation of {@link StatsComponent}. */ +public final class StatsComponentImpl extends StatsComponentImplBase { + + /** Public constructor to be used with reflection loading. */ + public StatsComponentImpl() { + super(DisruptorEventQueue.getInstance(), MillisClock.getInstance()); + } +} diff --git a/impl/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java b/impl/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java new file mode 100644 index 00000000..8dd1f373 --- /dev/null +++ b/impl/src/main/java/io/opencensus/impl/tags/TagsComponentImpl.java @@ -0,0 +1,23 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impl.tags; + +import io.opencensus.implcore.tags.TagsComponentImplBase; +import io.opencensus.tags.TagsComponent; + +/** Java 7 and 8 implementation of {@link TagsComponent}. */ +public final class TagsComponentImpl extends TagsComponentImplBase {} diff --git a/impl/src/test/java/io/opencensus/impl/stats/StatsTest.java b/impl/src/test/java/io/opencensus/impl/stats/StatsTest.java new file mode 100644 index 00000000..23606a48 --- /dev/null +++ b/impl/src/test/java/io/opencensus/impl/stats/StatsTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impl.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.implcore.stats.StatsRecorderImpl; +import io.opencensus.implcore.stats.ViewManagerImpl; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsComponent; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test for accessing the {@link StatsComponent} through the {@link Stats} class. */ +@RunWith(JUnit4.class) +public final class StatsTest { + @Test + public void getStatsRecorder() { + assertThat(Stats.getStatsRecorder()).isInstanceOf(StatsRecorderImpl.class); + } + + @Test + public void getViewManager() { + assertThat(Stats.getViewManager()).isInstanceOf(ViewManagerImpl.class); + } +} diff --git a/impl/src/test/java/io/opencensus/impl/tags/TagsTest.java b/impl/src/test/java/io/opencensus/impl/tags/TagsTest.java new file mode 100644 index 00000000..e94cf254 --- /dev/null +++ b/impl/src/test/java/io/opencensus/impl/tags/TagsTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impl.tags; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.implcore.tags.TaggerImpl; +import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl; +import io.opencensus.tags.Tags; +import io.opencensus.tags.TagsComponent; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test for accessing the {@link TagsComponent} through the {@link Tags} class. */ +@RunWith(JUnit4.class) +public final class TagsTest { + @Test + public void getTagger() { + assertThat(Tags.getTagger()).isInstanceOf(TaggerImpl.class); + } + + @Test + public void getTagContextSerializer() { + assertThat(Tags.getTagPropagationComponent()).isInstanceOf(TagPropagationComponentImpl.class); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java b/impl_core/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java new file mode 100644 index 00000000..88a1f79a --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/CurrentStatsState.java @@ -0,0 +1,61 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.StatsComponent; +import javax.annotation.concurrent.GuardedBy; +import javax.annotation.concurrent.ThreadSafe; + +/** + * The current {@link StatsCollectionState} for a {@link StatsComponent}. + * + *

This class allows different stats classes to share the state in a thread-safe way. + */ +@ThreadSafe +public final class CurrentStatsState { + + @GuardedBy("this") + private StatsCollectionState currentState = StatsCollectionState.ENABLED; + + @GuardedBy("this") + private boolean isRead; + + public synchronized StatsCollectionState get() { + isRead = true; + return getInternal(); + } + + synchronized StatsCollectionState getInternal() { + return currentState; + } + + // Sets current state to the given state. Returns true if the current state is changed, false + // otherwise. + synchronized boolean set(StatsCollectionState state) { + checkState(!isRead, "State was already read, cannot set state."); + if (state == currentState) { + return false; + } else { + currentState = checkNotNull(state, "state"); + return true; + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java b/impl_core/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java new file mode 100644 index 00000000..68380791 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/IntervalBucket.java @@ -0,0 +1,86 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static io.opencensus.implcore.stats.MutableViewData.toMillis; + +import com.google.common.collect.Maps; +import io.opencensus.common.Duration; +import io.opencensus.common.Timestamp; +import io.opencensus.stats.Aggregation; +import io.opencensus.tags.TagValue; +import java.util.List; +import java.util.Map; + +/** The bucket with aggregated {@code MeasureValue}s used for {@code IntervalViewData}. */ +final class IntervalBucket { + + private static final Duration ZERO = Duration.create(0, 0); + + private final Timestamp start; + private final Duration duration; + private final Aggregation aggregation; + private final Map, MutableAggregation> tagValueAggregationMap = Maps.newHashMap(); + + IntervalBucket(Timestamp start, Duration duration, Aggregation aggregation) { + checkNotNull(start, "Start"); + checkNotNull(duration, "Duration"); + checkArgument(duration.compareTo(ZERO) > 0, "Duration must be positive"); + checkNotNull(aggregation, "Aggregation"); + this.start = start; + this.duration = duration; + this.aggregation = aggregation; + } + + Map, MutableAggregation> getTagValueAggregationMap() { + return tagValueAggregationMap; + } + + Timestamp getStart() { + return start; + } + + // Puts a new value into the internal MutableAggregations, based on the TagValues. + void record(List tagValues, double value) { + if (!tagValueAggregationMap.containsKey(tagValues)) { + tagValueAggregationMap.put(tagValues, MutableViewData.createMutableAggregation(aggregation)); + } + tagValueAggregationMap.get(tagValues).add(value); + } + + /* + * Returns how much fraction of duration has passed in this IntervalBucket. For example, if this + * bucket starts at 10s and has a duration of 20s, and now is 15s, then getFraction() should + * return (15 - 10) / 20 = 0.25. + * + * This IntervalBucket must be current, i.e. the current timestamp must be within + * [this.start, this.start + this.duration). + */ + double getFraction(Timestamp now) { + Duration elapsedTime = now.subtractTimestamp(start); + checkArgument( + elapsedTime.compareTo(ZERO) >= 0 && elapsedTime.compareTo(duration) < 0, + "This bucket must be current."); + return ((double) toMillis(elapsedTime)) / toMillis(duration); + } + + void clearStats() { + tagValueAggregationMap.clear(); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java b/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java new file mode 100644 index 00000000..a156747f --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapImpl.java @@ -0,0 +1,60 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.stats.MeasureMap; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.unsafe.ContextUtils; + +/** Implementation of {@link MeasureMap}. */ +final class MeasureMapImpl extends MeasureMap { + private final StatsManager statsManager; + private final MeasureMapInternal.Builder builder = MeasureMapInternal.builder(); + + static MeasureMapImpl create(StatsManager statsManager) { + return new MeasureMapImpl(statsManager); + } + + private MeasureMapImpl(StatsManager statsManager) { + this.statsManager = statsManager; + } + + @Override + public MeasureMapImpl put(MeasureDouble measure, double value) { + builder.put(measure, value); + return this; + } + + @Override + public MeasureMapImpl put(MeasureLong measure, long value) { + builder.put(measure, value); + return this; + } + + @Override + public void record() { + // Use the context key directly, to avoid depending on the tags implementation. + record(ContextUtils.TAG_CONTEXT_KEY.get()); + } + + @Override + public void record(TagContext tags) { + statsManager.record(tags, builder.build()); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java b/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java new file mode 100644 index 00000000..c68b4aff --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureMapInternal.java @@ -0,0 +1,122 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import io.opencensus.stats.Measure; +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.stats.Measurement; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; + +// TODO(songya): consider combining MeasureMapImpl and this class. +/** A map from {@link Measure}'s to measured values. */ +final class MeasureMapInternal { + + /** Returns a {@link Builder} for the {@link MeasureMapInternal} class. */ + static Builder builder() { + return new Builder(); + } + + /** + * Returns an {@link Iterator} over the measure/value mappings in this {@link MeasureMapInternal}. + * The {@code Iterator} does not support {@link Iterator#remove()}. + */ + Iterator iterator() { + return new MeasureMapInternalIterator(); + } + + private final ArrayList measurements; + + private MeasureMapInternal(ArrayList measurements) { + this.measurements = measurements; + } + + /** Builder for the {@link MeasureMapInternal} class. */ + static class Builder { + /** + * Associates the {@link MeasureDouble} with the given value. Subsequent updates to the same + * {@link MeasureDouble} will overwrite the previous value. + * + * @param measure the {@link MeasureDouble} + * @param value the value to be associated with {@code measure} + * @return this + */ + Builder put(MeasureDouble measure, double value) { + measurements.add(Measurement.MeasurementDouble.create(measure, value)); + return this; + } + + /** + * Associates the {@link MeasureLong} with the given value. Subsequent updates to the same + * {@link MeasureLong} will overwrite the previous value. + * + * @param measure the {@link MeasureLong} + * @param value the value to be associated with {@code measure} + * @return this + */ + Builder put(MeasureLong measure, long value) { + measurements.add(Measurement.MeasurementLong.create(measure, value)); + return this; + } + + /** Constructs a {@link MeasureMapInternal} from the current measurements. */ + MeasureMapInternal build() { + // Note: this makes adding measurements quadratic but is fastest for the sizes of + // MeasureMapInternals that we should see. We may want to go to a strategy of sort/eliminate + // for larger MeasureMapInternals. + for (int i = measurements.size() - 1; i >= 0; i--) { + for (int j = i - 1; j >= 0; j--) { + if (measurements.get(i).getMeasure() == measurements.get(j).getMeasure()) { + measurements.remove(j); + j--; + } + } + } + return new MeasureMapInternal(measurements); + } + + private final ArrayList measurements = new ArrayList(); + + private Builder() {} + } + + // Provides an unmodifiable Iterator over this instance's measurements. + private final class MeasureMapInternalIterator implements Iterator { + @Override + public boolean hasNext() { + return position < length; + } + + @Override + public Measurement next() { + if (position >= measurements.size()) { + throw new NoSuchElementException(); + } + return measurements.get(position++); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + private final int length = measurements.size(); + private int position = 0; + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java b/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java new file mode 100644 index 00000000..50cb236a --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MeasureToViewMap.java @@ -0,0 +1,185 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import io.opencensus.common.Clock; +import io.opencensus.common.Function; +import io.opencensus.common.Functions; +import io.opencensus.common.Timestamp; +import io.opencensus.stats.Measure; +import io.opencensus.stats.Measurement; +import io.opencensus.stats.Measurement.MeasurementDouble; +import io.opencensus.stats.Measurement.MeasurementLong; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.View; +import io.opencensus.stats.ViewData; +import io.opencensus.tags.TagContext; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import javax.annotation.Nullable; +import javax.annotation.concurrent.GuardedBy; + +/** A class that stores a singleton map from {@code MeasureName}s to {@link MutableViewData}s. */ +final class MeasureToViewMap { + + /* + * A synchronized singleton map that stores the one-to-many mapping from Measures + * to MutableViewDatas. + */ + @GuardedBy("this") + private final Multimap mutableMap = + HashMultimap.create(); + + @GuardedBy("this") + private final Map registeredViews = new HashMap(); + + // TODO(songya): consider adding a Measure.Name class + @GuardedBy("this") + private final Map registeredMeasures = Maps.newHashMap(); + + /** Returns a {@link ViewData} corresponding to the given {@link View.Name}. */ + synchronized ViewData getView(View.Name viewName, Clock clock, StatsCollectionState state) { + MutableViewData view = getMutableViewData(viewName); + return view == null ? null : view.toViewData(clock.now(), state); + } + + @Nullable + private synchronized MutableViewData getMutableViewData(View.Name viewName) { + View view = registeredViews.get(viewName); + if (view == null) { + return null; + } + Collection views = mutableMap.get(view.getMeasure().getName()); + for (MutableViewData viewData : views) { + if (viewData.getView().getName().equals(viewName)) { + return viewData; + } + } + throw new AssertionError( + "Internal error: Not recording stats for view: \"" + + viewName + + "\" registeredViews=" + + registeredViews + + ", mutableMap=" + + mutableMap); + } + + /** Enable stats collection for the given {@link View}. */ + synchronized void registerView(View view, Clock clock) { + View existing = registeredViews.get(view.getName()); + if (existing != null) { + if (existing.equals(view)) { + // Ignore views that are already registered. + return; + } else { + throw new IllegalArgumentException( + "A different view with the same name is already registered: " + existing); + } + } + Measure measure = view.getMeasure(); + Measure registeredMeasure = registeredMeasures.get(measure.getName()); + if (registeredMeasure != null && !registeredMeasure.equals(measure)) { + throw new IllegalArgumentException( + "A different measure with the same name is already registered: " + registeredMeasure); + } + registeredViews.put(view.getName(), view); + if (registeredMeasure == null) { + registeredMeasures.put(measure.getName(), measure); + } + mutableMap.put(view.getMeasure().getName(), MutableViewData.create(view, clock.now())); + } + + // Records stats with a set of tags. + synchronized void record(TagContext tags, MeasureMapInternal stats, Timestamp timestamp) { + Iterator iterator = stats.iterator(); + while (iterator.hasNext()) { + Measurement measurement = iterator.next(); + Measure measure = measurement.getMeasure(); + if (!measure.equals(registeredMeasures.get(measure.getName()))) { + // unregistered measures will be ignored. + return; + } + Collection views = mutableMap.get(measure.getName()); + for (MutableViewData view : views) { + measurement.match( + new RecordDoubleValueFunc(tags, view, timestamp), + new RecordLongValueFunc(tags, view, timestamp), + Functions.throwAssertionError()); + } + } + } + + // Clear stats for all the current MutableViewData + synchronized void clearStats() { + for (Entry> entry : mutableMap.asMap().entrySet()) { + for (MutableViewData mutableViewData : entry.getValue()) { + mutableViewData.clearStats(); + } + } + } + + // Resume stats collection for all MutableViewData. + synchronized void resumeStatsCollection(Timestamp now) { + for (Entry> entry : mutableMap.asMap().entrySet()) { + for (MutableViewData mutableViewData : entry.getValue()) { + mutableViewData.resumeStatsCollection(now); + } + } + } + + private static final class RecordDoubleValueFunc implements Function { + @Override + public Void apply(MeasurementDouble arg) { + view.record(tags, arg.getValue(), timestamp); + return null; + } + + private final TagContext tags; + private final MutableViewData view; + private final Timestamp timestamp; + + private RecordDoubleValueFunc(TagContext tags, MutableViewData view, Timestamp timestamp) { + this.tags = tags; + this.view = view; + this.timestamp = timestamp; + } + } + + private static final class RecordLongValueFunc implements Function { + @Override + public Void apply(MeasurementLong arg) { + view.record(tags, arg.getValue(), timestamp); + return null; + } + + private final TagContext tags; + private final MutableViewData view; + private final Timestamp timestamp; + + private RecordLongValueFunc(TagContext tags, MutableViewData view, Timestamp timestamp) { + this.tags = tags; + this.view = view; + this.timestamp = timestamp; + } + } +} 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 new file mode 100644 index 00000000..deabdce7 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MutableAggregation.java @@ -0,0 +1,361 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.common.Function; +import io.opencensus.stats.Aggregation; +import io.opencensus.stats.BucketBoundaries; + +/** Mutable version of {@link Aggregation} that supports adding values. */ +abstract class MutableAggregation { + + private MutableAggregation() {} + + // Tolerance for double comparison. + private static final double TOLERANCE = 1e-6; + + /** + * Put a new value into the MutableAggregation. + * + * @param value new value to be added to population + */ + abstract void add(double value); + + /** + * Combine the internal values of this MutableAggregation and value of the given + * MutableAggregation, with the given fraction. Then set the internal value of this + * MutableAggregation to the combined value. + * + * @param other the other {@code MutableAggregation}. The type of this and other {@code + * MutableAggregation} must match. + * @param fraction the fraction that the value in other {@code MutableAggregation} should + * contribute. Must be within [0.0, 1.0]. + */ + abstract void combine(MutableAggregation other, double fraction); + + /** Applies the given match function to the underlying data type. */ + abstract T match( + Function p0, + Function p1, + Function p2, + Function p3); + + /** Calculate sum on aggregated {@code MeasureValue}s. */ + static final class MutableSum extends MutableAggregation { + + private double sum = 0.0; + + private MutableSum() {} + + /** + * Construct a {@code MutableSum}. + * + * @return an empty {@code MutableSum}. + */ + static MutableSum create() { + return new MutableSum(); + } + + @Override + void add(double value) { + sum += value; + } + + @Override + void combine(MutableAggregation other, double fraction) { + checkArgument(other instanceof MutableSum, "MutableSum expected."); + this.sum += fraction * ((MutableSum) other).getSum(); + } + + /** + * Returns the aggregated sum. + * + * @return the aggregated sum. + */ + double getSum() { + return sum; + } + + @Override + final T match( + Function p0, + Function p1, + Function p2, + Function p3) { + return p0.apply(this); + } + } + + /** Calculate count on aggregated {@code MeasureValue}s. */ + static final class MutableCount extends MutableAggregation { + + private long count = 0; + + private MutableCount() {} + + /** + * Construct a {@code MutableCount}. + * + * @return an empty {@code MutableCount}. + */ + static MutableCount create() { + return new MutableCount(); + } + + @Override + void add(double value) { + count++; + } + + @Override + void combine(MutableAggregation other, double fraction) { + checkArgument(other instanceof MutableCount, "MutableCount expected."); + this.count += Math.round(fraction * ((MutableCount) other).getCount()); + } + + /** + * Returns the aggregated count. + * + * @return the aggregated count. + */ + long getCount() { + return count; + } + + @Override + final T match( + Function p0, + Function p1, + Function p2, + Function p3) { + return p1.apply(this); + } + } + + /** Calculate mean on aggregated {@code MeasureValue}s. */ + static final class MutableMean extends MutableAggregation { + + private double sum = 0.0; + private long count = 0; + + private MutableMean() {} + + /** + * Construct a {@code MutableMean}. + * + * @return an empty {@code MutableMean}. + */ + static MutableMean create() { + return new MutableMean(); + } + + @Override + void add(double value) { + count++; + sum += value; + } + + @Override + void combine(MutableAggregation other, double fraction) { + checkArgument(other instanceof MutableMean, "MutableMean expected."); + MutableMean mutableMean = (MutableMean) other; + this.count += Math.round(mutableMean.count * fraction); + this.sum += mutableMean.sum * fraction; + } + + /** + * Returns the aggregated mean. + * + * @return the aggregated mean. + */ + double getMean() { + return getCount() == 0 ? 0 : getSum() / getCount(); + } + + /** + * Returns the aggregated count. + * + * @return the aggregated count. + */ + long getCount() { + return count; + } + + /** + * Returns the aggregated sum. + * + * @return the aggregated sum. + */ + double getSum() { + return sum; + } + + @Override + final T match( + Function p0, + Function p1, + Function p2, + Function p3) { + return p2.apply(this); + } + } + + /** Calculate distribution stats on aggregated {@code MeasureValue}s. */ + static final class MutableDistribution extends MutableAggregation { + + private double sum = 0.0; + private double mean = 0.0; + private long count = 0; + private double sumOfSquaredDeviations = 0.0; + + // Initial "impossible" values, that will get reset as soon as first value is added. + private double min = Double.POSITIVE_INFINITY; + private double max = Double.NEGATIVE_INFINITY; + + private final BucketBoundaries bucketBoundaries; + private final long[] bucketCounts; + + private MutableDistribution(BucketBoundaries bucketBoundaries) { + this.bucketBoundaries = bucketBoundaries; + this.bucketCounts = new long[bucketBoundaries.getBoundaries().size() + 1]; + } + + /** + * Construct a {@code MutableDistribution}. + * + * @return an empty {@code MutableDistribution}. + */ + static MutableDistribution create(BucketBoundaries bucketBoundaries) { + checkNotNull(bucketBoundaries, "bucketBoundaries should not be null."); + return new MutableDistribution(bucketBoundaries); + } + + @Override + void add(double value) { + sum += value; + count++; + + /* + * Update the sum of squared deviations from the mean with the given value. For values + * x_i this is Sum[i=1..n]((x_i - mean)^2) + * + * Computed using Welfords method (see + * https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance, or Knuth, "The Art of + * Computer Programming", Vol. 2, page 323, 3rd edition) + */ + double deltaFromMean = value - mean; + mean += deltaFromMean / count; + double deltaFromMean2 = value - mean; + sumOfSquaredDeviations += deltaFromMean * deltaFromMean2; + + if (value < min) { + min = value; + } + if (value > max) { + max = value; + } + + for (int i = 0; i < bucketBoundaries.getBoundaries().size(); i++) { + if (value < bucketBoundaries.getBoundaries().get(i)) { + bucketCounts[i]++; + return; + } + } + bucketCounts[bucketCounts.length - 1]++; + } + + // We don't compute fractional MutableDistribution, it's either whole or none. + @Override + void combine(MutableAggregation other, double fraction) { + checkArgument(other instanceof MutableDistribution, "MutableDistribution expected."); + if (Math.abs(1.0 - fraction) > TOLERANCE) { + return; + } + + MutableDistribution mutableDistribution = (MutableDistribution) other; + checkArgument( + this.bucketBoundaries.equals(mutableDistribution.bucketBoundaries), + "Bucket boundaries should match."); + + // Algorithm for calculating the combination of sum of squared deviations: + // https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm. + if (this.count + mutableDistribution.count > 0) { + double delta = mutableDistribution.mean - this.mean; + this.sumOfSquaredDeviations = + this.sumOfSquaredDeviations + + mutableDistribution.sumOfSquaredDeviations + + Math.pow(delta, 2) + * this.count + * mutableDistribution.count + / (this.count + mutableDistribution.count); + } + + this.count += mutableDistribution.count; + this.sum += mutableDistribution.sum; + this.mean = this.sum / this.count; + + if (mutableDistribution.min < this.min) { + this.min = mutableDistribution.min; + } + if (mutableDistribution.max > this.max) { + this.max = mutableDistribution.max; + } + + long[] bucketCounts = mutableDistribution.getBucketCounts(); + for (int i = 0; i < bucketCounts.length; i++) { + this.bucketCounts[i] += bucketCounts[i]; + } + } + + double getMean() { + return mean; + } + + long getCount() { + return count; + } + + double getMin() { + return min; + } + + double getMax() { + return max; + } + + // Returns the aggregated sum of squared deviations. + double getSumOfSquaredDeviations() { + return sumOfSquaredDeviations; + } + + long[] getBucketCounts() { + return bucketCounts; + } + + @Override + final T match( + Function p0, + Function p1, + Function p2, + Function p3) { + return p3.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 new file mode 100644 index 00000000..1347a721 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/MutableViewData.java @@ -0,0 +1,588 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.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.Maps; +import com.google.common.collect.Multimap; +import io.opencensus.common.Duration; +import io.opencensus.common.Function; +import io.opencensus.common.Functions; +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.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.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.MeanData; +import io.opencensus.stats.AggregationData.SumDataDouble; +import io.opencensus.stats.AggregationData.SumDataLong; +import io.opencensus.stats.Measure; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.View; +import io.opencensus.stats.View.AggregationWindow.Cumulative; +import io.opencensus.stats.View.AggregationWindow.Interval; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; +import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData; +import io.opencensus.tags.InternalUtils; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** A mutable version of {@link ViewData}, used for recording stats and start/end time. */ +abstract class MutableViewData { + + private static final long MILLIS_PER_SECOND = 1000L; + private static final long NANOS_PER_MILLI = 1000 * 1000; + + @VisibleForTesting static final TagValue UNKNOWN_TAG_VALUE = null; + @VisibleForTesting static final Timestamp ZERO_TIMESTAMP = Timestamp.create(0, 0); + + private final View view; + + private MutableViewData(View view) { + this.view = view; + } + + /** + * Constructs a new {@link MutableViewData}. + * + * @param view the {@code View} linked with this {@code MutableViewData}. + * @param start the start {@code Timestamp}. + * @return a {@code MutableViewData}. + */ + static MutableViewData create(final View view, final Timestamp start) { + return view.getWindow() + .match( + new CreateCumulative(view, start), + new CreateInterval(view, start), + Functions.throwAssertionError()); + } + + /** The {@link View} associated with this {@link ViewData}. */ + View getView() { + return view; + } + + /** Record double stats with the given tags. */ + abstract void record(TagContext context, double value, Timestamp timestamp); + + /** Record long stats with the given tags. */ + void record(TagContext tags, long value, Timestamp timestamp) { + // TODO(songya): shall we check for precision loss here? + record(tags, (double) value, timestamp); + } + + /** Convert this {@link MutableViewData} to {@link ViewData}. */ + abstract ViewData toViewData(Timestamp now, StatsCollectionState state); + + // Clear recorded stats. + abstract void clearStats(); + + // Resume stats collection, and reset Start Timestamp (for CumulativeMutableViewData), or refresh + // bucket list (for InternalMutableViewData). + abstract void resumeStatsCollection(Timestamp now); + + private static Map getTagMap(TagContext ctx) { + if (ctx instanceof TagContextImpl) { + return ((TagContextImpl) ctx).getTags(); + } else { + Map tags = Maps.newHashMap(); + for (Iterator i = InternalUtils.getTags(ctx); i.hasNext(); ) { + Tag tag = i.next(); + tags.put(tag.getKey(), tag.getValue()); + } + return tags; + } + } + + @VisibleForTesting + static List getTagValues( + Map tags, List columns) { + List tagValues = new ArrayList(columns.size()); + // Record all the measures in a "Greedy" way. + // Every view aggregates every measure. This is similar to doing a GROUPBY view’s keys. + for (int i = 0; i < columns.size(); ++i) { + TagKey tagKey = columns.get(i); + if (!tags.containsKey(tagKey)) { + // replace not found key values by “unknown/not set”. + tagValues.add(UNKNOWN_TAG_VALUE); + } else { + tagValues.add(tags.get(tagKey)); + } + } + return tagValues; + } + + // Returns the milliseconds representation of a Duration. + static long toMillis(Duration duration) { + return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos() / NANOS_PER_MILLI; + } + + /** + * Create an empty {@link MutableAggregation} based on the given {@link Aggregation}. + * + * @param aggregation {@code Aggregation}. + * @return an empty {@code MutableAggregation}. + */ + @VisibleForTesting + static MutableAggregation createMutableAggregation(Aggregation aggregation) { + return aggregation.match( + CreateMutableSum.INSTANCE, + CreateMutableCount.INSTANCE, + CreateMutableMean.INSTANCE, + CreateMutableDistribution.INSTANCE, + Functions.throwIllegalArgumentException()); + } + + /** + * Create an {@link AggregationData} snapshot based on the given {@link MutableAggregation}. + * + * @param aggregation {@code MutableAggregation} + * @param measure {@code Measure} + * @return an {@code AggregationData} which is the snapshot of current summary statistics. + */ + @VisibleForTesting + static AggregationData createAggregationData(MutableAggregation aggregation, Measure measure) { + return aggregation.match( + new CreateSumData(measure), + CreateCountData.INSTANCE, + CreateMeanData.INSTANCE, + CreateDistributionData.INSTANCE); + } + + // Covert a mapping from TagValues to MutableAggregation, to a mapping from TagValues to + // AggregationData. + private static Map createAggregationMap( + Map tagValueAggregationMap, Measure measure) { + Map map = Maps.newHashMap(); + for (Entry entry : tagValueAggregationMap.entrySet()) { + map.put(entry.getKey(), createAggregationData(entry.getValue(), measure)); + } + return map; + } + + private static final class CumulativeMutableViewData extends MutableViewData { + + private Timestamp start; + private final Map, MutableAggregation> tagValueAggregationMap = + Maps.newHashMap(); + + private CumulativeMutableViewData(View view, Timestamp start) { + super(view); + this.start = start; + } + + @Override + void record(TagContext context, double value, Timestamp timestamp) { + List tagValues = getTagValues(getTagMap(context), super.view.getColumns()); + if (!tagValueAggregationMap.containsKey(tagValues)) { + tagValueAggregationMap.put( + tagValues, createMutableAggregation(super.view.getAggregation())); + } + tagValueAggregationMap.get(tagValues).add(value); + } + + @Override + ViewData toViewData(Timestamp now, StatsCollectionState state) { + if (state == StatsCollectionState.ENABLED) { + return ViewData.create( + super.view, + createAggregationMap(tagValueAggregationMap, super.view.getMeasure()), + CumulativeData.create(start, now)); + } else { + // If Stats state is DISABLED, return an empty ViewData. + return ViewData.create( + super.view, + Collections., AggregationData>emptyMap(), + CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)); + } + } + + @Override + void clearStats() { + tagValueAggregationMap.clear(); + } + + @Override + void resumeStatsCollection(Timestamp now) { + start = now; + } + } + + /* + * For each IntervalView, we always keep a queue of N + 1 buckets (by default N is 4). + * Each bucket has a duration which is interval duration / N. + * Ideally: + * 1. the buckets should always be up-to-date, + * 2. current time should always be within the latest bucket, currently recorded stats should fall + * into the latest bucket, + * 3. there are always N buckets before the current one, which holds the stats in the past + * interval duration. + * + * When getView() is called, we will extract and combine the stats from the current and past + * buckets (part of the stats from the oldest bucket could have expired). + * + * However, in reality, we couldn't track the status of buckets all the time (keep monitoring and + * updating the bucket queue will be expensive). When we call record() or getView(), some or all + * of the buckets might be outdated, and we will need to "pad" new buckets to the queue and remove + * outdated ones. After refreshing buckets, the bucket queue will able to maintain the three + * invariants in the ideal situation. + * + * For example: + * 1. We have an IntervalView which has a duration of 8 seconds, we register this view at 10s. + * 2. Initially there will be 5 buckets: [2.0, 4.0), [4.0, 6.0), ..., [10.0, 12.0). + * 3. If users don't call record() or getView(), bucket queue will remain as it is, and some + * buckets could expire. + * 4. Suppose record() is called at 15s, now we need to refresh the bucket queue. We need to add + * two new buckets [12.0, 14.0) and [14.0, 16.0), and remove two expired buckets [2.0, 4.0) + * and [4.0, 6.0) + * 5. Suppose record() is called again at 30s, all the current buckets should have expired. We add + * 5 new buckets [22.0, 24.0) ... [30.0, 32.0) and remove all the previous buckets. + * 6. Suppose users call getView() at 35s, again we need to add two new buckets and remove two + * expired one, so that bucket queue is up-to-date. Now we combine stats from all buckets and + * return the combined IntervalViewData. + */ + private static final class IntervalMutableViewData extends MutableViewData { + + // TODO(songya): allow customizable bucket size in the future. + private static final int N = 4; // IntervalView has N + 1 buckets + + private final LinkedList buckets = new LinkedList(); + private final Duration totalDuration; // Duration of the whole interval. + private final Duration bucketDuration; // Duration of a single bucket (totalDuration / N) + + private IntervalMutableViewData(View view, Timestamp start) { + super(view); + Duration totalDuration = ((Interval) view.getWindow()).getDuration(); + this.totalDuration = totalDuration; + this.bucketDuration = Duration.fromMillis(toMillis(totalDuration) / N); + + // When initializing. add N empty buckets prior to the start timestamp of this + // IntervalMutableViewData, so that the last bucket will be the current one in effect. + shiftBucketList(N + 1, start); + } + + @Override + void record(TagContext context, double value, Timestamp timestamp) { + List tagValues = getTagValues(getTagMap(context), super.view.getColumns()); + refreshBucketList(timestamp); + // It is always the last bucket that does the recording. + buckets.peekLast().record(tagValues, value); + } + + @Override + ViewData toViewData(Timestamp now, StatsCollectionState state) { + refreshBucketList(now); + if (state == StatsCollectionState.ENABLED) { + return ViewData.create( + super.view, combineBucketsAndGetAggregationMap(now), IntervalData.create(now)); + } else { + // If Stats state is DISABLED, return an empty ViewData. + return ViewData.create( + super.view, + Collections., AggregationData>emptyMap(), + IntervalData.create(ZERO_TIMESTAMP)); + } + } + + @Override + void clearStats() { + for (IntervalBucket bucket : buckets) { + bucket.clearStats(); + } + } + + @Override + void resumeStatsCollection(Timestamp now) { + // Refresh bucket list to be ready for stats recording, so that if record() is called right + // after stats state is turned back on, record() will be faster. + refreshBucketList(now); + } + + // Add new buckets and remove expired buckets by comparing the current timestamp with + // timestamp of the last bucket. + private void refreshBucketList(Timestamp now) { + if (buckets.size() != N + 1) { + throw new AssertionError("Bucket list must have exactly " + (N + 1) + " buckets."); + } + Timestamp startOfLastBucket = buckets.peekLast().getStart(); + // TODO(songya): decide what to do when time goes backwards + checkArgument( + now.compareTo(startOfLastBucket) >= 0, + "Current time must be within or after the last bucket."); + long elapsedTimeMillis = toMillis(now.subtractTimestamp(startOfLastBucket)); + long numOfPadBuckets = elapsedTimeMillis / toMillis(bucketDuration); + + shiftBucketList(numOfPadBuckets, now); + } + + // Add specified number of new buckets, and remove expired buckets + private void shiftBucketList(long numOfPadBuckets, Timestamp now) { + Timestamp startOfNewBucket; + + if (!buckets.isEmpty()) { + startOfNewBucket = buckets.peekLast().getStart().addDuration(bucketDuration); + } else { + // Initialize bucket list. Should only enter this block once. + startOfNewBucket = subtractDuration(now, totalDuration); + } + + if (numOfPadBuckets > N + 1) { + // All current buckets expired, need to add N + 1 new buckets. The start time of the latest + // bucket will be current time. + startOfNewBucket = subtractDuration(now, totalDuration); + numOfPadBuckets = N + 1; + } + + for (int i = 0; i < numOfPadBuckets; i++) { + buckets.add( + new IntervalBucket(startOfNewBucket, bucketDuration, super.view.getAggregation())); + startOfNewBucket = startOfNewBucket.addDuration(bucketDuration); + } + + // removed expired buckets + while (buckets.size() > N + 1) { + buckets.pollFirst(); + } + } + + // Combine stats within each bucket, aggregate stats by tag values, and return the mapping from + // tag values to aggregation data. + private Map, AggregationData> combineBucketsAndGetAggregationMap(Timestamp now) { + Multimap, MutableAggregation> multimap = HashMultimap.create(); + LinkedList shallowCopy = new LinkedList(buckets); + Aggregation aggregation = super.view.getAggregation(); + putBucketsIntoMultiMap(shallowCopy, multimap, aggregation, now); + Map, MutableAggregation> singleMap = + aggregateOnEachTagValueList(multimap, aggregation); + return createAggregationMap(singleMap, super.getView().getMeasure()); + } + + // Put stats within each bucket to a multimap. Each tag value list (map key) could have multiple + // mutable aggregations (map value) from different buckets. + private static void putBucketsIntoMultiMap( + LinkedList buckets, + Multimap, MutableAggregation> multimap, + Aggregation aggregation, + Timestamp now) { + // Put fractional stats of the head (oldest) bucket. + IntervalBucket head = buckets.peekFirst(); + IntervalBucket tail = buckets.peekLast(); + double fractionTail = tail.getFraction(now); + // TODO(songya): decide what to do when time goes backwards + checkArgument( + 0.0 <= fractionTail && fractionTail <= 1.0, + "Fraction " + fractionTail + " should be within [0.0, 1.0]."); + double fractionHead = 1.0 - fractionTail; + putFractionalMutableAggregationsToMultiMap( + head.getTagValueAggregationMap(), multimap, aggregation, fractionHead); + + // Put whole data of other buckets. + boolean shouldSkipFirst = true; + for (IntervalBucket bucket : buckets) { + if (shouldSkipFirst) { + shouldSkipFirst = false; + continue; // skip the first bucket + } + for (Entry, MutableAggregation> entry : + bucket.getTagValueAggregationMap().entrySet()) { + multimap.put(entry.getKey(), entry.getValue()); + } + } + } + + // Put stats within one bucket into multimap, multiplied by a given fraction. + private static void putFractionalMutableAggregationsToMultiMap( + Map mutableAggrMap, + Multimap multimap, + Aggregation aggregation, + double fraction) { + for (Entry entry : mutableAggrMap.entrySet()) { + // Initially empty MutableAggregations. + MutableAggregation fractionalMutableAgg = createMutableAggregation(aggregation); + fractionalMutableAgg.combine(entry.getValue(), fraction); + multimap.put(entry.getKey(), fractionalMutableAgg); + } + } + + // For each tag value list (key of AggregationMap), combine mutable aggregations into one + // mutable aggregation, thus convert the multimap into a single map. + private static Map aggregateOnEachTagValueList( + Multimap multimap, Aggregation aggregation) { + Map map = Maps.newHashMap(); + for (T tagValues : multimap.keySet()) { + // Initially empty MutableAggregations. + MutableAggregation combinedAggregation = createMutableAggregation(aggregation); + for (MutableAggregation mutableAggregation : multimap.get(tagValues)) { + combinedAggregation.combine(mutableAggregation, 1.0); + } + map.put(tagValues, combinedAggregation); + } + return map; + } + + // Subtract a Duration from a Timestamp, and return a new Timestamp. + private static Timestamp subtractDuration(Timestamp timestamp, Duration duration) { + return timestamp.addDuration(Duration.create(-duration.getSeconds(), -duration.getNanos())); + } + } + + // static inner Function classes + + private static final class CreateMutableSum implements Function { + @Override + public MutableAggregation apply(Sum arg) { + return MutableSum.create(); + } + + private static final CreateMutableSum INSTANCE = new CreateMutableSum(); + } + + private static final class CreateMutableCount implements Function { + @Override + public MutableAggregation apply(Count arg) { + return MutableCount.create(); + } + + private static final CreateMutableCount INSTANCE = new CreateMutableCount(); + } + + private static final class CreateMutableMean implements Function { + @Override + public MutableAggregation apply(Mean arg) { + return MutableMean.create(); + } + + private static final CreateMutableMean INSTANCE = new CreateMutableMean(); + } + + private static final class CreateMutableDistribution + implements Function { + @Override + public MutableAggregation apply(Distribution arg) { + return MutableDistribution.create(arg.getBucketBoundaries()); + } + + private static final CreateMutableDistribution INSTANCE = new CreateMutableDistribution(); + } + + private static final class CreateSumData implements Function { + + private final Measure measure; + + private CreateSumData(Measure measure) { + this.measure = measure; + } + + @Override + public AggregationData apply(final MutableSum arg) { + return measure.match( + Functions.returnConstant(SumDataDouble.create(arg.getSum())), + Functions.returnConstant(SumDataLong.create(Math.round(arg.getSum()))), + Functions.throwAssertionError()); + } + } + + private static final class CreateCountData implements Function { + @Override + public AggregationData apply(MutableCount arg) { + return CountData.create(arg.getCount()); + } + + private static final CreateCountData INSTANCE = new CreateCountData(); + } + + private static final class CreateMeanData implements Function { + @Override + public AggregationData apply(MutableMean arg) { + return MeanData.create(arg.getMean(), arg.getCount()); + } + + private static final CreateMeanData INSTANCE = new CreateMeanData(); + } + + private static final class CreateDistributionData + implements Function { + @Override + public AggregationData apply(MutableDistribution arg) { + List boxedBucketCounts = new ArrayList(); + for (long bucketCount : arg.getBucketCounts()) { + boxedBucketCounts.add(bucketCount); + } + return DistributionData.create( + arg.getMean(), + arg.getCount(), + arg.getMin(), + arg.getMax(), + arg.getSumOfSquaredDeviations(), + boxedBucketCounts); + } + + private static final CreateDistributionData INSTANCE = new CreateDistributionData(); + } + + private static final class CreateCumulative implements Function { + @Override + public MutableViewData apply(Cumulative arg) { + return new CumulativeMutableViewData(view, start); + } + + private final View view; + private final Timestamp start; + + private CreateCumulative(View view, Timestamp start) { + this.view = view; + this.start = start; + } + } + + private static final class CreateInterval implements Function { + @Override + public MutableViewData apply(Interval arg) { + return new IntervalMutableViewData(view, start); + } + + private final View view; + private final Timestamp start; + + private CreateInterval(View view, Timestamp start) { + this.view = view; + this.start = start; + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java new file mode 100644 index 00000000..5079e27c --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/StatsComponentImplBase.java @@ -0,0 +1,72 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import com.google.common.base.Preconditions; +import io.opencensus.common.Clock; +import io.opencensus.implcore.internal.EventQueue; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.StatsComponent; + +/** Base implementation of {@link StatsComponent}. */ +public class StatsComponentImplBase extends StatsComponent { + + // The StatsCollectionState shared between the StatsComponent, StatsRecorder and ViewManager. + private final CurrentStatsState state = new CurrentStatsState(); + + private final ViewManagerImpl viewManager; + private final StatsRecorderImpl statsRecorder; + + /** + * Creates a new {@code StatsComponentImplBase}. + * + * @param queue the queue implementation. + * @param clock the clock to use when recording stats. + */ + public StatsComponentImplBase(EventQueue queue, Clock clock) { + StatsManager statsManager = new StatsManager(queue, clock, state); + this.viewManager = new ViewManagerImpl(statsManager); + this.statsRecorder = new StatsRecorderImpl(statsManager); + } + + @Override + public ViewManagerImpl getViewManager() { + return viewManager; + } + + @Override + public StatsRecorderImpl getStatsRecorder() { + return statsRecorder; + } + + @Override + public StatsCollectionState getState() { + return state.get(); + } + + @Override + public void setState(StatsCollectionState newState) { + boolean stateChanged = state.set(Preconditions.checkNotNull(newState, "newState")); + if (stateChanged) { + if (newState == StatsCollectionState.DISABLED) { + viewManager.clearStats(); + } else { + viewManager.resumeStatsCollection(); + } + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/StatsManager.java b/impl_core/src/main/java/io/opencensus/implcore/stats/StatsManager.java new file mode 100644 index 00000000..63fcd587 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/StatsManager.java @@ -0,0 +1,90 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.common.Clock; +import io.opencensus.implcore.internal.EventQueue; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.View; +import io.opencensus.stats.ViewData; +import io.opencensus.tags.TagContext; + +/** Object that stores all views and stats. */ +final class StatsManager { + + private final EventQueue queue; + + // clock used throughout the stats implementation + private final Clock clock; + + private final CurrentStatsState state; + private final MeasureToViewMap measureToViewMap = new MeasureToViewMap(); + + StatsManager(EventQueue queue, Clock clock, CurrentStatsState state) { + checkNotNull(queue, "EventQueue"); + checkNotNull(clock, "Clock"); + checkNotNull(state, "state"); + this.queue = queue; + this.clock = clock; + this.state = state; + } + + void registerView(View view) { + measureToViewMap.registerView(view, clock); + } + + ViewData getView(View.Name viewName) { + return measureToViewMap.getView(viewName, clock, state.getInternal()); + } + + void record(TagContext tags, MeasureMapInternal measurementValues) { + // TODO(songya): consider exposing No-op MeasureMap and use it when stats state is DISABLED, so + // that we don't need to create actual MeasureMapImpl. + if (state.getInternal() == StatsCollectionState.ENABLED) { + queue.enqueue(new StatsEvent(this, tags, measurementValues)); + } + } + + void clearStats() { + measureToViewMap.clearStats(); + } + + void resumeStatsCollection() { + measureToViewMap.resumeStatsCollection(clock.now()); + } + + // An EventQueue entry that records the stats from one call to StatsManager.record(...). + private static final class StatsEvent implements EventQueue.Entry { + private final TagContext tags; + private final MeasureMapInternal stats; + private final StatsManager statsManager; + + StatsEvent(StatsManager statsManager, TagContext tags, MeasureMapInternal stats) { + this.statsManager = statsManager; + this.tags = tags; + this.stats = stats; + } + + @Override + public void process() { + // Add Timestamp to value after it went through the DisruptorQueue. + statsManager.measureToViewMap.record(tags, stats, statsManager.clock.now()); + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java b/impl_core/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java new file mode 100644 index 00000000..f9ebea41 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/StatsRecorderImpl.java @@ -0,0 +1,36 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.stats.StatsRecorder; + +/** Implementation of {@link StatsRecorder}. */ +public final class StatsRecorderImpl extends StatsRecorder { + private final StatsManager statsManager; + + StatsRecorderImpl(StatsManager statsManager) { + checkNotNull(statsManager, "StatsManager"); + this.statsManager = statsManager; + } + + @Override + public MeasureMapImpl newMeasureMap() { + return MeasureMapImpl.create(statsManager); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java new file mode 100644 index 00000000..eb716689 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/stats/ViewManagerImpl.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import io.opencensus.stats.View; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewManager; + +/** Implementation of {@link ViewManager}. */ +public final class ViewManagerImpl extends ViewManager { + private final StatsManager statsManager; + + ViewManagerImpl(StatsManager statsManager) { + this.statsManager = statsManager; + } + + @Override + public void registerView(View view) { + statsManager.registerView(view); + } + + @Override + public ViewData getView(View.Name viewName) { + return statsManager.getView(viewName); + } + + void clearStats() { + statsManager.clearStats(); + } + + void resumeStatsCollection() { + statsManager.resumeStatsCollection(); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java new file mode 100644 index 00000000..1a4ef81b --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTagContextUtils.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import io.grpc.Context; +import io.opencensus.common.Scope; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.unsafe.ContextUtils; +import javax.annotation.Nullable; + +/** + * Utility methods for accessing the {@link TagContext} contained in the {@link io.grpc.Context}. + */ +final class CurrentTagContextUtils { + + private CurrentTagContextUtils() {} + + /** + * Returns the {@link TagContext} from the current context. + * + * @return the {@code TagContext} from the current context. + */ + @Nullable + static TagContext getCurrentTagContext() { + return ContextUtils.TAG_CONTEXT_KEY.get(); + } + + /** + * Enters the scope of code where the given {@link TagContext} is in the current context and + * returns an object that represents that scope. The scope is exited when the returned object is + * closed. + * + * @param tags the {@code TagContext} to be set to the current context. + * @return an object that defines a scope where the given {@code TagContext} is set to the current + * context. + */ + static Scope withTagContext(TagContext tags) { + return new WithTagContext(tags); + } + + private static final class WithTagContext implements Scope { + + private final Context orig; + + /** + * Constructs a new {@link WithTagContext}. + * + * @param tags the {@code TagContext} to be added to the current {@code Context}. + */ + private WithTagContext(TagContext tags) { + orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tags).attach(); + } + + @Override + public void close() { + Context.current().detach(orig); + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java new file mode 100644 index 00000000..ab60ffa1 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/CurrentTaggingState.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.tags.TaggingState; +import io.opencensus.tags.TagsComponent; +import javax.annotation.concurrent.ThreadSafe; + +/** + * The current {@link TaggingState} for a {@link TagsComponent}. + * + *

This class allows different tagging classes to share the state in a thread-safe way. + */ +@ThreadSafe +public final class CurrentTaggingState { + private volatile TaggingState currentState = TaggingState.ENABLED; + + public TaggingState get() { + return currentState; + } + + void set(TaggingState state) { + currentState = checkNotNull(state, "state"); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java b/impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java new file mode 100644 index 00000000..eae54c5d --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/NoopTagContextBuilder.java @@ -0,0 +1,51 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import io.opencensus.common.Scope; +import io.opencensus.implcore.internal.NoopScope; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagContextBuilder; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; + +/** {@link TagContextBuilder} that is used when tagging is disabled. */ +final class NoopTagContextBuilder extends TagContextBuilder { + static final NoopTagContextBuilder INSTANCE = new NoopTagContextBuilder(); + + private NoopTagContextBuilder() {} + + @Override + public TagContextBuilder put(TagKey key, TagValue value) { + return this; + } + + @Override + public TagContextBuilder remove(TagKey key) { + return this; + } + + @Override + public TagContext build() { + return TagContextImpl.EMPTY; + } + + @Override + public Scope buildScoped() { + return NoopScope.getInstance(); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java new file mode 100644 index 00000000..1f473454 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextBuilderImpl.java @@ -0,0 +1,64 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.common.Scope; +import io.opencensus.tags.TagContextBuilder; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import java.util.HashMap; +import java.util.Map; + +final class TagContextBuilderImpl extends TagContextBuilder { + private final Map tags; + + TagContextBuilderImpl(Map tags) { + this.tags = new HashMap(tags); + } + + TagContextBuilderImpl() { + this.tags = new HashMap(); + } + + @Override + public TagContextBuilderImpl put(TagKey key, TagValue value) { + return setInternal(key, checkNotNull(value, "value")); + } + + private TagContextBuilderImpl setInternal(TagKey key, TagValue value) { + tags.put(checkNotNull(key), value); + return this; + } + + @Override + public TagContextBuilderImpl remove(TagKey key) { + tags.remove(key); + return this; + } + + @Override + public TagContextImpl build() { + return new TagContextImpl(tags); + } + + @Override + public Scope buildScoped() { + return CurrentTagContextUtils.withTagContext(build()); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java new file mode 100644 index 00000000..177ce639 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextImpl.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import javax.annotation.concurrent.Immutable; + +@Immutable +public final class TagContextImpl extends TagContext { + + public static final TagContextImpl EMPTY = + new TagContextImpl(Collections.emptyMap()); + + // The types of the TagKey and value must match for each entry. + private final Map tags; + + public TagContextImpl(Map tags) { + this.tags = Collections.unmodifiableMap(new HashMap(tags)); + } + + public Map getTags() { + return tags; + } + + @Override + protected Iterator getIterator() { + return new TagIterator(tags); + } + + @Override + public boolean equals(Object other) { + // Directly compare the tags when both objects are TagContextImpls, for efficiency. + if (other instanceof TagContextImpl) { + return getTags().equals(((TagContextImpl) other).getTags()); + } + return super.equals(other); + } + + private static final class TagIterator implements Iterator { + Iterator> iterator; + + TagIterator(Map tags) { + iterator = tags.entrySet().iterator(); + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public Tag next() { + final Entry next = iterator.next(); + return Tag.create(next.getKey(), next.getValue()); + } + + @Override + public void remove() { + throw new UnsupportedOperationException("TagIterator.remove()"); + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java new file mode 100644 index 00000000..5fbc5050 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagContextUtils.java @@ -0,0 +1,33 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import io.opencensus.tags.Tag; + +final class TagContextUtils { + private TagContextUtils() {} + + /** + * Add a {@code Tag} of any type to a builder. + * + * @param tag tag containing the key and value to set. + * @param builder the builder to update. + */ + static void addTagToBuilder(Tag tag, TagContextBuilderImpl builder) { + builder.put(tag.getKey(), tag.getValue()); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java new file mode 100644 index 00000000..82c1d8cf --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TaggerImpl.java @@ -0,0 +1,114 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import io.opencensus.common.Scope; +import io.opencensus.implcore.internal.NoopScope; +import io.opencensus.tags.InternalUtils; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagContextBuilder; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TaggingState; +import java.util.Iterator; + +public final class TaggerImpl extends Tagger { + // All methods in this class use TagContextImpl and TagContextBuilderImpl. For example, + // withTagContext(...) always puts a TagContextImpl into scope, even if the argument is another + // TagContext subclass. + + private final CurrentTaggingState state; + + TaggerImpl(CurrentTaggingState state) { + this.state = state; + } + + @Override + public TagContextImpl empty() { + return TagContextImpl.EMPTY; + } + + @Override + public TagContextImpl getCurrentTagContext() { + return state.get() == TaggingState.DISABLED + ? TagContextImpl.EMPTY + : toTagContextImpl(CurrentTagContextUtils.getCurrentTagContext()); + } + + @Override + public TagContextBuilder emptyBuilder() { + return state.get() == TaggingState.DISABLED + ? NoopTagContextBuilder.INSTANCE + : new TagContextBuilderImpl(); + } + + @Override + public TagContextBuilder currentBuilder() { + return state.get() == TaggingState.DISABLED + ? NoopTagContextBuilder.INSTANCE + : toBuilder(CurrentTagContextUtils.getCurrentTagContext()); + } + + @Override + public TagContextBuilder toBuilder(TagContext tags) { + return state.get() == TaggingState.DISABLED + ? NoopTagContextBuilder.INSTANCE + : toTagContextBuilderImpl(tags); + } + + @Override + public Scope withTagContext(TagContext tags) { + return state.get() == TaggingState.DISABLED + ? NoopScope.getInstance() + : CurrentTagContextUtils.withTagContext(toTagContextImpl(tags)); + } + + private static TagContextImpl toTagContextImpl(TagContext tags) { + if (tags instanceof TagContextImpl) { + return (TagContextImpl) tags; + } else { + Iterator i = InternalUtils.getTags(tags); + if (!i.hasNext()) { + return TagContextImpl.EMPTY; + } + TagContextBuilderImpl builder = new TagContextBuilderImpl(); + while (i.hasNext()) { + Tag tag = i.next(); + if (tag != null) { + TagContextUtils.addTagToBuilder(tag, builder); + } + } + return builder.build(); + } + } + + private static TagContextBuilderImpl toTagContextBuilderImpl(TagContext tags) { + // Copy the tags more efficiently in the expected case, when the TagContext is a TagContextImpl. + if (tags instanceof TagContextImpl) { + return new TagContextBuilderImpl(((TagContextImpl) tags).getTags()); + } else { + TagContextBuilderImpl builder = new TagContextBuilderImpl(); + for (Iterator i = InternalUtils.getTags(tags); i.hasNext(); ) { + Tag tag = i.next(); + if (tag != null) { + TagContextUtils.addTagToBuilder(tag, builder); + } + } + return builder; + } + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java b/impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java new file mode 100644 index 00000000..216afdc9 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/TagsComponentImplBase.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TaggingState; +import io.opencensus.tags.TagsComponent; +import io.opencensus.tags.propagation.TagPropagationComponent; + +/** Base implementation of {@link TagsComponent}. */ +public class TagsComponentImplBase extends TagsComponent { + + // The TaggingState shared between the TagsComponent, Tagger, and TagPropagationComponent + private final CurrentTaggingState state = new CurrentTaggingState(); + + private final Tagger tagger = new TaggerImpl(state); + private final TagPropagationComponent tagPropagationComponent = + new TagPropagationComponentImpl(state); + + @Override + public Tagger getTagger() { + return tagger; + } + + @Override + public TagPropagationComponent getTagPropagationComponent() { + return tagPropagationComponent; + } + + @Override + public TaggingState getState() { + return state.get(); + } + + @Override + public void setState(TaggingState newState) { + state.set(checkNotNull(newState, "newState")); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java new file mode 100644 index 00000000..d889a4b8 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java @@ -0,0 +1,171 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Charsets; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import io.opencensus.implcore.internal.VarInt; +import io.opencensus.implcore.tags.TagContextImpl; +import io.opencensus.tags.InternalUtils; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.propagation.TagContextDeserializationException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Methods for serializing and deserializing {@link TagContext}s. + * + *

The format defined in this class is shared across all implementations of OpenCensus. It allows + * tags to propagate across requests. + * + *

OpenCensus tag context encoding: + * + *

    + *
  • Tags are encoded in single byte sequence. The version 0 format is: + *
  • {@code } + *
  • {@code == a single byte, value 0} + *
  • {@code == ()*} + *
      + *
    • {@code } == a single byte, value 0 + *
    • {@code }: + *
        + *
      • {@code } + *
          + *
        • {@code } == varint encoded integer + *
        • {@code } == tag_key_len bytes comprising tag key name + *
        • {@code } == varint encoded integer + *
        • {@code } == tag_val_len bytes comprising UTF-8 string + *
        + *
      + *
    + *
+ */ +final class SerializationUtils { + private SerializationUtils() {} + + @VisibleForTesting static final int VERSION_ID = 0; + @VisibleForTesting static final int TAG_FIELD_ID = 0; + + // Serializes a TagContext to the on-the-wire format. + // Encoded tags are of the form: + static byte[] serializeBinary(TagContext tags) { + // Use a ByteArrayDataOutput to avoid needing to handle IOExceptions. + final ByteArrayDataOutput byteArrayDataOutput = ByteStreams.newDataOutput(); + byteArrayDataOutput.write(VERSION_ID); + for (Iterator i = InternalUtils.getTags(tags); i.hasNext(); ) { + Tag tag = i.next(); + encodeTag(tag, byteArrayDataOutput); + } + return byteArrayDataOutput.toByteArray(); + } + + // Deserializes input to TagContext based on the binary format standard. + // The encoded tags are of the form: + static TagContextImpl deserializeBinary(byte[] bytes) throws TagContextDeserializationException { + try { + if (bytes.length == 0) { + // Does not allow empty byte array. + throw new TagContextDeserializationException("Input byte[] can not be empty."); + } + + ByteBuffer buffer = ByteBuffer.wrap(bytes).asReadOnlyBuffer(); + int versionId = buffer.get(); + if (versionId != VERSION_ID) { + throw new TagContextDeserializationException( + "Wrong Version ID: " + versionId + ". Currently supported version is: " + VERSION_ID); + } + return new TagContextImpl(parseTags(buffer)); + } catch (BufferUnderflowException exn) { + throw new TagContextDeserializationException(exn.toString()); // byte array format error. + } + } + + private static Map parseTags(ByteBuffer buffer) + throws TagContextDeserializationException { + Map tags = new HashMap(); + int limit = buffer.limit(); + while (buffer.position() < limit) { + int type = buffer.get(); + if (type == TAG_FIELD_ID) { + TagKey key = createTagKey(decodeString(buffer)); + TagValue val = createTagValue(key, decodeString(buffer)); + tags.put(key, val); + } else { + // Stop parsing at the first unknown field ID, since there is no way to know its length. + // TODO(sebright): Consider storing the rest of the byte array in the TagContext. + return tags; + } + } + return tags; + } + + // TODO(sebright): Consider exposing a TagKey name validation method to avoid needing to catch an + // IllegalArgumentException here. + private static final TagKey createTagKey(String name) throws TagContextDeserializationException { + try { + return TagKey.create(name); + } catch (IllegalArgumentException e) { + throw new TagContextDeserializationException("Invalid tag key: " + name, e); + } + } + + // TODO(sebright): Consider exposing a TagValue validation method to avoid needing to catch + // an IllegalArgumentException here. + private static final TagValue createTagValue(TagKey key, String value) + throws TagContextDeserializationException { + try { + return TagValue.create(value); + } catch (IllegalArgumentException e) { + throw new TagContextDeserializationException( + "Invalid tag value for key " + key + ": " + value, e); + } + } + + private static final void encodeTag(Tag tag, ByteArrayDataOutput byteArrayDataOutput) { + byteArrayDataOutput.write(TAG_FIELD_ID); + encodeString(tag.getKey().getName(), byteArrayDataOutput); + encodeString(tag.getValue().asString(), byteArrayDataOutput); + } + + private static final void encodeString(String input, ByteArrayDataOutput byteArrayDataOutput) { + putVarInt(input.length(), byteArrayDataOutput); + byteArrayDataOutput.write(input.getBytes(Charsets.UTF_8)); + } + + private static final void putVarInt(int input, ByteArrayDataOutput byteArrayDataOutput) { + byte[] output = new byte[VarInt.varIntSize(input)]; + VarInt.putVarInt(input, output, 0); + byteArrayDataOutput.write(output); + } + + private static final String decodeString(ByteBuffer buffer) { + int length = VarInt.getVarInt(buffer); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < length; i++) { + builder.append((char) buffer.get()); + } + return builder.toString(); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java new file mode 100644 index 00000000..eea24a33 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import io.opencensus.implcore.tags.CurrentTaggingState; +import io.opencensus.implcore.tags.TagContextImpl; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TaggingState; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import io.opencensus.tags.propagation.TagContextDeserializationException; + +final class TagContextBinarySerializerImpl extends TagContextBinarySerializer { + private static final byte[] EMPTY_BYTE_ARRAY = {}; + + private final CurrentTaggingState state; + + TagContextBinarySerializerImpl(CurrentTaggingState state) { + this.state = state; + } + + @Override + public byte[] toByteArray(TagContext tags) { + return state.get() == TaggingState.DISABLED + ? EMPTY_BYTE_ARRAY + : SerializationUtils.serializeBinary(tags); + } + + @Override + public TagContext fromByteArray(byte[] bytes) throws TagContextDeserializationException { + return state.get() == TaggingState.DISABLED + ? TagContextImpl.EMPTY + : SerializationUtils.deserializeBinary(bytes); + } +} diff --git a/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java new file mode 100644 index 00000000..5def0758 --- /dev/null +++ b/impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java @@ -0,0 +1,34 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import io.opencensus.implcore.tags.CurrentTaggingState; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import io.opencensus.tags.propagation.TagPropagationComponent; + +public final class TagPropagationComponentImpl extends TagPropagationComponent { + private final TagContextBinarySerializer tagContextBinarySerializer; + + public TagPropagationComponentImpl(CurrentTaggingState state) { + tagContextBinarySerializer = new TagContextBinarySerializerImpl(state); + } + + @Override + public TagContextBinarySerializer getBinarySerializer() { + return tagContextBinarySerializer; + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java new file mode 100644 index 00000000..2fd1ddc7 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/CurrentStatsStateTest.java @@ -0,0 +1,65 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.stats.StatsCollectionState; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link CurrentStatsState}. */ +@RunWith(JUnit4.class) +public final class CurrentStatsStateTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void defaultState() { + assertThat(new CurrentStatsState().get()).isEqualTo(StatsCollectionState.ENABLED); + } + + @Test + public void setState() { + CurrentStatsState state = new CurrentStatsState(); + assertThat(state.set(StatsCollectionState.DISABLED)).isTrue(); + assertThat(state.getInternal()).isEqualTo(StatsCollectionState.DISABLED); + assertThat(state.set(StatsCollectionState.ENABLED)).isTrue(); + assertThat(state.getInternal()).isEqualTo(StatsCollectionState.ENABLED); + assertThat(state.set(StatsCollectionState.ENABLED)).isFalse(); + } + + @Test + public void preventNull() { + CurrentStatsState state = new CurrentStatsState(); + thrown.expect(NullPointerException.class); + thrown.expectMessage("state"); + state.set(null); + } + + @Test + public void preventSettingStateAfterReadingState() { + CurrentStatsState state = new CurrentStatsState(); + state.get(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("State was already read, cannot set state."); + state.set(StatsCollectionState.DISABLED); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java new file mode 100644 index 00000000..10bce262 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/IntervalBucketTest.java @@ -0,0 +1,120 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.common.Duration; +import io.opencensus.common.Timestamp; +import io.opencensus.implcore.stats.MutableAggregation.MutableMean; +import io.opencensus.stats.Aggregation.Mean; +import io.opencensus.tags.TagValue; +import java.util.Arrays; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link IntervalBucket}. */ +@RunWith(JUnit4.class) +public class IntervalBucketTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private static final double TOLERANCE = 1e-6; + private static final Duration MINUTE = Duration.create(60, 0); + private static final Duration NEGATIVE_TEN_SEC = Duration.create(-10, 0); + private static final Timestamp START = Timestamp.create(60, 0); + private static final Mean MEAN = Mean.create(); + + @Test + public void preventNullStartTime() { + thrown.expect(NullPointerException.class); + new IntervalBucket(null, MINUTE, MEAN); + } + + @Test + public void preventNullDuration() { + thrown.expect(NullPointerException.class); + new IntervalBucket(START, null, MEAN); + } + + @Test + public void preventNegativeDuration() { + thrown.expect(IllegalArgumentException.class); + new IntervalBucket(START, NEGATIVE_TEN_SEC, MEAN); + } + + @Test + public void preventNullAggregationList() { + thrown.expect(NullPointerException.class); + new IntervalBucket(START, MINUTE, null); + } + + @Test + public void testGetTagValueAggregationMap_empty() { + assertThat(new IntervalBucket(START, MINUTE, MEAN).getTagValueAggregationMap()).isEmpty(); + } + + @Test + public void testGetStart() { + assertThat(new IntervalBucket(START, MINUTE, MEAN).getStart()).isEqualTo(START); + } + + @Test + public void testRecord() { + IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN); + List tagValues1 = Arrays.asList(TagValue.create("VALUE1")); + List tagValues2 = Arrays.asList(TagValue.create("VALUE2")); + bucket.record(tagValues1, 5.0); + bucket.record(tagValues1, 15.0); + bucket.record(tagValues2, 10.0); + assertThat(bucket.getTagValueAggregationMap().keySet()).containsExactly(tagValues1, tagValues2); + MutableMean mutableMean1 = (MutableMean) bucket.getTagValueAggregationMap().get(tagValues1); + MutableMean mutableMean2 = (MutableMean) bucket.getTagValueAggregationMap().get(tagValues2); + assertThat(mutableMean1.getSum()).isWithin(TOLERANCE).of(20); + assertThat(mutableMean2.getSum()).isWithin(TOLERANCE).of(10); + assertThat(mutableMean1.getCount()).isEqualTo(2); + assertThat(mutableMean2.getCount()).isEqualTo(1); + } + + @Test + public void testGetFraction() { + Timestamp thirtySecondsAfterStart = Timestamp.create(90, 0); + assertThat(new IntervalBucket(START, MINUTE, MEAN).getFraction(thirtySecondsAfterStart)) + .isWithin(TOLERANCE) + .of(0.5); + } + + @Test + public void preventCallingGetFractionOnPastBuckets() { + IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN); + Timestamp twoMinutesAfterStart = Timestamp.create(180, 0); + thrown.expect(IllegalArgumentException.class); + bucket.getFraction(twoMinutesAfterStart); + } + + @Test + public void preventCallingGetFractionOnFutureBuckets() { + IntervalBucket bucket = new IntervalBucket(START, MINUTE, MEAN); + Timestamp thirtySecondsBeforeStart = Timestamp.create(30, 0); + thrown.expect(IllegalArgumentException.class); + bucket.getFraction(thirtySecondsBeforeStart); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java new file mode 100644 index 00000000..c57baa0b --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureMapInternalTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.Lists; +import io.opencensus.stats.Measure; +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.stats.Measurement; +import io.opencensus.stats.Measurement.MeasurementDouble; +import io.opencensus.stats.Measurement.MeasurementLong; +import java.util.ArrayList; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link MeasureMapInternal}. */ +@RunWith(JUnit4.class) +public class MeasureMapInternalTest { + + @Test + public void testPutDouble() { + MeasureMapInternal metrics = MeasureMapInternal.builder().put(M1, 44.4).build(); + assertContains(metrics, MeasurementDouble.create(M1, 44.4)); + } + + @Test + public void testPutLong() { + MeasureMapInternal metrics = MeasureMapInternal.builder().put(M3, 9999L).put(M4, 8888L).build(); + assertContains(metrics, MeasurementLong.create(M3, 9999L), MeasurementLong.create(M4, 8888L)); + } + + @Test + public void testCombination() { + MeasureMapInternal metrics = + MeasureMapInternal.builder() + .put(M1, 44.4) + .put(M2, 66.6) + .put(M3, 9999L) + .put(M4, 8888L) + .build(); + assertContains( + metrics, + MeasurementDouble.create(M1, 44.4), + MeasurementDouble.create(M2, 66.6), + MeasurementLong.create(M3, 9999L), + MeasurementLong.create(M4, 8888L)); + } + + @Test + public void testBuilderEmpty() { + MeasureMapInternal metrics = MeasureMapInternal.builder().build(); + assertContains(metrics); + } + + @Test + public void testBuilder() { + ArrayList expected = new ArrayList(10); + MeasureMapInternal.Builder builder = MeasureMapInternal.builder(); + for (int i = 1; i <= 10; i++) { + expected.add(MeasurementDouble.create(makeSimpleMeasureDouble("m" + i), i * 11.1)); + builder.put(makeSimpleMeasureDouble("m" + i), i * 11.1); + assertContains(builder.build(), expected.toArray(new Measurement[i])); + } + } + + @Test + public void testDuplicateMeasureDoubles() { + assertContains( + MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).build(), + MeasurementDouble.create(M1, 2.0)); + assertContains( + MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).put(M1, 3.0).build(), + MeasurementDouble.create(M1, 3.0)); + assertContains( + MeasureMapInternal.builder().put(M1, 1.0).put(M2, 2.0).put(M1, 3.0).build(), + MeasurementDouble.create(M1, 3.0), + MeasurementDouble.create(M2, 2.0)); + assertContains( + MeasureMapInternal.builder().put(M1, 1.0).put(M1, 2.0).put(M2, 2.0).build(), + MeasurementDouble.create(M1, 2.0), + MeasurementDouble.create(M2, 2.0)); + } + + @Test + public void testDuplicateMeasureLongs() { + assertContains( + MeasureMapInternal.builder().put(M3, 100L).put(M3, 100L).build(), + MeasurementLong.create(M3, 100L)); + assertContains( + MeasureMapInternal.builder().put(M3, 100L).put(M3, 200L).put(M3, 300L).build(), + MeasurementLong.create(M3, 300L)); + assertContains( + MeasureMapInternal.builder().put(M3, 100L).put(M4, 200L).put(M3, 300L).build(), + MeasurementLong.create(M3, 300L), + MeasurementLong.create(M4, 200L)); + assertContains( + MeasureMapInternal.builder().put(M3, 100L).put(M3, 200L).put(M4, 200L).build(), + MeasurementLong.create(M3, 200L), + MeasurementLong.create(M4, 200L)); + } + + @Test + public void testDuplicateMeasures() { + assertContains( + MeasureMapInternal.builder().put(M3, 100L).put(M1, 1.0).put(M3, 300L).build(), + MeasurementLong.create(M3, 300L), + MeasurementDouble.create(M1, 1.0)); + assertContains( + MeasureMapInternal.builder().put(M2, 2.0).put(M3, 100L).put(M2, 3.0).build(), + MeasurementDouble.create(M2, 3.0), + MeasurementLong.create(M3, 100L)); + } + + private static final MeasureDouble M1 = makeSimpleMeasureDouble("m1"); + private static final MeasureDouble M2 = makeSimpleMeasureDouble("m2"); + private static final MeasureLong M3 = makeSimpleMeasureLong("m3"); + private static final MeasureLong M4 = makeSimpleMeasureLong("m4"); + + private static MeasureDouble makeSimpleMeasureDouble(String measure) { + return Measure.MeasureDouble.create(measure, measure + " description", "1"); + } + + private static MeasureLong makeSimpleMeasureLong(String measure) { + return Measure.MeasureLong.create(measure, measure + " description", "1"); + } + + private static void assertContains(MeasureMapInternal metrics, Measurement... measurements) { + assertThat(Lists.newArrayList(metrics.iterator())).containsExactly((Object[]) measurements); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java new file mode 100644 index 00000000..0a198b0c --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MeasureToViewMapTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.common.Timestamp; +import io.opencensus.stats.Aggregation.Mean; +import io.opencensus.stats.Measure; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.View; +import io.opencensus.stats.View.AggregationWindow.Cumulative; +import io.opencensus.stats.View.Name; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; +import io.opencensus.tags.TagKey; +import io.opencensus.testing.common.TestClock; +import java.util.Arrays; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link MeasureToViewMap}. */ +@RunWith(JUnit4.class) +public class MeasureToViewMapTest { + + private static final Measure MEASURE = + Measure.MeasureDouble.create("my measurement", "measurement description", "By"); + + private static final Name VIEW_NAME = View.Name.create("my view"); + + private static final Cumulative CUMULATIVE = Cumulative.create(); + + private static final View VIEW = + View.create( + VIEW_NAME, + "view description", + MEASURE, + Mean.create(), + Arrays.asList(TagKey.create("my key")), + CUMULATIVE); + + @Test + public void testRegisterAndGetView() { + MeasureToViewMap measureToViewMap = new MeasureToViewMap(); + TestClock clock = TestClock.create(Timestamp.create(10, 20)); + measureToViewMap.registerView(VIEW, clock); + clock.setTime(Timestamp.create(30, 40)); + ViewData viewData = measureToViewMap.getView(VIEW_NAME, clock, StatsCollectionState.ENABLED); + assertThat(viewData.getView()).isEqualTo(VIEW); + assertThat(viewData.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(10, 20), Timestamp.create(30, 40))); + assertThat(viewData.getAggregationMap()).isEmpty(); + } +} 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 new file mode 100644 index 00000000..054a5b44 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableAggregationTest.java @@ -0,0 +1,249 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.common.Function; +import io.opencensus.implcore.stats.MutableAggregation.MutableCount; +import io.opencensus.implcore.stats.MutableAggregation.MutableDistribution; +import io.opencensus.implcore.stats.MutableAggregation.MutableMean; +import io.opencensus.implcore.stats.MutableAggregation.MutableSum; +import io.opencensus.stats.BucketBoundaries; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link io.opencensus.implcore.stats.MutableAggregation}. */ +@RunWith(JUnit4.class) +public class MutableAggregationTest { + + @Rule public ExpectedException thrown = ExpectedException.none(); + + private static final double TOLERANCE = 1e-6; + private static final BucketBoundaries BUCKET_BOUNDARIES = + BucketBoundaries.create(Arrays.asList(-10.0, 0.0, 10.0)); + + @Test + public void testCreateEmpty() { + assertThat(MutableSum.create().getSum()).isWithin(TOLERANCE).of(0); + assertThat(MutableCount.create().getCount()).isEqualTo(0); + assertThat(MutableMean.create().getMean()).isWithin(TOLERANCE).of(0); + + BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(0.1, 2.2, 33.3)); + MutableDistribution mutableDistribution = MutableDistribution.create(bucketBoundaries); + assertThat(mutableDistribution.getMean()).isWithin(TOLERANCE).of(0); + assertThat(mutableDistribution.getCount()).isEqualTo(0); + assertThat(mutableDistribution.getMin()).isPositiveInfinity(); + assertThat(mutableDistribution.getMax()).isNegativeInfinity(); + assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(TOLERANCE).of(0); + assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]); + } + + @Test + public void testNullBucketBoundaries() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("bucketBoundaries should not be null."); + MutableDistribution.create(null); + } + + @Test + public void testNoBoundaries() { + List buckets = Arrays.asList(); + MutableDistribution noBoundaries = MutableDistribution.create(BucketBoundaries.create(buckets)); + assertThat(noBoundaries.getBucketCounts().length).isEqualTo(1); + assertThat(noBoundaries.getBucketCounts()[0]).isEqualTo(0); + } + + @Test + public void testAdd() { + List aggregations = + Arrays.asList( + MutableSum.create(), + MutableCount.create(), + MutableMean.create(), + MutableDistribution.create(BUCKET_BOUNDARIES)); + + List values = Arrays.asList(-1.0, 1.0, -5.0, 20.0, 5.0); + + for (double value : values) { + for (MutableAggregation aggregation : aggregations) { + aggregation.add(value); + } + } + + for (MutableAggregation aggregation : aggregations) { + aggregation.match( + new Function() { + @Override + public Void apply(MutableSum arg) { + assertThat(arg.getSum()).isWithin(TOLERANCE).of(20.0); + return null; + } + }, + new Function() { + @Override + public Void apply(MutableCount arg) { + assertThat(arg.getCount()).isEqualTo(5); + return null; + } + }, + new Function() { + @Override + public Void apply(MutableMean arg) { + assertThat(arg.getMean()).isWithin(TOLERANCE).of(4.0); + return null; + } + }, + new Function() { + @Override + public Void apply(MutableDistribution arg) { + assertThat(arg.getBucketCounts()).isEqualTo(new long[] {0, 2, 2, 1}); + return null; + } + }); + } + } + + @Test + public void testMatch() { + List aggregations = + Arrays.asList( + MutableSum.create(), + MutableCount.create(), + MutableMean.create(), + MutableDistribution.create(BUCKET_BOUNDARIES)); + + List actual = new ArrayList(); + for (MutableAggregation aggregation : aggregations) { + actual.add( + aggregation.match( + new Function() { + @Override + public String apply(MutableSum arg) { + return "SUM"; + } + }, + new Function() { + @Override + public String apply(MutableCount arg) { + return "COUNT"; + } + }, + new Function() { + @Override + public String apply(MutableMean arg) { + return "MEAN"; + } + }, + new Function() { + @Override + public String apply(MutableDistribution arg) { + return "DISTRIBUTION"; + } + })); + } + + assertThat(actual).isEqualTo(Arrays.asList("SUM", "COUNT", "MEAN", "DISTRIBUTION")); + } + + @Test + public void testCombine_SumCountMean() { + // combine() for Mutable Sum, Count and Mean will pick up fractional stats + List aggregations1 = + Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create()); + List aggregations2 = + Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create()); + + for (double val : Arrays.asList(-1.0, -5.0)) { + for (MutableAggregation aggregation : aggregations1) { + aggregation.add(val); + } + } + for (double val : Arrays.asList(10.0, 50.0)) { + for (MutableAggregation aggregation : aggregations2) { + aggregation.add(val); + } + } + + List combined = + Arrays.asList(MutableSum.create(), MutableCount.create(), MutableMean.create()); + double fraction1 = 1.0; + double fraction2 = 0.6; + for (int i = 0; i < combined.size(); i++) { + combined.get(i).combine(aggregations1.get(i), fraction1); + combined.get(i).combine(aggregations2.get(i), fraction2); + } + + assertThat(((MutableSum) combined.get(0)).getSum()).isWithin(TOLERANCE).of(30); + assertThat(((MutableCount) combined.get(1)).getCount()).isEqualTo(3); + assertThat(((MutableMean) combined.get(2)).getMean()).isWithin(TOLERANCE).of(10); + } + + @Test + public void testCombine_Distribution() { + // combine() for Mutable Distribution will ignore fractional stats + MutableDistribution distribution1 = MutableDistribution.create(BUCKET_BOUNDARIES); + MutableDistribution distribution2 = MutableDistribution.create(BUCKET_BOUNDARIES); + MutableDistribution distribution3 = MutableDistribution.create(BUCKET_BOUNDARIES); + + for (double val : Arrays.asList(5.0, -5.0)) { + distribution1.add(val); + } + for (double val : Arrays.asList(10.0, 20.0)) { + distribution2.add(val); + } + for (double val : Arrays.asList(-10.0, 15.0, -15.0, -20.0)) { + distribution3.add(val); + } + + MutableDistribution combined = MutableDistribution.create(BUCKET_BOUNDARIES); + combined.combine(distribution1, 1.0); // distribution1 will be combined + combined.combine(distribution2, 0.6); // distribution2 will be ignored + verifyMutableDistribution(combined, 0, 2, -5, 5, 50.0, new long[] {0, 1, 1, 0}, TOLERANCE); + + combined.combine(distribution2, 1.0); // distribution2 will be combined + verifyMutableDistribution(combined, 7.5, 4, -5, 20, 325.0, new long[] {0, 1, 1, 2}, TOLERANCE); + + combined.combine(distribution3, 1.0); // distribution3 will be combined + verifyMutableDistribution(combined, 0, 8, -20, 20, 1500.0, new long[] {2, 2, 1, 3}, TOLERANCE); + } + + private static void verifyMutableDistribution( + MutableDistribution mutableDistribution, + double mean, + long count, + double min, + double max, + double sumOfSquaredDeviations, + long[] bucketCounts, + double tolerance) { + assertThat(mutableDistribution.getMean()).isWithin(tolerance).of(mean); + assertThat(mutableDistribution.getCount()).isEqualTo(count); + assertThat(mutableDistribution.getMin()).isWithin(tolerance).of(min); + assertThat(mutableDistribution.getMax()).isWithin(tolerance).of(max); + assertThat(mutableDistribution.getSumOfSquaredDeviations()) + .isWithin(tolerance) + .of(sumOfSquaredDeviations); + assertThat(mutableDistribution.getBucketCounts()).isEqualTo(bucketCounts); + } +} 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 new file mode 100644 index 00000000..b4b4c85b --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/MutableViewDataTest.java @@ -0,0 +1,147 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.stats.MutableViewData.toMillis; + +import com.google.common.collect.ImmutableMap; +import io.opencensus.common.Duration; +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.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.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.MeanData; +import io.opencensus.stats.AggregationData.SumDataDouble; +import io.opencensus.stats.AggregationData.SumDataLong; +import io.opencensus.stats.BucketBoundaries; +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link MutableViewData}. */ +@RunWith(JUnit4.class) +public class MutableViewDataTest { + + private static final double EPSILON = 1e-7; + + private static final TagKey ORIGINATOR = TagKey.create("originator"); + private static final TagKey CALLER = TagKey.create("caller"); + private static final TagKey METHOD = TagKey.create("method"); + private static final TagValue CALLER_V = TagValue.create("some caller"); + private static final TagValue METHOD_V = TagValue.create("some method"); + private static final MeasureDouble MEASURE_DOUBLE = + MeasureDouble.create("measure1", "description", "1"); + private static final MeasureLong MEASURE_LONG = + MeasureLong.create("measure2", "description", "1"); + + @Test + public void testConstants() { + assertThat(MutableViewData.UNKNOWN_TAG_VALUE).isNull(); + assertThat(MutableViewData.ZERO_TIMESTAMP).isEqualTo(Timestamp.create(0, 0)); + } + + @Test + public void testGetTagValues() { + List columns = Arrays.asList(CALLER, METHOD, ORIGINATOR); + Map tags = ImmutableMap.of(CALLER, CALLER_V, METHOD, METHOD_V); + + assertThat(MutableViewData.getTagValues(tags, columns)) + .containsExactly(CALLER_V, METHOD_V, MutableViewData.UNKNOWN_TAG_VALUE) + .inOrder(); + } + + @Test + public void createMutableAggregation() { + BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0)); + + assertThat(((MutableSum) MutableViewData.createMutableAggregation(Sum.create())).getSum()) + .isWithin(EPSILON) + .of(0.0); + assertThat(((MutableCount) MutableViewData.createMutableAggregation(Count.create())).getCount()) + .isEqualTo(0L); + assertThat(((MutableMean) MutableViewData.createMutableAggregation(Mean.create())).getMean()) + .isWithin(EPSILON) + .of(0D); + + MutableDistribution mutableDistribution = + (MutableDistribution) + MutableViewData.createMutableAggregation(Distribution.create(bucketBoundaries)); + assertThat(mutableDistribution.getMin()).isPositiveInfinity(); + assertThat(mutableDistribution.getMax()).isNegativeInfinity(); + assertThat(mutableDistribution.getSumOfSquaredDeviations()).isWithin(EPSILON).of(0); + assertThat(mutableDistribution.getBucketCounts()).isEqualTo(new long[4]); + } + + @Test + public void createAggregationData() { + BucketBoundaries bucketBoundaries = BucketBoundaries.create(Arrays.asList(-1.0, 0.0, 1.0)); + List mutableAggregations = + Arrays.asList( + MutableCount.create(), + MutableMean.create(), + MutableDistribution.create(bucketBoundaries)); + List aggregates = new ArrayList(); + + 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)); + } + + assertThat(aggregates) + .containsExactly( + SumDataDouble.create(0), + SumDataLong.create(0), + CountData.create(0), + MeanData.create(0, 0), + DistributionData.create( + 0, + 0, + Double.POSITIVE_INFINITY, + Double.NEGATIVE_INFINITY, + 0, + Arrays.asList(new Long[] {0L, 0L, 0L, 0L}))) + .inOrder(); + } + + @Test + public void testDurationToMillis() { + assertThat(toMillis(Duration.create(0, 0))).isEqualTo(0); + assertThat(toMillis(Duration.create(0, 987000000))).isEqualTo(987); + assertThat(toMillis(Duration.create(3, 456000000))).isEqualTo(3456); + assertThat(toMillis(Duration.create(0, -1000000))).isEqualTo(-1); + assertThat(toMillis(Duration.create(-1, 0))).isEqualTo(-1000); + assertThat(toMillis(Duration.create(-3, -456000000))).isEqualTo(-3456); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java new file mode 100644 index 00000000..49131d8a --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsComponentImplBaseTest.java @@ -0,0 +1,73 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.implcore.internal.SimpleEventQueue; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.StatsComponent; +import io.opencensus.testing.common.TestClock; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link StatsComponentImplBase}. */ +@RunWith(JUnit4.class) +public final class StatsComponentImplBaseTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private final StatsComponent statsComponent = + new StatsComponentImplBase(new SimpleEventQueue(), TestClock.create()); + + @Test + public void defaultState() { + assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.ENABLED); + } + + @Test + public void setState_Disabled() { + statsComponent.setState(StatsCollectionState.DISABLED); + assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.DISABLED); + } + + @Test + public void setState_Enabled() { + statsComponent.setState(StatsCollectionState.DISABLED); + statsComponent.setState(StatsCollectionState.ENABLED); + assertThat(statsComponent.getState()).isEqualTo(StatsCollectionState.ENABLED); + } + + @Test + public void setState_DisallowsNull() { + thrown.expect(NullPointerException.class); + thrown.expectMessage("newState"); + statsComponent.setState(null); + } + + @Test + public void preventSettingStateAfterGettingState() { + statsComponent.setState(StatsCollectionState.DISABLED); + statsComponent.getState(); + thrown.expect(IllegalStateException.class); + thrown.expectMessage("State was already read, cannot set state."); + statsComponent.setState(StatsCollectionState.ENABLED); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java new file mode 100644 index 00000000..b0533d0d --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsRecorderImplTest.java @@ -0,0 +1,207 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.stats.MutableViewData.ZERO_TIMESTAMP; +import static io.opencensus.implcore.stats.StatsTestUtil.createEmptyViewData; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Lists; +import io.grpc.Context; +import io.opencensus.implcore.internal.SimpleEventQueue; +import io.opencensus.stats.Aggregation.Sum; +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.MeasureMap; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.StatsComponent; +import io.opencensus.stats.StatsRecorder; +import io.opencensus.stats.View; +import io.opencensus.stats.View.AggregationWindow.Cumulative; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; +import io.opencensus.stats.ViewManager; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.unsafe.ContextUtils; +import io.opencensus.testing.common.TestClock; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link StatsRecorderImpl}. */ +@RunWith(JUnit4.class) +public final class StatsRecorderImplTest { + private static final TagKey KEY = TagKey.create("KEY"); + private static final TagValue VALUE = TagValue.create("VALUE"); + private static final TagValue VALUE_2 = TagValue.create("VALUE_2"); + private static final MeasureDouble MEASURE_DOUBLE = + MeasureDouble.create("my measurement", "description", "us"); + private static final View.Name VIEW_NAME = View.Name.create("my view"); + + private final StatsComponent statsComponent = + new StatsComponentImplBase(new SimpleEventQueue(), TestClock.create()); + + private final ViewManager viewManager = statsComponent.getViewManager(); + private final StatsRecorder statsRecorder = statsComponent.getStatsRecorder(); + + @Test + public void record_CurrentContextNotSet() { + View view = + View.create( + VIEW_NAME, + "description", + MEASURE_DOUBLE, + Sum.create(), + Arrays.asList(KEY), + Cumulative.create()); + viewManager.registerView(view); + statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0).record(); + ViewData viewData = viewManager.getView(VIEW_NAME); + + // record() should have used the default TagContext, so the tag value should be null. + assertThat(viewData.getAggregationMap().keySet()) + .containsExactly(Arrays.asList((TagValue) null)); + } + + @Test + public void record_CurrentContextSet() { + View view = + View.create( + VIEW_NAME, + "description", + MEASURE_DOUBLE, + Sum.create(), + Arrays.asList(KEY), + Cumulative.create()); + viewManager.registerView(view); + Context orig = + Context.current() + .withValue(ContextUtils.TAG_CONTEXT_KEY, new SimpleTagContext(Tag.create(KEY, VALUE))) + .attach(); + try { + statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0).record(); + } finally { + Context.current().detach(orig); + } + ViewData viewData = viewManager.getView(VIEW_NAME); + + // record() should have used the given TagContext. + assertThat(viewData.getAggregationMap().keySet()).containsExactly(Arrays.asList(VALUE)); + } + + @Test + public void recordTwice() { + View view = + View.create( + VIEW_NAME, + "description", + MEASURE_DOUBLE, + Sum.create(), + Arrays.asList(KEY), + Cumulative.create()); + viewManager.registerView(view); + MeasureMap statsRecord = statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 1.0); + statsRecord.record(new SimpleTagContext(Tag.create(KEY, VALUE))); + statsRecord.record(new SimpleTagContext(Tag.create(KEY, VALUE_2))); + ViewData viewData = viewManager.getView(VIEW_NAME); + + // There should be two entries. + StatsTestUtil.assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 1.0), + Arrays.asList(VALUE_2), + StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 1.0)), + 1e-6); + } + + @Test + public void record_StatsDisabled() { + View view = + View.create( + VIEW_NAME, + "description", + MEASURE_DOUBLE, + Sum.create(), + Arrays.asList(KEY), + Cumulative.create()); + + viewManager.registerView(view); + statsComponent.setState(StatsCollectionState.DISABLED); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.0) + .record(new SimpleTagContext(Tag.create(KEY, VALUE))); + assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view)); + } + + @Test + public void record_StatsReenabled() { + View view = + View.create( + VIEW_NAME, + "description", + MEASURE_DOUBLE, + Sum.create(), + Arrays.asList(KEY), + Cumulative.create()); + viewManager.registerView(view); + + statsComponent.setState(StatsCollectionState.DISABLED); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.0) + .record(new SimpleTagContext(Tag.create(KEY, VALUE))); + assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view)); + + statsComponent.setState(StatsCollectionState.ENABLED); + assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); + assertThat(viewManager.getView(VIEW_NAME).getWindowData()) + .isNotEqualTo(CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 4.0) + .record(new SimpleTagContext(Tag.create(KEY, VALUE))); + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(Sum.create(), MEASURE_DOUBLE, 4.0)), + 1e-6); + } + + private static final class SimpleTagContext extends TagContext { + private final List tags; + + SimpleTagContext(Tag... tags) { + this.tags = Collections.unmodifiableList(Lists.newArrayList(tags)); + } + + @Override + protected Iterator getIterator() { + return tags.iterator(); + } + } +} 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 new file mode 100644 index 00000000..3a714af4 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/StatsTestUtil.java @@ -0,0 +1,183 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.stats.MutableViewData.ZERO_TIMESTAMP; + +import com.google.common.collect.Iterables; +import io.opencensus.common.Function; +import io.opencensus.common.Functions; +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.MeanData; +import io.opencensus.stats.AggregationData.SumDataDouble; +import io.opencensus.stats.AggregationData.SumDataLong; +import io.opencensus.stats.Measure; +import io.opencensus.stats.View; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewData.AggregationWindowData; +import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; +import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData; +import io.opencensus.tags.TagValue; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +/** Stats test utilities. */ +final class StatsTestUtil { + + private StatsTestUtil() {} + + /** + * Creates an {@link AggregationData} by adding the given sequence of values, based on the + * definition of the given {@link Aggregation}. + * + * @param aggregation the {@code Aggregation} to apply the values to. + * @param values the values to add to the {@code MutableAggregation}s. + * @return an {@code AggregationData}. + */ + static AggregationData createAggregationData( + Aggregation aggregation, Measure measure, double... values) { + MutableAggregation mutableAggregation = MutableViewData.createMutableAggregation(aggregation); + for (double value : values) { + mutableAggregation.add(value); + } + return MutableViewData.createAggregationData(mutableAggregation, measure); + } + + /** + * Compare the actual and expected AggregationMap within the given tolerance. + * + * @param expected the expected map. + * @param actual the actual mapping from {@code List} to {@code AggregationData}. + * @param tolerance the tolerance used for {@code double} comparison. + */ + static void assertAggregationMapEquals( + Map, ? extends AggregationData> actual, + Map, ? extends AggregationData> expected, + double tolerance) { + assertThat(actual.keySet()).containsExactlyElementsIn(expected.keySet()); + for (List tagValues : actual.keySet()) { + assertAggregationDataEquals(expected.get(tagValues), actual.get(tagValues), tolerance); + } + } + + /** + * Compare the expected and actual {@code AggregationData} within the given tolerance. + * + * @param expected the expected {@code AggregationData}. + * @param actual the actual {@code AggregationData}. + * @param tolerance the tolerance used for {@code double} comparison. + */ + static void assertAggregationDataEquals( + AggregationData expected, final AggregationData actual, final double tolerance) { + expected.match( + new Function() { + @Override + public Void apply(SumDataDouble arg) { + assertThat(actual).isInstanceOf(SumDataDouble.class); + assertThat(((SumDataDouble) actual).getSum()).isWithin(tolerance).of(arg.getSum()); + return null; + } + }, + new Function() { + @Override + public Void apply(SumDataLong arg) { + assertThat(actual).isInstanceOf(SumDataLong.class); + assertThat(((SumDataLong) actual).getSum()).isEqualTo(arg.getSum()); + return null; + } + }, + new Function() { + @Override + public Void apply(CountData arg) { + assertThat(actual).isInstanceOf(CountData.class); + assertThat(((CountData) actual).getCount()).isEqualTo(arg.getCount()); + return null; + } + }, + new Function() { + @Override + public Void apply(MeanData arg) { + assertThat(actual).isInstanceOf(MeanData.class); + assertThat(((MeanData) actual).getMean()).isWithin(tolerance).of(arg.getMean()); + return null; + } + }, + new Function() { + @Override + public Void apply(DistributionData arg) { + assertThat(actual).isInstanceOf(DistributionData.class); + assertDistributionDataEquals(arg, (DistributionData) actual, tolerance); + return null; + } + }, + Functions.throwIllegalArgumentException()); + } + + // Create an empty ViewData with the given View. + static ViewData createEmptyViewData(View view) { + return ViewData.create( + view, + Collections., AggregationData>emptyMap(), + view.getWindow() + .match( + Functions.returnConstant( + CumulativeData.create(ZERO_TIMESTAMP, ZERO_TIMESTAMP)), + Functions.returnConstant( + IntervalData.create(ZERO_TIMESTAMP)), + Functions.throwAssertionError())); + } + + // Compare the expected and actual DistributionData within the given tolerance. + private static void assertDistributionDataEquals( + DistributionData expected, DistributionData actual, double tolerance) { + assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean()); + assertThat(actual.getCount()).isEqualTo(expected.getCount()); + assertThat(actual.getMean()).isWithin(tolerance).of(expected.getMean()); + assertThat(actual.getSumOfSquaredDeviations()) + .isWithin(tolerance) + .of(expected.getSumOfSquaredDeviations()); + + if (expected.getMax() == Double.NEGATIVE_INFINITY + && expected.getMin() == Double.POSITIVE_INFINITY) { + assertThat(actual.getMax()).isNegativeInfinity(); + assertThat(actual.getMin()).isPositiveInfinity(); + } else { + assertThat(actual.getMax()).isWithin(tolerance).of(expected.getMax()); + assertThat(actual.getMin()).isWithin(tolerance).of(expected.getMin()); + } + + assertThat(removeTrailingZeros((actual).getBucketCounts())) + .isEqualTo(removeTrailingZeros(expected.getBucketCounts())); + } + + private static List removeTrailingZeros(List longs) { + if (longs == null) { + return null; + } + List truncated = new ArrayList(longs); + while (!truncated.isEmpty() && Iterables.getLast(truncated) == 0) { + truncated.remove(truncated.size() - 1); + } + return truncated; + } +} 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 new file mode 100644 index 00000000..5eaa34e5 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/stats/ViewManagerImplTest.java @@ -0,0 +1,924 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.stats; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.stats.StatsTestUtil.assertAggregationMapEquals; +import static io.opencensus.implcore.stats.StatsTestUtil.createAggregationData; +import static io.opencensus.implcore.stats.StatsTestUtil.createEmptyViewData; + +import com.google.common.collect.ImmutableMap; +import io.opencensus.common.Duration; +import io.opencensus.common.Timestamp; +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.Mean; +import io.opencensus.stats.Aggregation.Sum; +import io.opencensus.stats.AggregationData; +import io.opencensus.stats.AggregationData.MeanData; +import io.opencensus.stats.AggregationData.SumDataDouble; +import io.opencensus.stats.AggregationData.SumDataLong; +import io.opencensus.stats.BucketBoundaries; +import io.opencensus.stats.Measure; +import io.opencensus.stats.Measure.MeasureDouble; +import io.opencensus.stats.Measure.MeasureLong; +import io.opencensus.stats.MeasureMap; +import io.opencensus.stats.StatsCollectionState; +import io.opencensus.stats.View; +import io.opencensus.stats.View.AggregationWindow.Cumulative; +import io.opencensus.stats.View.AggregationWindow.Interval; +import io.opencensus.stats.View.Name; +import io.opencensus.stats.ViewData; +import io.opencensus.stats.ViewData.AggregationWindowData; +import io.opencensus.stats.ViewData.AggregationWindowData.CumulativeData; +import io.opencensus.stats.ViewData.AggregationWindowData.IntervalData; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TagsComponent; +import io.opencensus.testing.common.TestClock; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link ViewManagerImpl}. */ +@RunWith(JUnit4.class) +public class ViewManagerImplTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private static final TagKey KEY = TagKey.create("KEY"); + + private static final TagValue VALUE = TagValue.create("VALUE"); + private static final TagValue VALUE_2 = TagValue.create("VALUE_2"); + + private static final String MEASURE_NAME = "my measurement"; + + private static final String MEASURE_NAME_2 = "my measurement 2"; + + private static final String MEASURE_UNIT = "us"; + + private static final String MEASURE_DESCRIPTION = "measure description"; + + private static final MeasureDouble MEASURE_DOUBLE = + MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT); + + private static final MeasureLong MEASURE_LONG = + MeasureLong.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT); + + private static final Name VIEW_NAME = Name.create("my view"); + private static final Name VIEW_NAME_2 = Name.create("my view 2"); + + private static final String VIEW_DESCRIPTION = "view description"; + + private static final Cumulative CUMULATIVE = Cumulative.create(); + + private static final double EPSILON = 1e-7; + private static final int MILLIS_PER_SECOND = 1000; + private static final Duration TEN_SECONDS = Duration.create(10, 0); + + private static final BucketBoundaries BUCKET_BOUNDARIES = + BucketBoundaries.create( + Arrays.asList( + 0.0, 0.2, 0.5, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 10.0, 15.0, 20.0, 30.0, 40.0, 50.0)); + + private static final Sum SUM = Sum.create(); + private static final Mean MEAN = Mean.create(); + private static final Distribution DISTRIBUTION = Distribution.create(BUCKET_BOUNDARIES); + + private final TestClock clock = TestClock.create(); + + private final StatsComponentImplBase statsComponent = + new StatsComponentImplBase(new SimpleEventQueue(), clock); + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + + private final Tagger tagger = tagsComponent.getTagger(); + private final ViewManagerImpl viewManager = statsComponent.getViewManager(); + private final StatsRecorderImpl statsRecorder = statsComponent.getStatsRecorder(); + + private static View createCumulativeView() { + return createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); + } + + private static View createCumulativeView( + View.Name name, Measure measure, Aggregation aggregation, List keys) { + return View.create(name, VIEW_DESCRIPTION, measure, aggregation, keys, CUMULATIVE); + } + + @Test + public void testRegisterAndGetCumulativeView() { + View view = createCumulativeView(); + viewManager.registerView(view); + assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view); + assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); + assertThat(viewManager.getView(VIEW_NAME).getWindowData()).isInstanceOf(CumulativeData.class); + } + + @Test + public void testRegisterAndGetIntervalView() { + View intervalView = + View.create( + VIEW_NAME, + VIEW_DESCRIPTION, + MEASURE_DOUBLE, + DISTRIBUTION, + Arrays.asList(KEY), + Interval.create(Duration.create(60, 0))); + viewManager.registerView(intervalView); + assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(intervalView); + assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); + assertThat(viewManager.getView(VIEW_NAME).getWindowData()).isInstanceOf(IntervalData.class); + } + + @Test + public void allowRegisteringSameViewTwice() { + View view = createCumulativeView(); + viewManager.registerView(view); + viewManager.registerView(view); + assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view); + } + + @Test + public void preventRegisteringDifferentViewWithSameName() { + View view1 = + View.create( + VIEW_NAME, + "View description.", + MEASURE_DOUBLE, + DISTRIBUTION, + Arrays.asList(KEY), + CUMULATIVE); + View view2 = + View.create( + VIEW_NAME, + "This is a different description.", + MEASURE_DOUBLE, + DISTRIBUTION, + Arrays.asList(KEY), + CUMULATIVE); + testFailedToRegisterView( + view1, view2, "A different view with the same name is already registered"); + } + + @Test + public void preventRegisteringDifferentMeasureWithSameName() { + MeasureDouble measure1 = MeasureDouble.create("measure", "description", "1"); + MeasureLong measure2 = MeasureLong.create("measure", "description", "1"); + View view1 = + View.create( + VIEW_NAME, VIEW_DESCRIPTION, measure1, DISTRIBUTION, Arrays.asList(KEY), CUMULATIVE); + View view2 = + View.create( + VIEW_NAME_2, VIEW_DESCRIPTION, measure2, DISTRIBUTION, Arrays.asList(KEY), CUMULATIVE); + testFailedToRegisterView( + view1, view2, "A different measure with the same name is already registered"); + } + + private void testFailedToRegisterView(View view1, View view2, String message) { + viewManager.registerView(view1); + try { + thrown.expect(IllegalArgumentException.class); + thrown.expectMessage(message); + viewManager.registerView(view2); + } finally { + assertThat(viewManager.getView(VIEW_NAME).getView()).isEqualTo(view1); + } + } + + @Test + public void returnNullWhenGettingNonexistentViewData() { + assertThat(viewManager.getView(VIEW_NAME)).isNull(); + } + + @Test + public void testRecordDouble_distribution_cumulative() { + testRecordCumulative(MEASURE_DOUBLE, DISTRIBUTION, 10.0, 20.0, 30.0, 40.0); + } + + @Test + public void testRecordLong_distribution_cumulative() { + testRecordCumulative(MEASURE_LONG, DISTRIBUTION, 1000, 2000, 3000, 4000); + } + + @Test + public void testRecordDouble_sum_cumulative() { + testRecordCumulative(MEASURE_DOUBLE, SUM, 11.1, 22.2, 33.3, 44.4); + } + + @Test + public void testRecordLong_sum_cumulative() { + testRecordCumulative(MEASURE_LONG, SUM, 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)); + viewManager.registerView(view); + TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); + for (double val : values) { + putToMeasureMap(statsRecorder.newMeasureMap(), measure, val).record(tags); + } + clock.setTime(Timestamp.create(3, 4)); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertThat(viewData.getView()).isEqualTo(view); + assertThat(viewData.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(1, 2), Timestamp.create(3, 4))); + StatsTestUtil.assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(aggregation, measure, values)), + EPSILON); + } + + @Test + public void testRecordDouble_mean_interval() { + testRecordInterval( + MEASURE_DOUBLE, + MEAN, + new double[] {20.0, -1.0, 1.0, -5.0, 5.0}, + 9.0, + 30.0, + MeanData.create((19 * 0.6 + 1) / 4, 4), + MeanData.create(0.2 * 5 + 9, 1), + MeanData.create(30.0, 1)); + } + + @Test + public void testRecordLong_mean_interval() { + testRecordInterval( + MEASURE_LONG, + MEAN, + new double[] {1000, 2000, 3000, 4000, 5000}, + -5000, + 30, + MeanData.create((3000 * 0.6 + 12000) / 4, 4), + MeanData.create(-4000, 1), + MeanData.create(30, 1)); + } + + @Test + public void testRecordDouble_sum_interval() { + testRecordInterval( + MEASURE_DOUBLE, + SUM, + new double[] {20.0, -1.0, 1.0, -5.0, 5.0}, + 9.0, + 30.0, + SumDataDouble.create(19 * 0.6 + 1), + SumDataDouble.create(0.2 * 5 + 9), + SumDataDouble.create(30.0)); + } + + @Test + public void testRecordLong_sum_interval() { + testRecordInterval( + MEASURE_LONG, + SUM, + new double[] {1000, 2000, 3000, 4000, 5000}, + -5000, + 30, + SumDataLong.create(Math.round(3000 * 0.6 + 12000)), + SumDataLong.create(-4000), + SumDataLong.create(30)); + } + + private void testRecordInterval( + Measure measure, + Aggregation aggregation, + double[] initialValues, /* There are 5 initial values recorded before we call getView(). */ + double value6, + double value7, + AggregationData expectedValues1, + AggregationData expectedValues2, + AggregationData expectedValues3) { + // The interval is 10 seconds, i.e. values should expire after 10 seconds. + // Each bucket has a duration of 2.5 seconds. + View view = + View.create( + VIEW_NAME, + VIEW_DESCRIPTION, + measure, + aggregation, + Arrays.asList(KEY), + Interval.create(TEN_SECONDS)); + long startTimeMillis = 30 * MILLIS_PER_SECOND; // start at 30s + clock.setTime(Timestamp.fromMillis(startTimeMillis)); + viewManager.registerView(view); + + TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); + + for (int i = 1; i <= 5; i++) { + /* + * Add each value in sequence, at 31s, 32s, 33s, etc. + * 1st and 2nd values should fall into the first bucket [30.0, 32.5), + * 3rd and 4th values should fall into the second bucket [32.5, 35.0), + * 5th value should fall into the third bucket [35.0, 37.5). + */ + clock.setTime(Timestamp.fromMillis(startTimeMillis + i * MILLIS_PER_SECOND)); + putToMeasureMap(statsRecorder.newMeasureMap(), measure, initialValues[i - 1]).record(tags); + } + + clock.setTime(Timestamp.fromMillis(startTimeMillis + 8 * MILLIS_PER_SECOND)); + // 38s, no values should have expired + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(aggregation, measure, initialValues)), + EPSILON); + + clock.setTime(Timestamp.fromMillis(startTimeMillis + 11 * MILLIS_PER_SECOND)); + // 41s, 40% of the values in the first bucket should have expired (1 / 2.5 = 0.4). + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of(Arrays.asList(VALUE), expectedValues1), + EPSILON); + + clock.setTime(Timestamp.fromMillis(startTimeMillis + 12 * MILLIS_PER_SECOND)); + // 42s, add a new value value1, should fall into bucket [40.0, 42.5) + putToMeasureMap(statsRecorder.newMeasureMap(), measure, value6).record(tags); + + clock.setTime(Timestamp.fromMillis(startTimeMillis + 17 * MILLIS_PER_SECOND)); + // 47s, values in the first and second bucket should have expired, and 80% of values in the + // third bucket should have expired. The new value should persist. + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of(Arrays.asList(VALUE), expectedValues2), + EPSILON); + + clock.setTime(Timestamp.fromMillis(60 * MILLIS_PER_SECOND)); + // 60s, all previous values should have expired, add another value value2 + putToMeasureMap(statsRecorder.newMeasureMap(), measure, value7).record(tags); + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of(Arrays.asList(VALUE), expectedValues3), + EPSILON); + + clock.setTime(Timestamp.fromMillis(100 * MILLIS_PER_SECOND)); + // 100s, all values should have expired + assertThat(viewManager.getView(VIEW_NAME).getAggregationMap()).isEmpty(); + } + + @Test + public void getViewDoesNotClearStats() { + View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); + clock.setTime(Timestamp.create(10, 0)); + viewManager.registerView(view); + TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); + statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 0.1).record(tags); + clock.setTime(Timestamp.create(11, 0)); + ViewData viewData1 = viewManager.getView(VIEW_NAME); + assertThat(viewData1.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(10, 0), Timestamp.create(11, 0))); + StatsTestUtil.assertAggregationMapEquals( + viewData1.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 0.1)), + EPSILON); + + statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 0.2).record(tags); + clock.setTime(Timestamp.create(12, 0)); + ViewData viewData2 = viewManager.getView(VIEW_NAME); + + // The second view should have the same start time as the first view, and it should include both + // recorded values: + assertThat(viewData2.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(10, 0), Timestamp.create(12, 0))); + StatsTestUtil.assertAggregationMapEquals( + viewData2.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 0.1, 0.2)), + EPSILON); + } + + @Test + public void testRecordCumulativeMultipleTagValues() { + viewManager.registerView( + createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY))); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 10.0) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 30.0) + .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 50.0) + .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0), + Arrays.asList(VALUE_2), + createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0)), + EPSILON); + } + + @Test + public void testRecordIntervalMultipleTagValues() { + // The interval is 10 seconds, i.e. values should expire after 10 seconds. + View view = + View.create( + VIEW_NAME, + VIEW_DESCRIPTION, + MEASURE_DOUBLE, + DISTRIBUTION, + Arrays.asList(KEY), + Interval.create(TEN_SECONDS)); + clock.setTime(Timestamp.create(10, 0)); // Start at 10s + viewManager.registerView(view); + + // record for TagValue1 at 11s + clock.setTime(Timestamp.fromMillis(11 * MILLIS_PER_SECOND)); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 10.0) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + + // record for TagValue2 at 15s + clock.setTime(Timestamp.fromMillis(15 * MILLIS_PER_SECOND)); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 30.0) + .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 50.0) + .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); + + // get ViewData at 19s, no stats should have expired. + clock.setTime(Timestamp.fromMillis(19 * MILLIS_PER_SECOND)); + ViewData viewData1 = viewManager.getView(VIEW_NAME); + StatsTestUtil.assertAggregationMapEquals( + viewData1.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0), + Arrays.asList(VALUE_2), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0)), + EPSILON); + + // record for TagValue2 again at 20s + clock.setTime(Timestamp.fromMillis(20 * MILLIS_PER_SECOND)); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 40.0) + .record(tagger.emptyBuilder().put(KEY, VALUE_2).build()); + + // get ViewData at 25s, stats for TagValue1 should have expired. + clock.setTime(Timestamp.fromMillis(25 * MILLIS_PER_SECOND)); + ViewData viewData2 = viewManager.getView(VIEW_NAME); + StatsTestUtil.assertAggregationMapEquals( + viewData2.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE_2), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 30.0, 50.0, 40.0)), + EPSILON); + + // get ViewData at 30s, the first two values for TagValue2 should have expired. + clock.setTime(Timestamp.fromMillis(30 * MILLIS_PER_SECOND)); + ViewData viewData3 = viewManager.getView(VIEW_NAME); + StatsTestUtil.assertAggregationMapEquals( + viewData3.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE_2), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 40.0)), + EPSILON); + + // get ViewData at 40s, all stats should have expired. + clock.setTime(Timestamp.fromMillis(40 * MILLIS_PER_SECOND)); + ViewData viewData4 = viewManager.getView(VIEW_NAME); + assertThat(viewData4.getAggregationMap()).isEmpty(); + } + + // This test checks that MeasureMaper.record(...) does not throw an exception when no views are + // registered. + @Test + public void allowRecordingWithoutRegisteringMatchingViewData() { + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 10) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + } + + @Test + public void testRecordWithEmptyStatsContext() { + viewManager.registerView( + createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY))); + // DEFAULT doesn't have tags, but the view has tag key "KEY". + statsRecorder.newMeasureMap().put(MEASURE_DOUBLE, 10.0).record(tagger.empty()); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + // Tag is missing for associated measureValues, should use default tag value + // "unknown/not set". + Arrays.asList(MutableViewData.UNKNOWN_TAG_VALUE), + // Should record stats with default tag value: "KEY" : "unknown/not set". + createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0)), + EPSILON); + } + + @Test + public void testRecord_MeasureNameNotMatch() { + testRecord_MeasureNotMatch( + MeasureDouble.create(MEASURE_NAME, "measure", MEASURE_UNIT), + MeasureDouble.create(MEASURE_NAME_2, "measure", MEASURE_UNIT), + 10.0); + } + + @Test + public void testRecord_MeasureTypeNotMatch() { + testRecord_MeasureNotMatch( + MeasureLong.create(MEASURE_NAME, "measure", MEASURE_UNIT), + MeasureDouble.create(MEASURE_NAME, "measure", MEASURE_UNIT), + 10.0); + } + + private void testRecord_MeasureNotMatch(Measure measure1, Measure measure2, double value) { + viewManager.registerView(createCumulativeView(VIEW_NAME, measure1, MEAN, Arrays.asList(KEY))); + TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); + putToMeasureMap(statsRecorder.newMeasureMap(), measure2, value).record(tags); + ViewData view = viewManager.getView(VIEW_NAME); + assertThat(view.getAggregationMap()).isEmpty(); + } + + @Test + public void testRecordWithTagsThatDoNotMatchViewData() { + viewManager.registerView( + createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY))); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 10.0) + .record(tagger.emptyBuilder().put(TagKey.create("wrong key"), VALUE).build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 50.0) + .record(tagger.emptyBuilder().put(TagKey.create("another wrong key"), VALUE).build()); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + // Won't record the unregistered tag key, for missing registered keys will use default + // tag value : "unknown/not set". + Arrays.asList(MutableViewData.UNKNOWN_TAG_VALUE), + // Should record stats with default tag value: "KEY" : "unknown/not set". + createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 10.0, 50.0)), + EPSILON); + } + + @Test + public void testViewDataWithMultipleTagKeys() { + TagKey key1 = TagKey.create("Key-1"); + TagKey key2 = TagKey.create("Key-2"); + viewManager.registerView( + createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(key1, key2))); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record( + tagger + .emptyBuilder() + .put(key1, TagValue.create("v1")) + .put(key2, TagValue.create("v10")) + .build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 2.2) + .record( + tagger + .emptyBuilder() + .put(key1, TagValue.create("v1")) + .put(key2, TagValue.create("v20")) + .build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 3.3) + .record( + tagger + .emptyBuilder() + .put(key1, TagValue.create("v2")) + .put(key2, TagValue.create("v10")) + .build()); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 4.4) + .record( + tagger + .emptyBuilder() + .put(key1, TagValue.create("v1")) + .put(key2, TagValue.create("v10")) + .build()); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(TagValue.create("v1"), TagValue.create("v10")), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 1.1, 4.4), + Arrays.asList(TagValue.create("v1"), TagValue.create("v20")), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 2.2), + Arrays.asList(TagValue.create("v2"), TagValue.create("v10")), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 3.3)), + EPSILON); + } + + @Test + public void testMultipleViewSameMeasure() { + final View view1 = + createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); + final View view2 = + createCumulativeView(VIEW_NAME_2, MEASURE_DOUBLE, DISTRIBUTION, Arrays.asList(KEY)); + clock.setTime(Timestamp.create(1, 1)); + viewManager.registerView(view1); + clock.setTime(Timestamp.create(2, 2)); + viewManager.registerView(view2); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 5.0) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + clock.setTime(Timestamp.create(3, 3)); + ViewData viewData1 = viewManager.getView(VIEW_NAME); + clock.setTime(Timestamp.create(4, 4)); + ViewData viewData2 = viewManager.getView(VIEW_NAME_2); + assertThat(viewData1.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(1, 1), Timestamp.create(3, 3))); + StatsTestUtil.assertAggregationMapEquals( + viewData1.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 5.0)), + EPSILON); + assertThat(viewData2.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(2, 2), Timestamp.create(4, 4))); + StatsTestUtil.assertAggregationMapEquals( + viewData2.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, MEASURE_DOUBLE, 5.0)), + EPSILON); + } + + @Test + public void testMultipleViews_DifferentMeasureNames() { + testMultipleViews_DifferentMeasures( + MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT), + MeasureDouble.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT), + 1.1, + 2.2); + } + + @Test + public void testMultipleViews_DifferentMeasureTypes() { + testMultipleViews_DifferentMeasures( + MeasureDouble.create(MEASURE_NAME, MEASURE_DESCRIPTION, MEASURE_UNIT), + MeasureLong.create(MEASURE_NAME_2, MEASURE_DESCRIPTION, MEASURE_UNIT), + 1.1, + 5000); + } + + private void testMultipleViews_DifferentMeasures( + Measure measure1, Measure measure2, double value1, double value2) { + final View view1 = createCumulativeView(VIEW_NAME, measure1, DISTRIBUTION, Arrays.asList(KEY)); + final View view2 = + createCumulativeView(VIEW_NAME_2, measure2, DISTRIBUTION, Arrays.asList(KEY)); + clock.setTime(Timestamp.create(1, 0)); + viewManager.registerView(view1); + clock.setTime(Timestamp.create(2, 0)); + viewManager.registerView(view2); + TagContext tags = tagger.emptyBuilder().put(KEY, VALUE).build(); + MeasureMap measureMap = statsRecorder.newMeasureMap(); + putToMeasureMap(measureMap, measure1, value1); + putToMeasureMap(measureMap, measure2, value2); + measureMap.record(tags); + clock.setTime(Timestamp.create(3, 0)); + ViewData viewData1 = viewManager.getView(VIEW_NAME); + clock.setTime(Timestamp.create(4, 0)); + ViewData viewData2 = viewManager.getView(VIEW_NAME_2); + assertThat(viewData1.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0))); + StatsTestUtil.assertAggregationMapEquals( + viewData1.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, measure1, value1)), + EPSILON); + assertThat(viewData2.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(2, 0), Timestamp.create(4, 0))); + StatsTestUtil.assertAggregationMapEquals( + viewData2.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(DISTRIBUTION, measure2, value2)), + EPSILON); + } + + @Test + public void testGetCumulativeViewDataWithEmptyBucketBoundaries() { + Aggregation noHistogram = + Distribution.create(BucketBoundaries.create(Collections.emptyList())); + View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, noHistogram, Arrays.asList(KEY)); + clock.setTime(Timestamp.create(1, 0)); + viewManager.registerView(view); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + clock.setTime(Timestamp.create(3, 0)); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertThat(viewData.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0))); + StatsTestUtil.assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(noHistogram, MEASURE_DOUBLE, 1.1)), + EPSILON); + } + + @Test + public void testGetCumulativeViewDataWithoutBucketBoundaries() { + View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); + clock.setTime(Timestamp.create(1, 0)); + viewManager.registerView(view); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + clock.setTime(Timestamp.create(3, 0)); + ViewData viewData = viewManager.getView(VIEW_NAME); + assertThat(viewData.getWindowData()) + .isEqualTo(CumulativeData.create(Timestamp.create(1, 0), Timestamp.create(3, 0))); + StatsTestUtil.assertAggregationMapEquals( + viewData.getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)), + EPSILON); + } + + @Test + public void registerRecordAndGetView_StatsDisabled() { + statsComponent.setState(StatsCollectionState.DISABLED); + View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); + viewManager.registerView(view); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + assertThat(viewManager.getView(VIEW_NAME)).isEqualTo(createEmptyViewData(view)); + } + + @Test + public void registerRecordAndGetView_StatsReenabled() { + statsComponent.setState(StatsCollectionState.DISABLED); + statsComponent.setState(StatsCollectionState.ENABLED); + View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); + viewManager.registerView(view); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)), + EPSILON); + } + + @Test + public void registerViewWithStatsDisabled_RecordAndGetViewWithStatsEnabled() { + statsComponent.setState(StatsCollectionState.DISABLED); + View view = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); + viewManager.registerView(view); // view will still be registered. + + statsComponent.setState(StatsCollectionState.ENABLED); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(VIEW_NAME).getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), StatsTestUtil.createAggregationData(MEAN, MEASURE_DOUBLE, 1.1)), + EPSILON); + } + + @Test + public void registerDifferentViewWithSameNameWithStatsDisabled() { + statsComponent.setState(StatsCollectionState.DISABLED); + View view1 = + View.create( + VIEW_NAME, + "View description.", + MEASURE_DOUBLE, + DISTRIBUTION, + Arrays.asList(KEY), + CUMULATIVE); + View view2 = + View.create( + VIEW_NAME, + "This is a different description.", + MEASURE_DOUBLE, + DISTRIBUTION, + Arrays.asList(KEY), + CUMULATIVE); + testFailedToRegisterView( + view1, view2, "A different view with the same name is already registered"); + } + + @Test + public void settingStateToDisabledWillClearStats_Cumulative() { + View cumulativeView = createCumulativeView(VIEW_NAME, MEASURE_DOUBLE, MEAN, Arrays.asList(KEY)); + settingStateToDisabledWillClearStats(cumulativeView); + } + + @Test + public void settingStateToDisabledWillClearStats_Interval() { + View intervalView = + View.create( + VIEW_NAME_2, + VIEW_DESCRIPTION, + MEASURE_DOUBLE, + MEAN, + Arrays.asList(KEY), + Interval.create(Duration.create(60, 0))); + settingStateToDisabledWillClearStats(intervalView); + } + + private void settingStateToDisabledWillClearStats(View view) { + Timestamp timestamp1 = Timestamp.create(1, 0); + clock.setTime(timestamp1); + viewManager.registerView(view); + statsRecorder + .newMeasureMap() + .put(MEASURE_DOUBLE, 1.1) + .record(tagger.emptyBuilder().put(KEY, VALUE).build()); + StatsTestUtil.assertAggregationMapEquals( + viewManager.getView(view.getName()).getAggregationMap(), + ImmutableMap.of( + Arrays.asList(VALUE), + StatsTestUtil.createAggregationData(view.getAggregation(), view.getMeasure(), 1.1)), + EPSILON); + + Timestamp timestamp2 = Timestamp.create(2, 0); + clock.setTime(timestamp2); + statsComponent.setState(StatsCollectionState.DISABLED); // This will clear stats. + assertThat(viewManager.getView(view.getName())).isEqualTo(createEmptyViewData(view)); + + Timestamp timestamp3 = Timestamp.create(3, 0); + clock.setTime(timestamp3); + statsComponent.setState(StatsCollectionState.ENABLED); + + Timestamp timestamp4 = Timestamp.create(4, 0); + clock.setTime(timestamp4); + // This ViewData does not have any stats, but it should not be an empty ViewData, since it has + // non-zero TimeStamps. + ViewData viewData = viewManager.getView(view.getName()); + assertThat(viewData.getAggregationMap()).isEmpty(); + AggregationWindowData windowData = viewData.getWindowData(); + if (windowData instanceof CumulativeData) { + assertThat(windowData).isEqualTo(CumulativeData.create(timestamp3, timestamp4)); + } else { + assertThat(windowData).isEqualTo(IntervalData.create(timestamp4)); + } + } + + private static MeasureMap putToMeasureMap(MeasureMap measureMap, Measure measure, double value) { + if (measure instanceof MeasureDouble) { + return measureMap.put((MeasureDouble) measure, value); + } else if (measure instanceof MeasureLong) { + return measureMap.put((MeasureLong) measure, Math.round(value)); + } else { + // Future measures. + throw new AssertionError(); + } + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java new file mode 100644 index 00000000..1a14ac6e --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTagContextUtilsTest.java @@ -0,0 +1,103 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; + +import com.google.common.collect.ImmutableSet; +import io.grpc.Context; +import io.opencensus.common.Scope; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.unsafe.ContextUtils; +import java.util.Iterator; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link CurrentTagContextUtils}. */ +@RunWith(JUnit4.class) +public class CurrentTagContextUtilsTest { + private static final Tag TAG = Tag.create(TagKey.create("key"), TagValue.create("value")); + + private final TagContext tagContext = + new TagContext() { + + @Override + protected Iterator getIterator() { + return ImmutableSet.of(TAG).iterator(); + } + }; + + @Test + public void testGetCurrentTagContext_DefaultContext() { + TagContext tags = CurrentTagContextUtils.getCurrentTagContext(); + assertThat(tags).isNotNull(); + assertThat(tagContextToList(tags)).isEmpty(); + } + + @Test + public void testGetCurrentTagContext_ContextSetToNull() { + Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, null).attach(); + try { + TagContext tags = CurrentTagContextUtils.getCurrentTagContext(); + assertThat(tags).isNotNull(); + assertThat(tagContextToList(tags)).isEmpty(); + } finally { + Context.current().detach(orig); + } + } + + @Test + public void testWithTagContext() { + assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty(); + Scope scopedTags = CurrentTagContextUtils.withTagContext(tagContext); + try { + assertThat(CurrentTagContextUtils.getCurrentTagContext()).isSameAs(tagContext); + } finally { + scopedTags.close(); + } + assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty(); + } + + @Test + public void testWithTagContextUsingWrap() { + Runnable runnable; + Scope scopedTags = CurrentTagContextUtils.withTagContext(tagContext); + try { + assertThat(CurrentTagContextUtils.getCurrentTagContext()).isSameAs(tagContext); + runnable = + Context.current() + .wrap( + new Runnable() { + @Override + public void run() { + assertThat(CurrentTagContextUtils.getCurrentTagContext()) + .isSameAs(tagContext); + } + }); + } finally { + scopedTags.close(); + } + assertThat(tagContextToList(CurrentTagContextUtils.getCurrentTagContext())).isEmpty(); + // When we run the runnable we will have the TagContext in the current Context. + runnable.run(); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java new file mode 100644 index 00000000..244b6711 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/CurrentTaggingStateTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.tags.TaggingState; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link CurrentTaggingState}. */ +@RunWith(JUnit4.class) +public final class CurrentTaggingStateTest { + + @Test + public void defaultState() { + assertThat(new CurrentTaggingState().get()).isEqualTo(TaggingState.ENABLED); + } + + @Test + public void setState() { + CurrentTaggingState state = new CurrentTaggingState(); + state.set(TaggingState.DISABLED); + assertThat(state.get()).isEqualTo(TaggingState.DISABLED); + state.set(TaggingState.ENABLED); + assertThat(state.get()).isEqualTo(TaggingState.ENABLED); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java new file mode 100644 index 00000000..c24cccb9 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/ScopedTagContextsTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; + +import io.opencensus.common.Scope; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for the methods in {@link TaggerImpl} and {@link TagContextBuilderImpl} that interact + * with the current {@link TagContext}. + */ +@RunWith(JUnit4.class) +public class ScopedTagContextsTest { + private static final TagKey KEY_1 = TagKey.create("key 1"); + private static final TagKey KEY_2 = TagKey.create("key 2"); + + private static final TagValue VALUE_1 = TagValue.create("value 1"); + private static final TagValue VALUE_2 = TagValue.create("value 2"); + + private final Tagger tagger = new TaggerImpl(new CurrentTaggingState()); + + @Test + public void defaultTagContext() { + TagContext defaultTagContext = tagger.getCurrentTagContext(); + assertThat(tagContextToList(defaultTagContext)).isEmpty(); + assertThat(defaultTagContext).isInstanceOf(TagContextImpl.class); + } + + @Test + public void withTagContext() { + assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); + TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build(); + Scope scope = tagger.withTagContext(scopedTags); + try { + assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags); + } finally { + scope.close(); + } + assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); + } + + @Test + public void createBuilderFromCurrentTags() { + TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build(); + Scope scope = tagger.withTagContext(scopedTags); + try { + TagContext newTags = tagger.currentBuilder().put(KEY_2, VALUE_2).build(); + assertThat(tagContextToList(newTags)) + .containsExactly(Tag.create(KEY_1, VALUE_1), Tag.create(KEY_2, VALUE_2)); + assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags); + } finally { + scope.close(); + } + } + + @Test + public void setCurrentTagsWithBuilder() { + assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); + Scope scope = tagger.emptyBuilder().put(KEY_1, VALUE_1).buildScoped(); + try { + assertThat(tagContextToList(tagger.getCurrentTagContext())) + .containsExactly(Tag.create(KEY_1, VALUE_1)); + } finally { + scope.close(); + } + assertThat(tagContextToList(tagger.getCurrentTagContext())).isEmpty(); + } + + @Test + public void addToCurrentTagsWithBuilder() { + TagContext scopedTags = tagger.emptyBuilder().put(KEY_1, VALUE_1).build(); + Scope scope1 = tagger.withTagContext(scopedTags); + try { + Scope scope2 = tagger.currentBuilder().put(KEY_2, VALUE_2).buildScoped(); + try { + assertThat(tagContextToList(tagger.getCurrentTagContext())) + .containsExactly(Tag.create(KEY_1, VALUE_1), Tag.create(KEY_2, VALUE_2)); + } finally { + scope2.close(); + } + assertThat(tagger.getCurrentTagContext()).isSameAs(scopedTags); + } finally { + scope1.close(); + } + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java new file mode 100644 index 00000000..b70d8b4e --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagContextImplTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.google.common.collect.Lists; +import com.google.common.testing.EqualsTester; +import io.opencensus.tags.InternalUtils; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import java.util.Arrays; +import java.util.Iterator; +import java.util.NoSuchElementException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link TagContextImpl} and {@link TagContextBuilderImpl}. */ +// TODO(sebright): Add more tests once the API is finalized. +@RunWith(JUnit4.class) +public class TagContextImplTest { + private final Tagger tagger = new TaggerImpl(new CurrentTaggingState()); + + private static final TagKey KS1 = TagKey.create("k1"); + private static final TagKey KS2 = TagKey.create("k2"); + + private static final TagValue V1 = TagValue.create("v1"); + private static final TagValue V2 = TagValue.create("v2"); + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + @Test + public void testSet() { + TagContext tags = tagger.emptyBuilder().put(KS1, V1).build(); + assertThat(tagContextToList(tagger.toBuilder(tags).put(KS1, V2).build())) + .containsExactly(Tag.create(KS1, V2)); + assertThat(tagContextToList(tagger.toBuilder(tags).put(KS2, V2).build())) + .containsExactly(Tag.create(KS1, V1), Tag.create(KS2, V2)); + } + + @Test + public void testClear() { + TagContext tags = tagger.emptyBuilder().put(KS1, V1).build(); + assertThat(tagContextToList(tagger.toBuilder(tags).remove(KS1).build())).isEmpty(); + assertThat(tagContextToList(tagger.toBuilder(tags).remove(KS2).build())) + .containsExactly(Tag.create(KS1, V1)); + } + + @Test + public void testIterator() { + TagContext tags = tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(); + Iterator i = InternalUtils.getTags(tags); + assertTrue(i.hasNext()); + Tag tag1 = i.next(); + assertTrue(i.hasNext()); + Tag tag2 = i.next(); + assertFalse(i.hasNext()); + assertThat(Arrays.asList(tag1, tag2)).containsExactly(Tag.create(KS1, V1), Tag.create(KS2, V2)); + thrown.expect(NoSuchElementException.class); + i.next(); + } + + @Test + public void disallowCallingRemoveOnIterator() { + TagContext tags = tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(); + Iterator i = InternalUtils.getTags(tags); + i.next(); + thrown.expect(UnsupportedOperationException.class); + i.remove(); + } + + @Test + public void testEquals() { + new EqualsTester() + .addEqualityGroup( + tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(), + tagger.emptyBuilder().put(KS1, V1).put(KS2, V2).build(), + tagger.emptyBuilder().put(KS2, V2).put(KS1, V1).build(), + new TagContext() { + @Override + protected Iterator getIterator() { + return Lists.newArrayList(Tag.create(KS1, V1), Tag.create(KS2, V2)).iterator(); + } + }) + .addEqualityGroup(tagger.emptyBuilder().put(KS1, V1).put(KS2, V1).build()) + .addEqualityGroup(tagger.emptyBuilder().put(KS1, V2).put(KS2, V1).build()) + .testEquals(); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java new file mode 100644 index 00000000..4ca2ae76 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TaggerImplTest.java @@ -0,0 +1,318 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.truth.Truth.assertThat; +import static io.opencensus.implcore.tags.TagsTestUtil.tagContextToList; + +import com.google.common.collect.Lists; +import io.grpc.Context; +import io.opencensus.common.Scope; +import io.opencensus.implcore.internal.NoopScope; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagContextBuilder; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TaggingState; +import io.opencensus.tags.TagsComponent; +import io.opencensus.tags.unsafe.ContextUtils; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link TaggerImpl}. */ +@RunWith(JUnit4.class) +public class TaggerImplTest { + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + private final Tagger tagger = tagsComponent.getTagger(); + + private static final TagKey K1 = TagKey.create("k1"); + private static final TagKey K2 = TagKey.create("k2"); + private static final TagKey K3 = TagKey.create("k3"); + + private static final TagValue V1 = TagValue.create("v1"); + private static final TagValue V2 = TagValue.create("v2"); + private static final TagValue V3 = TagValue.create("v3"); + + private static final Tag TAG1 = Tag.create(K1, V1); + private static final Tag TAG2 = Tag.create(K2, V2); + private static final Tag TAG3 = Tag.create(K3, V3); + + @Test + public void empty() { + assertThat(tagContextToList(tagger.empty())).isEmpty(); + assertThat(tagger.empty()).isInstanceOf(TagContextImpl.class); + } + + @Test + public void empty_TaggingDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagContextToList(tagger.empty())).isEmpty(); + assertThat(tagger.empty()).isInstanceOf(TagContextImpl.class); + } + + @Test + public void emptyBuilder() { + TagContextBuilder builder = tagger.emptyBuilder(); + assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); + assertThat(tagContextToList(builder.build())).isEmpty(); + } + + @Test + public void emptyBuilder_TaggingDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagger.emptyBuilder()).isSameAs(NoopTagContextBuilder.INSTANCE); + } + + @Test + public void emptyBuilder_TaggingReenabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagger.emptyBuilder()).isSameAs(NoopTagContextBuilder.INSTANCE); + tagsComponent.setState(TaggingState.ENABLED); + TagContextBuilder builder = tagger.emptyBuilder(); + assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); + assertThat(tagContextToList(builder.put(K1, V1).build())).containsExactly(Tag.create(K1, V1)); + } + + @Test + public void currentBuilder() { + TagContext tags = new SimpleTagContext(TAG1, TAG2, TAG3); + TagContextBuilder result = getResultOfCurrentBuilder(tags); + assertThat(result).isInstanceOf(TagContextBuilderImpl.class); + assertThat(tagContextToList(result.build())).containsExactly(TAG1, TAG2, TAG3); + } + + @Test + public void currentBuilder_DefaultIsEmpty() { + TagContextBuilder currentBuilder = tagger.currentBuilder(); + assertThat(currentBuilder).isInstanceOf(TagContextBuilderImpl.class); + assertThat(tagContextToList(currentBuilder.build())).isEmpty(); + } + + @Test + public void currentBuilder_RemoveDuplicateTags() { + Tag tag1 = Tag.create(K1, V1); + Tag tag2 = Tag.create(K1, V2); + TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); + TagContextBuilder result = getResultOfCurrentBuilder(tagContextWithDuplicateTags); + assertThat(tagContextToList(result.build())).containsExactly(tag2); + } + + @Test + public void currentBuilder_SkipNullTag() { + TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); + TagContextBuilder result = getResultOfCurrentBuilder(tagContextWithNullTag); + assertThat(tagContextToList(result.build())).containsExactly(TAG1, TAG2); + } + + @Test + public void currentBuilder_TaggingDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(getResultOfCurrentBuilder(new SimpleTagContext(TAG1))) + .isSameAs(NoopTagContextBuilder.INSTANCE); + } + + @Test + public void currentBuilder_TaggingReenabled() { + TagContext tags = new SimpleTagContext(TAG1); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(getResultOfCurrentBuilder(tags)).isSameAs(NoopTagContextBuilder.INSTANCE); + tagsComponent.setState(TaggingState.ENABLED); + TagContextBuilder builder = getResultOfCurrentBuilder(tags); + assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); + assertThat(tagContextToList(builder.build())).containsExactly(TAG1); + } + + private TagContextBuilder getResultOfCurrentBuilder(TagContext tagsToSet) { + Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tagsToSet).attach(); + try { + return tagger.currentBuilder(); + } finally { + Context.current().detach(orig); + } + } + + @Test + public void toBuilder_ConvertUnknownTagContextToTagContextImpl() { + TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3); + TagContext newTagContext = tagger.toBuilder(unknownTagContext).build(); + assertThat(tagContextToList(newTagContext)).containsExactly(TAG1, TAG2, TAG3); + assertThat(newTagContext).isInstanceOf(TagContextImpl.class); + } + + @Test + public void toBuilder_RemoveDuplicatesFromUnknownTagContext() { + Tag tag1 = Tag.create(K1, V1); + Tag tag2 = Tag.create(K1, V2); + TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); + TagContext newTagContext = tagger.toBuilder(tagContextWithDuplicateTags).build(); + assertThat(tagContextToList(newTagContext)).containsExactly(tag2); + } + + @Test + public void toBuilder_SkipNullTag() { + TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); + TagContext newTagContext = tagger.toBuilder(tagContextWithNullTag).build(); + assertThat(tagContextToList(newTagContext)).containsExactly(TAG1, TAG2); + } + + @Test + public void toBuilder_TaggingDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagger.toBuilder(new SimpleTagContext(TAG1))) + .isSameAs(NoopTagContextBuilder.INSTANCE); + } + + @Test + public void toBuilder_TaggingReenabled() { + TagContext tags = new SimpleTagContext(TAG1); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagger.toBuilder(tags)).isSameAs(NoopTagContextBuilder.INSTANCE); + tagsComponent.setState(TaggingState.ENABLED); + TagContextBuilder builder = tagger.toBuilder(tags); + assertThat(builder).isInstanceOf(TagContextBuilderImpl.class); + assertThat(tagContextToList(builder.build())).containsExactly(TAG1); + } + + @Test + public void getCurrentTagContext_DefaultIsEmptyTagContextImpl() { + TagContext currentTagContext = tagger.getCurrentTagContext(); + assertThat(tagContextToList(currentTagContext)).isEmpty(); + assertThat(currentTagContext).isInstanceOf(TagContextImpl.class); + } + + @Test + public void getCurrentTagContext_ConvertUnknownTagContextToTagContextImpl() { + TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3); + TagContext result = getResultOfGetCurrentTagContext(unknownTagContext); + assertThat(result).isInstanceOf(TagContextImpl.class); + assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2, TAG3); + } + + @Test + public void getCurrentTagContext_RemoveDuplicatesFromUnknownTagContext() { + Tag tag1 = Tag.create(K1, V1); + Tag tag2 = Tag.create(K1, V2); + TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); + TagContext result = getResultOfGetCurrentTagContext(tagContextWithDuplicateTags); + assertThat(tagContextToList(result)).containsExactly(tag2); + } + + @Test + public void getCurrentTagContext_SkipNullTag() { + TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); + TagContext result = getResultOfGetCurrentTagContext(tagContextWithNullTag); + assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2); + } + + @Test + public void getCurrentTagContext_TaggingDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagContextToList(getResultOfGetCurrentTagContext(new SimpleTagContext(TAG1)))) + .isEmpty(); + } + + @Test + public void getCurrentTagContext_TaggingReenabled() { + TagContext tags = new SimpleTagContext(TAG1); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagContextToList(getResultOfGetCurrentTagContext(tags))).isEmpty(); + tagsComponent.setState(TaggingState.ENABLED); + assertThat(tagContextToList(getResultOfGetCurrentTagContext(tags))).containsExactly(TAG1); + } + + private TagContext getResultOfGetCurrentTagContext(TagContext tagsToSet) { + Context orig = Context.current().withValue(ContextUtils.TAG_CONTEXT_KEY, tagsToSet).attach(); + try { + return tagger.getCurrentTagContext(); + } finally { + Context.current().detach(orig); + } + } + + @Test + public void withTagContext_ConvertUnknownTagContextToTagContextImpl() { + TagContext unknownTagContext = new SimpleTagContext(TAG1, TAG2, TAG3); + TagContext result = getResultOfWithTagContext(unknownTagContext); + assertThat(result).isInstanceOf(TagContextImpl.class); + assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2, TAG3); + } + + @Test + public void withTagContext_RemoveDuplicatesFromUnknownTagContext() { + Tag tag1 = Tag.create(K1, V1); + Tag tag2 = Tag.create(K1, V2); + TagContext tagContextWithDuplicateTags = new SimpleTagContext(tag1, tag2); + TagContext result = getResultOfWithTagContext(tagContextWithDuplicateTags); + assertThat(tagContextToList(result)).containsExactly(tag2); + } + + @Test + public void withTagContext_SkipNullTag() { + TagContext tagContextWithNullTag = new SimpleTagContext(TAG1, null, TAG2); + TagContext result = getResultOfWithTagContext(tagContextWithNullTag); + assertThat(tagContextToList(result)).containsExactly(TAG1, TAG2); + } + + @Test + public void withTagContext_ReturnsNoopScopeWhenTaggingIsDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagger.withTagContext(new SimpleTagContext(TAG1))).isSameAs(NoopScope.getInstance()); + } + + @Test + public void withTagContext_TaggingDisabled() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagContextToList(getResultOfWithTagContext(new SimpleTagContext(TAG1)))).isEmpty(); + } + + @Test + public void withTagContext_TaggingReenabled() { + TagContext tags = new SimpleTagContext(TAG1); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagContextToList(getResultOfWithTagContext(tags))).isEmpty(); + tagsComponent.setState(TaggingState.ENABLED); + assertThat(tagContextToList(getResultOfWithTagContext(tags))).containsExactly(TAG1); + } + + private TagContext getResultOfWithTagContext(TagContext tagsToSet) { + Scope scope = tagger.withTagContext(tagsToSet); + try { + return ContextUtils.TAG_CONTEXT_KEY.get(); + } finally { + scope.close(); + } + } + + private static final class SimpleTagContext extends TagContext { + private final List tags; + + SimpleTagContext(Tag... tags) { + this.tags = Collections.unmodifiableList(Lists.newArrayList(tags)); + } + + @Override + protected Iterator getIterator() { + return tags.iterator(); + } + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java new file mode 100644 index 00000000..e75a86d0 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsComponentImplBaseTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.tags.TaggingState; +import io.opencensus.tags.TagsComponent; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for {@link TagsComponentImplBase}. */ +@RunWith(JUnit4.class) +public class TagsComponentImplBaseTest { + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + + @Test + public void defaultState() { + assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED); + } + + @Test + public void setState() { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(tagsComponent.getState()).isEqualTo(TaggingState.DISABLED); + tagsComponent.setState(TaggingState.ENABLED); + assertThat(tagsComponent.getState()).isEqualTo(TaggingState.ENABLED); + } + + @Test(expected = NullPointerException.class) + public void setState_DisallowsNull() { + tagsComponent.setState(null); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java new file mode 100644 index 00000000..c64eced1 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/TagsTestUtil.java @@ -0,0 +1,32 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags; + +import com.google.common.collect.Lists; +import io.opencensus.tags.InternalUtils; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import java.util.Collection; + +/** Test utilities for tagging. */ +public class TagsTestUtil { + + /** Returns a collection of all tags in a {@link TagContext}. */ + public static Collection tagContextToList(TagContext tags) { + return Lists.newArrayList(InternalUtils.getTags(tags)); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java new file mode 100644 index 00000000..7e9bead1 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImplTest.java @@ -0,0 +1,91 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableSet; +import io.opencensus.implcore.tags.TagsComponentImplBase; +import io.opencensus.implcore.tags.TagsTestUtil; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.TaggingState; +import io.opencensus.tags.TagsComponent; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import io.opencensus.tags.propagation.TagContextDeserializationException; +import io.opencensus.tags.propagation.TagContextSerializationException; +import java.util.Iterator; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link TagContextBinarySerializerImpl}. + * + *

Thorough serialization/deserialization tests are in {@link TagContextSerializationTest}, + * {@link TagContextDeserializationTest}, and {@link TagContextRoundtripTest}. + */ +@RunWith(JUnit4.class) +public final class TagContextBinarySerializerImplTest { + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + private final TagContextBinarySerializer serializer = + tagsComponent.getTagPropagationComponent().getBinarySerializer(); + + private final TagContext tagContext = + new TagContext() { + @Override + public Iterator getIterator() { + return ImmutableSet.of(Tag.create(TagKey.create("key"), TagValue.create("value"))) + .iterator(); + } + }; + + @Test + public void toByteArray_TaggingDisabled() throws TagContextSerializationException { + tagsComponent.setState(TaggingState.DISABLED); + assertThat(serializer.toByteArray(tagContext)).isEmpty(); + } + + @Test + public void toByteArray_TaggingReenabled() throws TagContextSerializationException { + final byte[] serialized = serializer.toByteArray(tagContext); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(serializer.toByteArray(tagContext)).isEmpty(); + tagsComponent.setState(TaggingState.ENABLED); + assertThat(serializer.toByteArray(tagContext)).isEqualTo(serialized); + } + + @Test + public void fromByteArray_TaggingDisabled() + throws TagContextDeserializationException, TagContextSerializationException { + byte[] serialized = serializer.toByteArray(tagContext); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(TagsTestUtil.tagContextToList(serializer.fromByteArray(serialized))).isEmpty(); + } + + @Test + public void fromByteArray_TaggingReenabled() + throws TagContextDeserializationException, TagContextSerializationException { + byte[] serialized = serializer.toByteArray(tagContext); + tagsComponent.setState(TaggingState.DISABLED); + assertThat(TagsTestUtil.tagContextToList(serializer.fromByteArray(serialized))).isEmpty(); + tagsComponent.setState(TaggingState.ENABLED); + assertThat(serializer.fromByteArray(serialized)).isEqualTo(tagContext); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java new file mode 100644 index 00000000..14118be0 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextDeserializationTest.java @@ -0,0 +1,199 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.base.Charsets; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import io.opencensus.implcore.internal.VarInt; +import io.opencensus.implcore.tags.TagsComponentImplBase; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TagsComponent; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import io.opencensus.tags.propagation.TagContextDeserializationException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for deserializing tags with {@link SerializationUtils} and {@link + * TagContextBinarySerializerImpl}. + */ +@RunWith(JUnit4.class) +public class TagContextDeserializationTest { + + @Rule public final ExpectedException thrown = ExpectedException.none(); + + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + private final TagContextBinarySerializer serializer = + tagsComponent.getTagPropagationComponent().getBinarySerializer(); + private final Tagger tagger = tagsComponent.getTagger(); + + @Test + public void testVersionAndValueTypeConstants() { + // Refer to the JavaDoc on SerializationUtils for the definitions on these constants. + assertThat(SerializationUtils.VERSION_ID).isEqualTo(0); + assertThat(SerializationUtils.TAG_FIELD_ID).isEqualTo(0); + } + + @Test + public void testDeserializeNoTags() throws TagContextDeserializationException { + TagContext expected = tagger.empty(); + TagContext actual = + serializer.fromByteArray( + new byte[] {SerializationUtils.VERSION_ID}); // One byte that represents Version ID. + assertThat(actual).isEqualTo(expected); + } + + @Test + public void testDeserializeEmptyByteArrayThrowException() + throws TagContextDeserializationException { + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Input byte[] can not be empty."); + serializer.fromByteArray(new byte[0]); + } + + @Test + public void testDeserializeInvalidTagKey() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + + // Encode an invalid tag key and a valid tag value: + encodeTagToOutput("\2key", "value", output); + final byte[] bytes = output.toByteArray(); + + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Invalid tag key: \2key"); + serializer.fromByteArray(bytes); + } + + @Test + public void testDeserializeInvalidTagValue() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + + // Encode a valid tag key and an invalid tag value: + encodeTagToOutput("my key", "val\3", output); + final byte[] bytes = output.toByteArray(); + + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Invalid tag value for key TagKey{name=my key}: val\3"); + serializer.fromByteArray(bytes); + } + + @Test + public void testDeserializeOneTag() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key", "Value", output); + TagContext expected = + tagger.emptyBuilder().put(TagKey.create("Key"), TagValue.create("Value")).build(); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); + } + + @Test + public void testDeserializeMultipleTags() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key1", "Value1", output); + encodeTagToOutput("Key2", "Value2", output); + TagContext expected = + tagger + .emptyBuilder() + .put(TagKey.create("Key1"), TagValue.create("Value1")) + .put(TagKey.create("Key2"), TagValue.create("Value2")) + .build(); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); + } + + @Test + public void stopParsingAtUnknownField() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + encodeTagToOutput("Key1", "Value1", output); + encodeTagToOutput("Key2", "Value2", output); + + // Write unknown field ID 1. + output.write(1); + output.write(new byte[] {1, 2, 3, 4}); + + encodeTagToOutput("Key3", "Value3", output); + + // key 3 should not be included + TagContext expected = + tagger + .emptyBuilder() + .put(TagKey.create("Key1"), TagValue.create("Value1")) + .put(TagKey.create("Key2"), TagValue.create("Value2")) + .build(); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(expected); + } + + @Test + public void stopParsingAtUnknownTagAtStart() throws TagContextDeserializationException { + ByteArrayDataOutput output = ByteStreams.newDataOutput(); + output.write(SerializationUtils.VERSION_ID); + + // Write unknown field ID 1. + output.write(1); + output.write(new byte[] {1, 2, 3, 4}); + + encodeTagToOutput("Key", "Value", output); + assertThat(serializer.fromByteArray(output.toByteArray())).isEqualTo(tagger.empty()); + } + + @Test + public void testDeserializeWrongFormat() throws TagContextDeserializationException { + // encoded tags should follow the format ()* + thrown.expect(TagContextDeserializationException.class); + serializer.fromByteArray(new byte[3]); + } + + @Test + public void testDeserializeWrongVersionId() throws TagContextDeserializationException { + thrown.expect(TagContextDeserializationException.class); + thrown.expectMessage("Wrong Version ID: 1. Currently supported version is: 0"); + serializer.fromByteArray(new byte[] {(byte) (SerializationUtils.VERSION_ID + 1)}); + } + + // == + // + // == varint encoded integer + // == tag_key_len bytes comprising tag key name + // == varint encoded integer + // == tag_val_len bytes comprising UTF-8 string + private static void encodeTagToOutput(String key, String value, ByteArrayDataOutput output) { + output.write(SerializationUtils.TAG_FIELD_ID); + encodeString(key, output); + encodeString(value, output); + } + + private static void encodeString(String input, ByteArrayDataOutput output) { + int length = input.length(); + byte[] bytes = new byte[VarInt.varIntSize(length)]; + VarInt.putVarInt(length, bytes, 0); + output.write(bytes); + output.write(input.getBytes(Charsets.UTF_8)); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java new file mode 100644 index 00000000..88abcc1d --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextRoundtripTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.implcore.tags.TagsComponentImplBase; +import io.opencensus.tags.TagContext; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TagsComponent; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests for roundtrip serialization with {@link TagContextBinarySerializerImpl}. */ +@RunWith(JUnit4.class) +public class TagContextRoundtripTest { + + private static final TagKey K1 = TagKey.create("k1"); + private static final TagKey K2 = TagKey.create("k2"); + private static final TagKey K3 = TagKey.create("k3"); + + private static final TagValue V_EMPTY = TagValue.create(""); + private static final TagValue V1 = TagValue.create("v1"); + private static final TagValue V2 = TagValue.create("v2"); + private static final TagValue V3 = TagValue.create("v3"); + + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + private final TagContextBinarySerializer serializer = + tagsComponent.getTagPropagationComponent().getBinarySerializer(); + private final Tagger tagger = tagsComponent.getTagger(); + + @Test + public void testRoundtripSerialization() throws Exception { + testRoundtripSerialization(tagger.empty()); + testRoundtripSerialization(tagger.emptyBuilder().put(K1, V1).build()); + testRoundtripSerialization(tagger.emptyBuilder().put(K1, V1).put(K2, V2).put(K3, V3).build()); + testRoundtripSerialization(tagger.emptyBuilder().put(K1, V_EMPTY).build()); + } + + private void testRoundtripSerialization(TagContext expected) throws Exception { + byte[] bytes = serializer.toByteArray(expected); + TagContext actual = serializer.fromByteArray(bytes); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java new file mode 100644 index 00000000..6227fe54 --- /dev/null +++ b/impl_core/src/test/java/io/opencensus/implcore/tags/propagation/TagContextSerializationTest.java @@ -0,0 +1,118 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.implcore.tags.propagation; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.base.Charsets; +import com.google.common.collect.Collections2; +import io.opencensus.implcore.internal.VarInt; +import io.opencensus.implcore.tags.TagsComponentImplBase; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContextBuilder; +import io.opencensus.tags.TagKey; +import io.opencensus.tags.TagValue; +import io.opencensus.tags.Tagger; +import io.opencensus.tags.TagsComponent; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import io.opencensus.tags.propagation.TagContextSerializationException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for serializing tags with {@link SerializationUtils} and {@link + * TagContextBinarySerializerImpl}. + */ +@RunWith(JUnit4.class) +public class TagContextSerializationTest { + + private static final int VERSION_ID = 0; + private static final int TAG_FIELD_ID = 0; + + private static final TagKey K1 = TagKey.create("k1"); + private static final TagKey K2 = TagKey.create("k2"); + private static final TagKey K3 = TagKey.create("k3"); + private static final TagKey K4 = TagKey.create("k4"); + + private static final TagValue V1 = TagValue.create("v1"); + private static final TagValue V2 = TagValue.create("v2"); + private static final TagValue V3 = TagValue.create("v3"); + private static final TagValue V4 = TagValue.create("v4"); + + private static final Tag T1 = Tag.create(K1, V1); + private static final Tag T2 = Tag.create(K2, V2); + private static final Tag T3 = Tag.create(K3, V3); + private static final Tag T4 = Tag.create(K4, V4); + + private final TagsComponent tagsComponent = new TagsComponentImplBase(); + private final TagContextBinarySerializer serializer = + tagsComponent.getTagPropagationComponent().getBinarySerializer(); + private final Tagger tagger = tagsComponent.getTagger(); + + @Test + public void testSerializeDefault() throws Exception { + testSerialize(); + } + + @Test + public void testSerializeWithOneTag() throws Exception { + testSerialize(T1); + } + + @Test + public void testSerializeWithMultipleTags() throws Exception { + testSerialize(T1, T2, T3, T4); + } + + private void testSerialize(Tag... tags) throws IOException, TagContextSerializationException { + TagContextBuilder builder = tagger.emptyBuilder(); + for (Tag tag : tags) { + builder.put(tag.getKey(), tag.getValue()); + } + + byte[] actual = serializer.toByteArray(builder.build()); + + Collection> tagPermutation = Collections2.permutations(Arrays.asList(tags)); + Set possibleOutputs = new HashSet(); + for (List list : tagPermutation) { + ByteArrayOutputStream expected = new ByteArrayOutputStream(); + expected.write(VERSION_ID); + for (Tag tag : list) { + expected.write(TAG_FIELD_ID); + encodeString(tag.getKey().getName(), expected); + encodeString(tag.getValue().asString(), expected); + } + possibleOutputs.add(expected.toString()); + } + + assertThat(possibleOutputs).contains(new String(actual, Charsets.UTF_8)); + } + + private static void encodeString(String input, ByteArrayOutputStream byteArrayOutputStream) + throws IOException { + VarInt.putVarInt(input.length(), byteArrayOutputStream); + byteArrayOutputStream.write(input.getBytes(Charsets.UTF_8)); + } +} diff --git a/impl_lite/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java b/impl_lite/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java new file mode 100644 index 00000000..a58a9d3e --- /dev/null +++ b/impl_lite/src/main/java/io/opencensus/impllite/stats/StatsComponentImplLite.java @@ -0,0 +1,31 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impllite.stats; + +import io.opencensus.implcore.common.MillisClock; +import io.opencensus.implcore.internal.SimpleEventQueue; +import io.opencensus.implcore.stats.StatsComponentImplBase; +import io.opencensus.stats.StatsComponent; + +/** Android-compatible implementation of {@link StatsComponent}. */ +public final class StatsComponentImplLite extends StatsComponentImplBase { + + public StatsComponentImplLite() { + // TODO(sebright): Use a more efficient queue implementation. + super(new SimpleEventQueue(), MillisClock.getInstance()); + } +} diff --git a/impl_lite/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java b/impl_lite/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java new file mode 100644 index 00000000..dc0d900c --- /dev/null +++ b/impl_lite/src/main/java/io/opencensus/impllite/tags/TagsComponentImplLite.java @@ -0,0 +1,23 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impllite.tags; + +import io.opencensus.implcore.tags.TagsComponentImplBase; +import io.opencensus.tags.TagsComponent; + +/** Android-compatible implementation of {@link TagsComponent}. */ +public final class TagsComponentImplLite extends TagsComponentImplBase {} diff --git a/impl_lite/src/test/java/io/opencensus/impllite/stats/StatsTest.java b/impl_lite/src/test/java/io/opencensus/impllite/stats/StatsTest.java new file mode 100644 index 00000000..313f8916 --- /dev/null +++ b/impl_lite/src/test/java/io/opencensus/impllite/stats/StatsTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2016-17, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impllite.stats; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.implcore.stats.StatsRecorderImpl; +import io.opencensus.implcore.stats.ViewManagerImpl; +import io.opencensus.stats.Stats; +import io.opencensus.stats.StatsComponent; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test for accessing the {@link StatsComponent} through the {@link Stats} class. */ +@RunWith(JUnit4.class) +public final class StatsTest { + @Test + public void getStatsRecorder() { + assertThat(Stats.getStatsRecorder()).isInstanceOf(StatsRecorderImpl.class); + } + + @Test + public void getViewManager() { + assertThat(Stats.getViewManager()).isInstanceOf(ViewManagerImpl.class); + } +} diff --git a/impl_lite/src/test/java/io/opencensus/impllite/tags/TagsTest.java b/impl_lite/src/test/java/io/opencensus/impllite/tags/TagsTest.java new file mode 100644 index 00000000..890cdb15 --- /dev/null +++ b/impl_lite/src/test/java/io/opencensus/impllite/tags/TagsTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2017, OpenCensus Authors + * + * 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 + * + * http://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.opencensus.impllite.tags; + +import static com.google.common.truth.Truth.assertThat; + +import io.opencensus.implcore.tags.TaggerImpl; +import io.opencensus.implcore.tags.propagation.TagPropagationComponentImpl; +import io.opencensus.tags.Tags; +import io.opencensus.tags.TagsComponent; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test for accessing the {@link TagsComponent} through the {@link Tags} class. */ +@RunWith(JUnit4.class) +public final class TagsTest { + @Test + public void getTagger() { + assertThat(Tags.getTagger()).isInstanceOf(TaggerImpl.class); + } + + @Test + public void getTagContextSerializer() { + assertThat(Tags.getTagPropagationComponent()).isInstanceOf(TagPropagationComponentImpl.class); + } +} diff --git a/settings.gradle b/settings.gradle index 909c171f..e917496a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,9 +9,6 @@ include ":opencensus-exporter-trace-logging" include ":opencensus-exporter-trace-stackdriver" include ":opencensus-exporter-trace-zipkin" include ":opencensus-exporter-stats-stackdriver" -include ":core_impl" -include ":core_impl_java" -include ":core_impl_android" include ":opencensus-contrib-agent" include ":opencensus-contrib-grpc-metrics" include ":opencensus-contrib-grpc-util" -- cgit v1.2.3