diff options
author | sebright <sebright@google.com> | 2017-10-23 17:13:14 -0700 |
---|---|---|
committer | Bogdan Drutu <bdrutu@google.com> | 2017-10-23 17:13:14 -0700 |
commit | 92e363fb2daa1a8aee308d3bd5fc20c9e83eeab2 (patch) | |
tree | 34cf4a254947a69b24ed522f997d15c072bfe8e4 /api/src/main/java/io/opencensus/tags | |
parent | e69bb99d61c529fc9ad8c0be83d1f438c93a63af (diff) | |
download | opencensus-java-92e363fb2daa1a8aee308d3bd5fc20c9e83eeab2.tar.gz |
Move stats and tags packages to opencensus-api to prepare for release. (#723)
Diffstat (limited to 'api/src/main/java/io/opencensus/tags')
16 files changed, 1563 insertions, 0 deletions
diff --git a/api/src/main/java/io/opencensus/tags/InternalUtils.java b/api/src/main/java/io/opencensus/tags/InternalUtils.java new file mode 100644 index 00000000..c55ca7d4 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/InternalUtils.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.tags; + +import java.util.Iterator; + +/** + * Internal tagging utilities. + */ +@io.opencensus.common.Internal +public final class InternalUtils { + private InternalUtils() {} + + public static Iterator<Tag> getTags(TagContext tags) { + return tags.getIterator(); + } +} diff --git a/api/src/main/java/io/opencensus/tags/NoopTags.java b/api/src/main/java/io/opencensus/tags/NoopTags.java new file mode 100644 index 00000000..2267edb0 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/NoopTags.java @@ -0,0 +1,232 @@ +/* + * 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.tags; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.base.Preconditions; +import io.opencensus.common.Scope; +import io.opencensus.internal.NoopScope; +import io.opencensus.tags.TagKey.TagKeyBoolean; +import io.opencensus.tags.TagKey.TagKeyLong; +import io.opencensus.tags.TagKey.TagKeyString; +import io.opencensus.tags.TagValue.TagValueBoolean; +import io.opencensus.tags.TagValue.TagValueLong; +import io.opencensus.tags.TagValue.TagValueString; +import io.opencensus.tags.propagation.TagContextBinarySerializer; +import io.opencensus.tags.propagation.TagPropagationComponent; +import java.util.Collections; +import java.util.Iterator; +import javax.annotation.concurrent.Immutable; + +/** No-op implementations of tagging classes. */ +final class NoopTags { + + private NoopTags() {} + + /** + * Returns a {@code TagsComponent} that has a no-op implementation for {@link Tagger}. + * + * @return a {@code TagsComponent} that has a no-op implementation for {@code Tagger}. + */ + static TagsComponent getNoopTagsComponent() { + return NoopTagsComponent.INSTANCE; + } + + /** + * Returns a {@code Tagger} that only produces {@link TagContext}s with no tags. + * + * @return a {@code Tagger} that only produces {@code TagContext}s with no tags. + */ + static Tagger getNoopTagger() { + return NoopTagger.INSTANCE; + } + + /** + * Returns a {@code TagContextBuilder} that ignores all calls to {@link TagContextBuilder#put}. + * + * @return a {@code TagContextBuilder} that ignores all calls to {@link TagContextBuilder#put}. + */ + static TagContextBuilder getNoopTagContextBuilder() { + return NoopTagContextBuilder.INSTANCE; + } + + /** + * Returns a {@code TagContext} that does not contain any tags. + * + * @return a {@code TagContext} that does not contain any tags. + */ + static TagContext getNoopTagContext() { + return NoopTagContext.INSTANCE; + } + + /** Returns a {@code TagPropagationComponent} that contains no-op serializers. */ + static TagPropagationComponent getNoopTagPropagationComponent() { + return NoopTagPropagationComponent.INSTANCE; + } + + /** + * Returns a {@code TagContextBinarySerializer} that serializes all {@code TagContext}s to zero + * bytes and deserializes all inputs to empty {@code TagContext}s. + */ + static TagContextBinarySerializer getNoopTagContextBinarySerializer() { + return NoopTagContextBinarySerializer.INSTANCE; + } + + @Immutable + private static final class NoopTagsComponent extends TagsComponent { + static final TagsComponent INSTANCE = new NoopTagsComponent(); + + @Override + public Tagger getTagger() { + return getNoopTagger(); + } + + @Override + public TagPropagationComponent getTagPropagationComponent() { + return getNoopTagPropagationComponent(); + } + + @Override + public TaggingState getState() { + return TaggingState.DISABLED; + } + + @Override + public void setState(TaggingState state) { + Preconditions.checkNotNull(state, "state"); + } + } + + @Immutable + private static final class NoopTagger extends Tagger { + static final Tagger INSTANCE = new NoopTagger(); + + @Override + public TagContext empty() { + return getNoopTagContext(); + } + + @Override + public TagContext getCurrentTagContext() { + return getNoopTagContext(); + } + + @Override + public TagContextBuilder emptyBuilder() { + return getNoopTagContextBuilder(); + } + + @Override + public TagContextBuilder toBuilder(TagContext tags) { + checkNotNull(tags, "tags"); + return getNoopTagContextBuilder(); + } + + @Override + public TagContextBuilder currentBuilder() { + return getNoopTagContextBuilder(); + } + + @Override + public Scope withTagContext(TagContext tags) { + checkNotNull(tags, "tags"); + return NoopScope.getInstance(); + } + } + + @Immutable + private static final class NoopTagContextBuilder extends TagContextBuilder { + static final TagContextBuilder INSTANCE = new NoopTagContextBuilder(); + + @Override + public TagContextBuilder put(TagKeyString key, TagValueString value) { + checkNotNull(key, "key"); + checkNotNull(value, "value"); + return this; + } + + @Override + public TagContextBuilder put(TagKeyLong key, TagValueLong value) { + checkNotNull(key, "key"); + checkNotNull(value, "value"); + return this; + } + + @Override + public TagContextBuilder put(TagKeyBoolean key, TagValueBoolean value) { + checkNotNull(key, "key"); + checkNotNull(value, "value"); + return this; + } + + @Override + public TagContextBuilder remove(TagKey key) { + checkNotNull(key, "key"); + return this; + } + + @Override + public TagContext build() { + return getNoopTagContext(); + } + + @Override + public Scope buildScoped() { + return NoopScope.getInstance(); + } + } + + @Immutable + private static final class NoopTagContext extends TagContext { + static final TagContext INSTANCE = new NoopTagContext(); + + // TODO(sebright): Is there any way to let the user know that their tags were ignored? + @Override + protected Iterator<Tag> getIterator() { + return Collections.<Tag>emptySet().iterator(); + } + } + + @Immutable + private static final class NoopTagPropagationComponent extends TagPropagationComponent { + static final TagPropagationComponent INSTANCE = new NoopTagPropagationComponent(); + + @Override + public TagContextBinarySerializer getBinarySerializer() { + return getNoopTagContextBinarySerializer(); + } + } + + @Immutable + private static final class NoopTagContextBinarySerializer extends TagContextBinarySerializer { + static final TagContextBinarySerializer INSTANCE = new NoopTagContextBinarySerializer(); + static final byte[] EMPTY_BYTE_ARRAY = {}; + + @Override + public byte[] toByteArray(TagContext tags) { + checkNotNull(tags, "tags"); + return EMPTY_BYTE_ARRAY; + } + + @Override + public TagContext fromByteArray(byte[] bytes) { + checkNotNull(bytes, "bytes"); + return getNoopTagContext(); + } + } +} diff --git a/api/src/main/java/io/opencensus/tags/Tag.java b/api/src/main/java/io/opencensus/tags/Tag.java new file mode 100644 index 00000000..a53cd838 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/Tag.java @@ -0,0 +1,208 @@ +/* + * 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.tags; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.Function; +import io.opencensus.tags.TagKey.TagKeyBoolean; +import io.opencensus.tags.TagKey.TagKeyLong; +import io.opencensus.tags.TagKey.TagKeyString; +import io.opencensus.tags.TagValue.TagValueBoolean; +import io.opencensus.tags.TagValue.TagValueLong; +import io.opencensus.tags.TagValue.TagValueString; +import javax.annotation.concurrent.Immutable; + +/** {@link TagKey} paired with a value. */ +@Immutable +public abstract class Tag { + + /** + * Returns the tag's key. + * + * @return the tag's key. + */ + public abstract TagKey getKey(); + + /** + * Returns the associated tag value. + * + * @return the associated tag value. + */ + public abstract TagValue getValue(); + + Tag() {} + + /** + * Applies a function to the tag's key and value. The function that is called depends on the type + * of the tag. This is similar to the visitor pattern. {@code match} also takes a function to + * handle the default case, for backwards compatibility when tag types are added. For example, + * this code serializes a {@code Tag} and tries to handle new tag types by calling {@code + * toString()}. + * + * <pre>{@code + * byte[] serializedValue = + * tag.match( + * stringTag -> serializeString(stringTag.getValue().asString()), + * longTag -> serializeLong(longTag.getValue()), + * booleanTag -> serializeBoolean(booleanTag.getValue()), + * unknownTag -> serializeString(unknownTag.toString())); + * }</pre> + * + * <p>Without lambdas: + * + * <pre><code> + * byte[] serializedValue = + * tag.match( + * new Function<TagString, String>() { + * {@literal @}Override + * public String apply(TagString stringTag) { + * return serializeString(stringTag.getValue().asString()); + * } + * }, + * new Function<TagLong, String>() { + * {@literal @}Override + * public String apply(TagLong longTag) { + * serializeLong(longTag.getValue()); + * } + * }, + * new Function<TagBoolean, String>() { + * {@literal @}Override + * public String apply(TagBoolean booleanTag) { + * serializeBoolean(booleanTag.getValue()); + * } + * }, + * new Function<Tag, String>() { + * {@literal @}Override + * public String apply(TagBoolean unknownTag) { + * serializeString(unknownTag.toString()); + * } + * }); + * </code></pre> + * + * @param stringFunction the function to call when the tag has a {@code String} value. + * @param longFunction the function to call when the tag has a {@code long} value. + * @param booleanFunction the function to call when the tag has a {@code boolean} value. + * @param defaultFunction the function to call when the tag has a value other than {@code String}, + * {@code long}, or {@code boolean}. + * @param <T> The result type of the function. + * @return The result of calling the function that matches the tag's type. + */ + public abstract <T> T match( + Function<? super TagString, T> stringFunction, + Function<? super TagLong, T> longFunction, + Function<? super TagBoolean, T> booleanFunction, + Function<? super Tag, T> defaultFunction); + + /** A tag with a {@code String} key and value. */ + @Immutable + @AutoValue + public abstract static class TagString extends Tag { + TagString() {} + + /** + * Creates a {@code TagString} from the given {@code String} key and value. + * + * @param key the tag key. + * @param value the tag value. + * @return a {@code TagString} with the given key and value. + */ + public static TagString create(TagKeyString key, TagValueString value) { + return new AutoValue_Tag_TagString(key, value); + } + + @Override + public abstract TagKeyString getKey(); + + @Override + public abstract TagValueString getValue(); + + @Override + public final <T> T match( + Function<? super TagString, T> stringFunction, + Function<? super TagLong, T> longFunction, + Function<? super TagBoolean, T> booleanFunction, + Function<? super Tag, T> defaultFunction) { + return stringFunction.apply(this); + } + } + + /** A tag with a {@code long} key and value. */ + @Immutable + @AutoValue + public abstract static class TagLong extends Tag { + TagLong() {} + + /** + * Creates a {@code TagLong} from the given {@code long} key and value. + * + * @param key the tag key. + * @param value the tag value. + * @return a {@code TagLong} with the given key and value. + */ + public static TagLong create(TagKeyLong key, TagValueLong value) { + return new AutoValue_Tag_TagLong(key, value); + } + + @Override + public abstract TagKeyLong getKey(); + + @Override + public abstract TagValueLong getValue(); + + @Override + public final <T> T match( + Function<? super TagString, T> stringFunction, + Function<? super TagLong, T> longFunction, + Function<? super TagBoolean, T> booleanFunction, + Function<? super Tag, T> defaultFunction) { + return longFunction.apply(this); + } + } + + /** A tag with a {@code boolean} key and value. */ + @Immutable + @AutoValue + public abstract static class TagBoolean extends Tag { + TagBoolean() {} + + /** + * Creates a {@code TagBoolean} from the given {@code boolean} key and value. + * + * @param key the tag key. + * @param value the tag value. + * @return a {@code TagBoolean} with the given key and value. + */ + public static TagBoolean create(TagKeyBoolean key, TagValueBoolean value) { + return new AutoValue_Tag_TagBoolean(key, value); + } + + @Override + public abstract TagKeyBoolean getKey(); + + @Override + public abstract TagValueBoolean getValue(); + + @Override + public final <T> T match( + Function<? super TagString, T> stringFunction, + Function<? super TagLong, T> longFunction, + Function<? super TagBoolean, T> booleanFunction, + Function<? super Tag, T> defaultFunction) { + return booleanFunction.apply(this); + } + } +} diff --git a/api/src/main/java/io/opencensus/tags/TagContext.java b/api/src/main/java/io/opencensus/tags/TagContext.java new file mode 100644 index 00000000..be8f0dc1 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/TagContext.java @@ -0,0 +1,99 @@ +/* + * 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.tags; + +import com.google.common.collect.HashMultiset; +import com.google.common.collect.ImmutableMultiset; +import com.google.common.collect.Lists; +import com.google.common.collect.Multiset; +import io.opencensus.tags.TagValue.TagValueString; +import java.util.Iterator; +import javax.annotation.concurrent.Immutable; + +/** + * A map from keys to values that can be used to label anything that is associated with a specific + * operation. + * + * <p>For example, {@code TagContext}s can be used to label stats, log messages, or debugging + * information. + * + * <p>Keys have type {@link TagKey}. Values have type {@link TagValueString}, though the library + * will support more types in the future, including {@code long} and {@code boolean}. + */ +@Immutable +public abstract class TagContext { + + /** + * Returns an iterator over the tags in this {@code TagContext}. + * + * @return an iterator over the tags in this {@code TagContext}. + */ + // This method is protected to prevent client code from accessing the tags of any TagContext. We + // don't currently support efficient access to tags. However, every TagContext subclass needs to + // provide access to its tags to the stats and tagging implementations by implementing this + // method. If we decide to support access to tags in the future, we can add a public iterator() + // method and implement it for all subclasses by calling getIterator(). + // + // The stats and tagging implementations can access any TagContext's tags through + // io.opencensus.tags.InternalUtils.getTags, which calls this method. + protected abstract Iterator<Tag> getIterator(); + + @Override + public String toString() { + return "TagContext"; + } + + /** + * Returns true iff the other object is an instance of {@code TagContext} and contains the same + * key-value pairs. Implementations are free to override this method to provide better + * performance. + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof TagContext)) { + return false; + } + TagContext otherTags = (TagContext) other; + Iterator<Tag> iter1 = getIterator(); + Iterator<Tag> iter2 = otherTags.getIterator(); + Multiset<Tag> tags1 = + iter1 == null + ? ImmutableMultiset.<Tag>of() + : HashMultiset.create(Lists.newArrayList(iter1)); + Multiset<Tag> tags2 = + iter2 == null + ? ImmutableMultiset.<Tag>of() + : HashMultiset.create(Lists.newArrayList(iter2)); + return tags1.equals(tags2); + } + + @Override + public final int hashCode() { + int hashCode = 0; + Iterator<Tag> i = getIterator(); + if (i == null) { + return hashCode; + } + while (i.hasNext()) { + Tag tag = i.next(); + if (tag != null) { + hashCode += tag.hashCode(); + } + } + return hashCode; + } +} diff --git a/api/src/main/java/io/opencensus/tags/TagContextBuilder.java b/api/src/main/java/io/opencensus/tags/TagContextBuilder.java new file mode 100644 index 00000000..bbd6da7c --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/TagContextBuilder.java @@ -0,0 +1,83 @@ +/* + * 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.tags; + +import io.opencensus.common.Scope; +import io.opencensus.tags.TagKey.TagKeyBoolean; +import io.opencensus.tags.TagKey.TagKeyLong; +import io.opencensus.tags.TagKey.TagKeyString; +import io.opencensus.tags.TagValue.TagValueBoolean; +import io.opencensus.tags.TagValue.TagValueLong; +import io.opencensus.tags.TagValue.TagValueString; + +/** Builder for the {@link TagContext} class. */ +// TODO(sebright): Decide what to do when 'put' is called with a key that has the same name as an +// existing key, but a different type. We currently keep both keys. +public abstract class TagContextBuilder { + + /** + * Adds the key/value pair regardless of whether the key is present. + * + * @param key the {@code TagKey} which will be set. + * @param value the value to set for the given key. + * @return this + */ + public abstract TagContextBuilder put(TagKeyString key, TagValueString value); + + /** + * Adds the key/value pair regardless of whether the key is present. + * + * @param key the {@code TagKey} which will be set. + * @param value the value to set for the given key. + * @return this + */ + public abstract TagContextBuilder put(TagKeyLong key, TagValueLong value); + + /** + * Adds the key/value pair regardless of whether the key is present. + * + * @param key the {@code TagKey} which will be set. + * @param value the value to set for the given key. + * @return this + */ + public abstract TagContextBuilder put(TagKeyBoolean key, TagValueBoolean value); + + /** + * Removes the key if it exists. + * + * @param key the {@code TagKey} which will be removed. + * @return this + */ + public abstract TagContextBuilder remove(TagKey key); + + /** + * Creates a {@code TagContext} from this builder. + * + * @return a {@code TagContext} with the same tags as this builder. + */ + public abstract TagContext build(); + + /** + * Enters the scope of code where the {@link TagContext} created from this builder is in the + * current context and returns an object that represents that scope. The scope is exited when the + * returned object is closed. + * + * @return an object that defines a scope where the {@code TagContext} created from this builder + * is set to the current context. + */ + public abstract Scope buildScoped(); +} diff --git a/api/src/main/java/io/opencensus/tags/TagKey.java b/api/src/main/java/io/opencensus/tags/TagKey.java new file mode 100644 index 00000000..943f12d7 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/TagKey.java @@ -0,0 +1,244 @@ +/* + * 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.tags; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.auto.value.AutoValue; +import io.opencensus.common.Function; +import io.opencensus.internal.StringUtil; +import io.opencensus.tags.TagValue.TagValueString; +import javax.annotation.concurrent.Immutable; + +/** + * A key to a value stored in a {@link TagContext}. + * + * <p>There is one {@code TagKey} subclass corresponding to each tag value type, so that each key + * can only be paired with a single type of value. For example, {@link TagKeyString} can only be + * used to set {@link TagValueString} values in a {@code TagContext}. + * + * <p>Each {@code TagKey} has a {@code String} name. Names have a maximum length of {@link + * #MAX_LENGTH} and contain only printable ASCII characters. + * + * <p>{@code TagKey}s are designed to be used as constants. Declaring each key as a constant ensures + * that the keys have consistent value types and prevents key names from being validated multiple + * times. + */ +@Immutable +public abstract class TagKey { + /** The maximum length for a tag key name. The value is {@value #MAX_LENGTH}. */ + public static final int MAX_LENGTH = 255; + + TagKey() {} + + public abstract String getName(); + + /** + * Applies a function to the {@code TagKey} subclass. The function that is called depends on the + * type of the tag key. This is similar to the visitor pattern. {@code match} also takes a + * function to handle the default case, for backwards compatibility when tag types are added. For + * example, this code creates a {@code Tag} from a {@code TagKey}. It handles new tag types by + * logging an error and returning a {@code TagKeyString}. + * + * <pre>{@code + * Tag tag = + * tagKey.match( + * stringKey -> TagString.create(stringKey, TagValueString.create("string value")), + * longKey -> TagLong.create(longKey, 100L), + * booleanKey -> TagBoolean.create(booleanKey, true), + * unknownKey -> { + * logger.log(Level.WARNING, "Unknown tag key type: " + unknownKey.toString()); + * return TagString.create( + * TagKeyString.create(unknownKey.getName()), + * TagValueString.create("string value")); + * }); + * }</pre> + * + * <p>Without lambdas: + * + * <pre><code> + * Tag tag = + * tagKey.match( + * new Function<TagKeyString, Tag>() { + * {@literal @}Override + * public Tag apply(TagKeyString stringKey) { + * return TagString.create(stringKey, TagValueString.create("string value")); + * } + * }, + * new Function<TagKeyLong, Tag>() { + * {@literal @}Override + * public Tag apply(TagKeyLong longKey) { + * return TagLong.create(longKey, 100L); + * } + * }, + * new Function<TagKeyBoolean, Tag>() { + * {@literal @}Override + * public Tag apply(TagKeyBoolean booleanKey) { + * return TagBoolean.create(booleanKey, true); + * } + * }, + * new Function<TagKey, Tag>() { + * {@literal @}Override + * public Tag apply(TagKey unknownKey) { + * logger.log(Level.WARNING, "Unknown tag key type: " + unknownKey.toString()); + * return TagString.create( + * TagKeyString.create(unknownKey.getName()), + * TagValueString.create("string value")); + * } + * }); + * </code></pre> + * + * @param stringFunction the function to call when the {@code TagKey} is a {@code TagKeyString}. + * @param longFunction the function to call when the {@code TagKey} is a {@code TagKeyLong}. + * @param booleanFunction the function to call when the {@code TagKey} is a {@code TagKeyBoolean}. + * @param defaultFunction the function to call when the tag key has a type other than {@code + * String}, {@code long}, or {@code boolean}. + * @param <T> The result type of the function. + * @return The result of calling the function that matches the tag key's type. + */ + // TODO(sebright): Should we make this public in the first release? + public abstract <T> T match( + Function<? super TagKeyString, T> stringFunction, + Function<? super TagKeyLong, T> longFunction, + Function<? super TagKeyBoolean, T> booleanFunction, + Function<? super TagKey, T> defaultFunction); + + /** + * Determines whether the given {@code String} is a valid tag key. + * + * @param name the tag key name to be validated. + * @return whether the name is valid. + */ + private static boolean isValid(String name) { + return name.length() <= MAX_LENGTH && StringUtil.isPrintableString(name); + } + + /** A {@code TagKey} for values of type {@code String}. */ + @Immutable + @AutoValue + public abstract static class TagKeyString extends TagKey { + + /** + * Constructs a {@code TagKeyString} with the given name. + * + * <p>The name must meet the following requirements: + * + * <ol> + * <li>It cannot be longer than {@link #MAX_LENGTH}. + * <li>It can only contain printable ASCII characters. + * </ol> + * + * @param name the name of the key. + * @return a {@code TagKeyString} with the given name. + * @throws IllegalArgumentException if the name is not valid. + */ + public static TagKeyString create(String name) { + // TODO(sebright): Should we disallow an empty name? + checkArgument(isValid(name)); + return new AutoValue_TagKey_TagKeyString(name); + } + + @Override + public final <T> T match( + Function<? super TagKeyString, T> stringFunction, + Function<? super TagKeyLong, T> longFunction, + Function<? super TagKeyBoolean, T> booleanFunction, + Function<? super TagKey, T> defaultFunction) { + return stringFunction.apply(this); + } + } + + /** + * A {@code TagKey} for values of type {@code long}. + * + * <p>Note that {@link TagKeyLong} isn't supported by the implementation yet, so the factory + * method isn't exposed. + */ + @Immutable + @AutoValue + public abstract static class TagKeyLong extends TagKey { + + /** + * Constructs a {@code TagKeyLong} with the given name. + * + * <p>The name must meet the following requirements: + * + * <ol> + * <li>It cannot be longer than {@link #MAX_LENGTH}. + * <li>It can only contain printable ASCII characters. + * </ol> + * + * @param name the name of the key. + * @return a {@code TagKeyLong} with the given name. + * @throws IllegalArgumentException if the name is not valid. + */ + // TODO(sebright): Make this public once we support types other than String. + static TagKeyLong create(String name) { + checkArgument(isValid(name)); + return new AutoValue_TagKey_TagKeyLong(name); + } + + @Override + public final <T> T match( + Function<? super TagKeyString, T> stringFunction, + Function<? super TagKeyLong, T> longFunction, + Function<? super TagKeyBoolean, T> booleanFunction, + Function<? super TagKey, T> defaultFunction) { + return longFunction.apply(this); + } + } + + /** + * A {@code TagKey} for values of type {@code boolean}. + * + * <p>Note that {@link TagKeyBoolean} isn't supported by the implementation yet, so the factory + * method isn't exposed. + */ + @Immutable + @AutoValue + public abstract static class TagKeyBoolean extends TagKey { + + /** + * Constructs a {@code TagKeyBoolean} with the given name. + * + * <p>The name must meet the following requirements: + * + * <ol> + * <li>It cannot be longer than {@link #MAX_LENGTH}. + * <li>It can only contain printable ASCII characters. + * </ol> + * + * @param name the name of the key. + * @return a {@code TagKeyBoolean} with the given name. + * @throws IllegalArgumentException if the name is not valid. + */ + // TODO(sebright): Make this public once we support types other than String. + static TagKeyBoolean create(String name) { + checkArgument(isValid(name)); + return new AutoValue_TagKey_TagKeyBoolean(name); + } + + @Override + public final <T> T match( + Function<? super TagKeyString, T> stringFunction, + Function<? super TagKeyLong, T> longFunction, + Function<? super TagKeyBoolean, T> booleanFunction, + Function<? super TagKey, T> defaultFunction) { + return booleanFunction.apply(this); + } + } +} diff --git a/api/src/main/java/io/opencensus/tags/TagValue.java b/api/src/main/java/io/opencensus/tags/TagValue.java new file mode 100644 index 00000000..7da713c5 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/TagValue.java @@ -0,0 +1,182 @@ +/* + * 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.tags; + +import com.google.auto.value.AutoValue; +import com.google.common.base.Preconditions; +import io.opencensus.common.Function; +import io.opencensus.internal.StringUtil; +import io.opencensus.tags.TagKey.TagKeyBoolean; +import io.opencensus.tags.TagKey.TagKeyLong; +import io.opencensus.tags.TagKey.TagKeyString; +import javax.annotation.concurrent.Immutable; + +/** A validated tag value. */ +@Immutable +public abstract class TagValue { + + TagValue() {} + + /** + * Applies a function to a tag value. The function that is called depends on the type of the + * value. This is similar to the visitor pattern. {@code match} also takes a function to handle + * the default case, for backwards compatibility when tag types are added. + * + * @param stringFunction the function to call when the tag value has type {@code String}. + * @param longFunction the function to call when the tag value has type {@code long}. + * @param booleanFunction the function to call when the tag value has type {@code boolean}. + * @param defaultFunction the function to call when the tag value has a type other than {@code + * String}, {@code long}, or {@code boolean}. + * @param <T> The result type of the function. + * @return The result of calling the function that matches the tag value's type. + */ + public abstract <T> T match( + Function<? super TagValueString, T> stringFunction, + Function<? super TagValueLong, T> longFunction, + Function<? super TagValueBoolean, T> booleanFunction, + Function<? super TagValue, T> defaultFunction); + + /** + * A validated tag value associated with a {@link TagKeyString}. + * + * <p>Validation ensures that the {@code String} has a maximum length of {@link #MAX_LENGTH} and + * contains only printable ASCII characters. + */ + @Immutable + @AutoValue + public abstract static class TagValueString extends TagValue { + /** The maximum length for a {@code String} tag value. The value is {@value #MAX_LENGTH}. */ + public static final int MAX_LENGTH = 256; + + TagValueString() {} + + /** + * Constructs a {@code TagValueString} from the given string. The string must meet the following + * requirements: + * + * <ol> + * <li>It cannot be longer than {@link #MAX_LENGTH}. + * <li>It can only contain printable ASCII characters. + * </ol> + * + * @param value the tag value. + * @throws IllegalArgumentException if the {@code String} is not valid. + */ + public static TagValueString create(String value) { + Preconditions.checkArgument(isValid(value)); + return new AutoValue_TagValue_TagValueString(value); + } + + @Override + public final <T> T match( + Function<? super TagValueString, T> stringFunction, + Function<? super TagValueLong, T> longFunction, + Function<? super TagValueBoolean, T> booleanFunction, + Function<? super TagValue, T> defaultFunction) { + return stringFunction.apply(this); + } + + /** + * Returns the tag value as a {@code String}. + * + * @return the tag value as a {@code String}. + */ + public abstract String asString(); + + /** + * Determines whether the given {@code String} is a valid tag value. + * + * @param value the tag value to be validated. + * @return whether the value is valid. + */ + private static boolean isValid(String value) { + return value.length() <= MAX_LENGTH && StringUtil.isPrintableString(value); + } + } + + /** A tag value associated with a {@link TagKeyLong}. */ + @Immutable + @AutoValue + public abstract static class TagValueLong extends TagValue { + + TagValueLong() {} + + /** + * Constructs a {@code TagValueLong} from the given {@code long}. + * + * @param value the tag value. + */ + public static TagValueLong create(long value) { + return new AutoValue_TagValue_TagValueLong(value); + } + + @Override + public final <T> T match( + Function<? super TagValueString, T> stringFunction, + Function<? super TagValueLong, T> longFunction, + Function<? super TagValueBoolean, T> booleanFunction, + Function<? super TagValue, T> defaultFunction) { + return longFunction.apply(this); + } + + /** + * Returns the tag value as a {@code long}. + * + * @return the tag value as a {@code long}. + */ + public abstract long asLong(); + } + + /** A tag value associated with a {@link TagKeyBoolean}. */ + @Immutable + @AutoValue + public abstract static class TagValueBoolean extends TagValue { + private static final TagValueBoolean TRUE_VALUE = createInternal(true); + private static final TagValueBoolean FALSE_VALUE = createInternal(false); + + TagValueBoolean() {} + + /** + * Constructs a {@code TagValueBoolean} from the given {@code boolean}. + * + * @param value the tag value. + */ + public static TagValueBoolean create(boolean value) { + return value ? TRUE_VALUE : FALSE_VALUE; + } + + private static TagValueBoolean createInternal(boolean value) { + return new AutoValue_TagValue_TagValueBoolean(value); + } + + @Override + public final <T> T match( + Function<? super TagValueString, T> stringFunction, + Function<? super TagValueLong, T> longFunction, + Function<? super TagValueBoolean, T> booleanFunction, + Function<? super TagValue, T> defaultFunction) { + return booleanFunction.apply(this); + } + + /** + * Returns the tag value as a {@code boolean}. + * + * @return the tag value as a {@code boolean}. + */ + public abstract boolean asBoolean(); + } +} diff --git a/api/src/main/java/io/opencensus/tags/Tagger.java b/api/src/main/java/io/opencensus/tags/Tagger.java new file mode 100644 index 00000000..1d786f71 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/Tagger.java @@ -0,0 +1,78 @@ +/* + * 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.tags; + +import io.opencensus.common.Scope; + +/** + * Object for creating new {@link TagContext}s and {@code TagContext}s based on the current context. + * + * <p>This class returns {@link TagContextBuilder builders} that can be used to create the + * implementation-dependent {@link TagContext}s. + * + * <p>Implementations may have different constraints and are free to convert tag contexts to their + * own subtypes. This means callers cannot assume the {@link #getCurrentTagContext() current + * context} is the same instance as the one {@link #withTagContext(TagContext) placed into scope}. + */ +public abstract class Tagger { + + /** + * Returns an empty {@code TagContext}. + * + * @return an empty {@code TagContext}. + */ + public abstract TagContext empty(); + + /** + * Returns the current {@code TagContext}. + * + * @return the current {@code TagContext}. + */ + public abstract TagContext getCurrentTagContext(); + + /** + * Returns a new empty {@code Builder}. + * + * @return a new empty {@code Builder}. + */ + public abstract TagContextBuilder emptyBuilder(); + + /** + * Returns a builder based on this {@code TagContext}. + * + * @return a builder based on this {@code TagContext}. + */ + public abstract TagContextBuilder toBuilder(TagContext tags); + + /** + * Returns a new builder created from the current {@code TagContext}. + * + * @return a new builder created from the current {@code TagContext}. + */ + public abstract TagContextBuilder currentBuilder(); + + /** + * Enters the scope of code where the given {@code 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. + */ + public abstract Scope withTagContext(TagContext tags); +} diff --git a/api/src/main/java/io/opencensus/tags/TaggingState.java b/api/src/main/java/io/opencensus/tags/TaggingState.java new file mode 100644 index 00000000..861aca74 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/TaggingState.java @@ -0,0 +1,40 @@ +/* + * 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.tags; + +/** State of the {@link TagsComponent}. */ +public enum TaggingState { + // TODO(sebright): Should we add a state that propagates the tags, but doesn't allow + // modifications? + + /** + * State that fully enables tagging. + * + * <p>The {@link TagsComponent} can add tags to {@link TagContext}s, propagate {@code TagContext}s + * in the current context, and serialize {@code TagContext}s. + */ + ENABLED, + + /** + * State that disables tagging. + * + * <p>The {@link TagsComponent} may not add tags to {@link TagContext}s, propagate {@code + * TagContext}s in the current context, or serialize {@code TagContext}s. + */ + // TODO(sebright): Document how this interacts with stats collection. + DISABLED +} diff --git a/api/src/main/java/io/opencensus/tags/Tags.java b/api/src/main/java/io/opencensus/tags/Tags.java new file mode 100644 index 00000000..5378fa5a --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/Tags.java @@ -0,0 +1,104 @@ +/* + * 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.tags; + +import com.google.common.annotations.VisibleForTesting; +import io.opencensus.internal.Provider; +import io.opencensus.tags.propagation.TagPropagationComponent; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** Class for accessing the default {@link TagsComponent}. */ +public final class Tags { + private static final Logger logger = Logger.getLogger(Tags.class.getName()); + + private static final TagsComponent tagsComponent = + loadTagsComponent(TagsComponent.class.getClassLoader()); + + private Tags() {} + + /** + * Returns the default {@code Tagger}. + * + * @return the default {@code Tagger}. + */ + public static Tagger getTagger() { + return tagsComponent.getTagger(); + } + + /** + * Returns the default {@code TagPropagationComponent}. + * + * @return the default {@code TagPropagationComponent}. + */ + public static TagPropagationComponent getTagPropagationComponent() { + return tagsComponent.getTagPropagationComponent(); + } + + /** + * Returns the current {@code TaggingState}. + * + * <p>When no implementation is available, {@code getState} always returns {@link + * TaggingState#DISABLED}. + * + * @return the current {@code TaggingState}. + */ + public static TaggingState getState() { + return tagsComponent.getState(); + } + + /** + * Sets the current {@code TaggingState}. + * + * <p>When no implementation is available, {@code setState} has no effect. + * + * @param state the new {@code TaggingState}. + */ + public static void setState(TaggingState state) { + tagsComponent.setState(state); + } + + // Any provider that may be used for TagsComponent can be added here. + @VisibleForTesting + static TagsComponent loadTagsComponent(ClassLoader classLoader) { + try { + // Call Class.forName with literal string name of the class to help shading tools. + return Provider.createInstance( + Class.forName("io.opencensus.impl.tags.TagsComponentImpl", true, classLoader), + TagsComponent.class); + } catch (ClassNotFoundException e) { + logger.log( + Level.FINE, + "Couldn't load full implementation for TagsComponent, now trying to load lite " + + "implementation.", + e); + } + try { + // Call Class.forName with literal string name of the class to help shading tools. + return Provider.createInstance( + Class.forName("io.opencensus.impllite.tags.TagsComponentImplLite", true, classLoader), + TagsComponent.class); + } catch (ClassNotFoundException e) { + logger.log( + Level.FINE, + "Couldn't load lite implementation for TagsComponent, now using " + + "default implementation for TagsComponent.", + e); + } + return NoopTags.getNoopTagsComponent(); + } +} diff --git a/api/src/main/java/io/opencensus/tags/TagsComponent.java b/api/src/main/java/io/opencensus/tags/TagsComponent.java new file mode 100644 index 00000000..755173d8 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/TagsComponent.java @@ -0,0 +1,52 @@ +/* + * 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.tags; + +import io.opencensus.tags.propagation.TagPropagationComponent; + +/** + * Class that holds the implementation for {@link Tagger} and {@link TagPropagationComponent}. + * + * <p>All objects returned by methods on {@code TagsComponent} are cacheable. + */ +public abstract class TagsComponent { + + /** Returns the {@link Tagger} for this implementation. */ + public abstract Tagger getTagger(); + + /** Returns the {@link TagPropagationComponent} for this implementation. */ + public abstract TagPropagationComponent getTagPropagationComponent(); + + /** + * Returns the current {@code TaggingState}. + * + * <p>When no implementation is available, {@code getState} always returns {@link + * TaggingState#DISABLED}. + * + * @return the current {@code TaggingState}. + */ + public abstract TaggingState getState(); + + /** + * Sets the current {@code TaggingState}. + * + * <p>When no implementation is available, {@code setState} has no effect. + * + * @param state the new {@code TaggingState}. + */ + public abstract void setState(TaggingState state); +} diff --git a/api/src/main/java/io/opencensus/tags/package-info.java b/api/src/main/java/io/opencensus/tags/package-info.java new file mode 100644 index 00000000..2a332f6d --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/package-info.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. + */ + +/** + * API for associating tags with scoped operations. + * + * <p>This package manages a set of tags in the {@code io.grpc.Context}. The tags can be used to + * label anything that is associated with a specific operation. For example, the {@code + * io.opencensus.stats} package labels all stats with the current tags. + * + * <p>{@link io.opencensus.tags.Tag Tags} are key-value pairs. The {@link io.opencensus.tags.TagKey + * keys} are wrapped {@code String}s, but the values can have multiple types, such as {@code + * String}, {@code long}, and {@code boolean}. They are stored as a map in a {@link + * io.opencensus.tags.TagContext}. + * + * <p>Note that tags are independent of the tracing data that is propagated in the {@code + * io.grpc.Context}, such as trace ID. + */ +// TODO(sebright): Add code examples after the API is updated to use a TagContext factory. +package io.opencensus.tags; diff --git a/api/src/main/java/io/opencensus/tags/propagation/TagContextBinarySerializer.java b/api/src/main/java/io/opencensus/tags/propagation/TagContextBinarySerializer.java new file mode 100644 index 00000000..e54e5d3d --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/propagation/TagContextBinarySerializer.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.tags.propagation; + +import io.opencensus.tags.TagContext; + +/** + * Object for serializing and deserializing {@link TagContext}s with the binary format. + * + * <p>See <a + * href="https://github.com/census-instrumentation/opencensus-specs/blob/master/encodings/BinaryEncoding.md#tag-context">opencensus-specs</a> + * for the specification of the cross-language binary serialization format. + */ +public abstract class TagContextBinarySerializer { + + /** + * Serializes the {@code TagContext} into the on-the-wire representation. + * + * <p>This method should be the inverse of {@link #fromByteArray}. + * + * @param tags the {@code TagContext} to serialize. + * @return the on-the-wire representation of a {@code TagContext}. + */ + public abstract byte[] toByteArray(TagContext tags); + + /** + * Creates a {@code TagContext} from the given on-the-wire encoded representation. + * + * <p>This method should be the inverse of {@link #toByteArray}. + * + * @param bytes on-the-wire representation of a {@code TagContext}. + * @return a {@code TagContext} deserialized from {@code bytes}. + * @throws TagContextParseException if there is a parse error or the serialized {@code TagContext} + * contains invalid tags. + */ + public abstract TagContext fromByteArray(byte[] bytes) throws TagContextParseException; +} diff --git a/api/src/main/java/io/opencensus/tags/propagation/TagContextParseException.java b/api/src/main/java/io/opencensus/tags/propagation/TagContextParseException.java new file mode 100644 index 00000000..0174c416 --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/propagation/TagContextParseException.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.tags.propagation; + +import io.opencensus.tags.TagContext; + +/** Exception thrown when a {@link TagContext} cannot be parsed. */ +public final class TagContextParseException extends Exception { + private static final long serialVersionUID = 0L; + + /** + * Constructs a new {@code TagContextParseException} with the given message. + * + * @param message a message describing the parse error. + */ + public TagContextParseException(String message) { + super(message); + } + + /** + * Constructs a new {@code TagContextParseException} with the given message and cause. + * + * @param message a message describing the parse error. + * @param cause the cause of the parse error. + */ + public TagContextParseException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/api/src/main/java/io/opencensus/tags/propagation/TagPropagationComponent.java b/api/src/main/java/io/opencensus/tags/propagation/TagPropagationComponent.java new file mode 100644 index 00000000..c51a845c --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/propagation/TagPropagationComponent.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.tags.propagation; + +import io.opencensus.tags.TagContext; + +/** Object containing all supported {@link TagContext} propagation formats. */ +// TODO(sebright): Add an HTTP serializer. +public abstract class TagPropagationComponent { + + /** + * Returns the {@link TagContextBinarySerializer} for this implementation. + * + * @return the {@code TagContextBinarySerializer} for this implementation. + */ + public abstract TagContextBinarySerializer getBinarySerializer(); +} diff --git a/api/src/main/java/io/opencensus/tags/unsafe/ContextUtils.java b/api/src/main/java/io/opencensus/tags/unsafe/ContextUtils.java new file mode 100644 index 00000000..2baf1a2a --- /dev/null +++ b/api/src/main/java/io/opencensus/tags/unsafe/ContextUtils.java @@ -0,0 +1,52 @@ +/* + * 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.tags.unsafe; + +import io.grpc.Context; +import io.opencensus.tags.Tag; +import io.opencensus.tags.TagContext; +import java.util.Collections; +import java.util.Iterator; +import javax.annotation.concurrent.Immutable; + +/** + * Utility methods for accessing the {@link TagContext} contained in the {@link io.grpc.Context}. + * + * <p>Most code should interact with the current context via the public APIs in {@link + * io.opencensus.tags.TagContext} and avoid accessing {@link #TAG_CONTEXT_KEY} directly. + */ +public final class ContextUtils { + private static final TagContext EMPTY_TAG_CONTEXT = new EmptyTagContext(); + + private ContextUtils() {} + + /** + * The {@link io.grpc.Context.Key} used to interact with the {@code TagContext} contained in the + * {@link io.grpc.Context}. + */ + public static final Context.Key<TagContext> TAG_CONTEXT_KEY = + Context.keyWithDefault("opencensus-tag-context-key", EMPTY_TAG_CONTEXT); + + @Immutable + private static final class EmptyTagContext extends TagContext { + + @Override + protected Iterator<Tag> getIterator() { + return Collections.<Tag>emptySet().iterator(); + } + } +} |