Skip to content
This repository was archived by the owner on Dec 23, 2023. It is now read-only.

Commit 1023986

Browse files
authored
Tags: Implementation of w3c correlation context format. (#1810)
1 parent fbd628f commit 1023986

File tree

9 files changed

+526
-33
lines changed

9 files changed

+526
-33
lines changed

impl_core/src/main/java/io/opencensus/implcore/tags/propagation/SerializationUtils.java renamed to impl_core/src/main/java/io/opencensus/implcore/tags/propagation/BinarySerializationUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,12 @@
6666
* </ul>
6767
* </ul>
6868
*/
69-
final class SerializationUtils {
69+
final class BinarySerializationUtils {
7070

7171
private static final TagMetadata METADATA_UNLIMITED_PROPAGATION =
7272
TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION);
7373

74-
private SerializationUtils() {}
74+
private BinarySerializationUtils() {}
7575

7676
@VisibleForTesting static final int VERSION_ID = 0;
7777
@VisibleForTesting static final int TAG_FIELD_ID = 0;
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright 2019, OpenCensus Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.opencensus.implcore.tags.propagation;
18+
19+
import static com.google.common.base.Preconditions.checkArgument;
20+
import static com.google.common.base.Preconditions.checkNotNull;
21+
22+
import com.google.common.annotations.VisibleForTesting;
23+
import com.google.common.base.Splitter;
24+
import io.opencensus.implcore.internal.CurrentState;
25+
import io.opencensus.implcore.internal.CurrentState.State;
26+
import io.opencensus.implcore.tags.TagMapImpl;
27+
import io.opencensus.implcore.tags.TagValueWithMetadata;
28+
import io.opencensus.tags.InternalUtils;
29+
import io.opencensus.tags.Tag;
30+
import io.opencensus.tags.TagContext;
31+
import io.opencensus.tags.TagKey;
32+
import io.opencensus.tags.TagMetadata;
33+
import io.opencensus.tags.TagMetadata.TagTtl;
34+
import io.opencensus.tags.TagValue;
35+
import io.opencensus.tags.propagation.TagContextDeserializationException;
36+
import io.opencensus.tags.propagation.TagContextSerializationException;
37+
import io.opencensus.tags.propagation.TagContextTextFormat;
38+
import java.util.Collections;
39+
import java.util.HashMap;
40+
import java.util.Iterator;
41+
import java.util.List;
42+
import java.util.Map;
43+
import javax.annotation.Nullable;
44+
45+
/*>>>
46+
import org.checkerframework.checker.nullness.qual.NonNull;
47+
*/
48+
49+
/**
50+
* Implementation of the W3C correlation context propagation protocol. See <a
51+
* href=https://github.com/w3c/correlation-context>w3c/correlation-context</a>.
52+
*/
53+
final class CorrelationContextFormat extends TagContextTextFormat {
54+
55+
@VisibleForTesting static final String CORRELATION_CONTEXT = "Correlation-Context";
56+
private static final List<String> FIELDS = Collections.singletonList(CORRELATION_CONTEXT);
57+
58+
@VisibleForTesting static final int MAX_NUMBER_OF_TAGS = 180;
59+
private static final int TAG_SERIALIZED_SIZE_LIMIT = 4096;
60+
private static final int TAGCONTEXT_SERIALIZED_SIZE_LIMIT = 8192;
61+
private static final char TAG_KEY_VALUE_DELIMITER = '=';
62+
private static final char TAG_DELIMITER = ',';
63+
private static final Splitter TAG_KEY_VALUE_SPLITTER = Splitter.on(TAG_KEY_VALUE_DELIMITER);
64+
private static final Splitter TAG_SPLITTER = Splitter.on(TAG_DELIMITER);
65+
66+
// TODO(songya): These constants are for tag metadata. Uncomment them when we decided to support
67+
// encoding tag metadata.
68+
private static final char TAG_PROPERTIES_DELIMITER = ';';
69+
// private static final char TAG_PROPERTIES_KEY_VALUE_DELIMITER = '=';
70+
71+
@VisibleForTesting
72+
static final TagMetadata METADATA_UNLIMITED_PROPAGATION =
73+
TagMetadata.create(TagTtl.UNLIMITED_PROPAGATION);
74+
75+
private final CurrentState state;
76+
77+
CorrelationContextFormat(CurrentState state) {
78+
this.state = state;
79+
}
80+
81+
@Override
82+
public List<String> fields() {
83+
return FIELDS;
84+
}
85+
86+
@Override
87+
public <C /*>>> extends @NonNull Object*/> void inject(
88+
TagContext tagContext, C carrier, Setter<C> setter) throws TagContextSerializationException {
89+
checkNotNull(tagContext, "tagContext");
90+
checkNotNull(carrier, "carrier");
91+
checkNotNull(setter, "setter");
92+
if (State.DISABLED.equals(state.getInternal())) {
93+
return;
94+
}
95+
96+
try {
97+
StringBuilder stringBuilder = new StringBuilder(TAGCONTEXT_SERIALIZED_SIZE_LIMIT);
98+
int totalChars = 0; // Here chars are equivalent to bytes, since we're using ascii chars.
99+
int totalTags = 0;
100+
for (Iterator<Tag> i = InternalUtils.getTags(tagContext); i.hasNext(); ) {
101+
Tag tag = i.next();
102+
if (TagTtl.NO_PROPAGATION.equals(tag.getTagMetadata().getTagTtl())) {
103+
continue;
104+
}
105+
if (stringBuilder.length() > 0) {
106+
stringBuilder.append(TAG_DELIMITER);
107+
}
108+
totalTags++;
109+
totalChars += encodeTag(tag, stringBuilder);
110+
}
111+
checkArgument(
112+
totalTags <= MAX_NUMBER_OF_TAGS,
113+
"Number of tags in the TagContext exceeds limit " + MAX_NUMBER_OF_TAGS);
114+
// Note per W3C spec, only the length of tag key and value counts towards the total length.
115+
// Length of properties (a.k.a TagMetadata) does not count.
116+
checkArgument(
117+
totalChars <= TAGCONTEXT_SERIALIZED_SIZE_LIMIT,
118+
"Size of TagContext exceeds the maximum serialized size "
119+
+ TAGCONTEXT_SERIALIZED_SIZE_LIMIT);
120+
setter.put(carrier, CORRELATION_CONTEXT, stringBuilder.toString());
121+
} catch (IllegalArgumentException e) {
122+
throw new TagContextSerializationException("Failed to serialize TagContext", e);
123+
}
124+
}
125+
126+
// Encodes the tag to the given string builder, and returns the length of encoded key-value pair.
127+
private static int encodeTag(Tag tag, StringBuilder stringBuilder) {
128+
String key = tag.getKey().getName();
129+
String value = tag.getValue().asString();
130+
int charsOfTag = key.length() + value.length();
131+
// This should never happen with our current constraints (<= 255 chars) on tags.
132+
checkArgument(
133+
charsOfTag <= TAG_SERIALIZED_SIZE_LIMIT,
134+
"Serialized size of tag " + tag + " exceeds limit " + TAG_SERIALIZED_SIZE_LIMIT);
135+
136+
// TODO(songy23): do we want to encode TagMetadata?
137+
stringBuilder.append(key).append(TAG_KEY_VALUE_DELIMITER).append(value);
138+
return charsOfTag;
139+
}
140+
141+
@Override
142+
public <C /*>>> extends @NonNull Object*/> TagContext extract(C carrier, Getter<C> getter)
143+
throws TagContextDeserializationException {
144+
checkNotNull(carrier, "carrier");
145+
checkNotNull(getter, "getter");
146+
if (State.DISABLED.equals(state.getInternal())) {
147+
return TagMapImpl.EMPTY;
148+
}
149+
150+
@Nullable String correlationContext = getter.get(carrier, CORRELATION_CONTEXT);
151+
if (correlationContext == null) {
152+
throw new TagContextDeserializationException(CORRELATION_CONTEXT + " not present.");
153+
}
154+
try {
155+
if (correlationContext.isEmpty()) {
156+
return TagMapImpl.EMPTY;
157+
}
158+
Map<TagKey, TagValueWithMetadata> tags = new HashMap<>();
159+
List<String> stringTags = TAG_SPLITTER.splitToList(correlationContext);
160+
for (String stringTag : stringTags) {
161+
decodeTag(stringTag, tags);
162+
}
163+
return new TagMapImpl(tags);
164+
} catch (IllegalArgumentException e) {
165+
throw new TagContextDeserializationException("Invalid TagContext: " + correlationContext, e);
166+
}
167+
}
168+
169+
// Decodes tag key, value and metadata from the encoded string tag, then puts it into the tag map.
170+
// The format of encoded string tag is name1=value1;properties1=p1;properties2=p2.
171+
private static void decodeTag(String stringTag, Map<TagKey, TagValueWithMetadata> tags) {
172+
String keyWithValue;
173+
int firstPropertyIndex = stringTag.indexOf(TAG_PROPERTIES_DELIMITER);
174+
if (firstPropertyIndex != -1) { // Tag with properties.
175+
keyWithValue = stringTag.substring(0, firstPropertyIndex);
176+
// TODO(songya): support decoding tag properties.
177+
} else { // Tag without properties.
178+
keyWithValue = stringTag;
179+
}
180+
List<String> keyValuePair = TAG_KEY_VALUE_SPLITTER.splitToList(keyWithValue);
181+
checkArgument(keyValuePair.size() == 2, "Malformed tag " + stringTag);
182+
TagKey key = TagKey.create(keyValuePair.get(0).trim());
183+
TagValue value = TagValue.create(keyValuePair.get(1).trim());
184+
TagValueWithMetadata valueWithMetadata =
185+
TagValueWithMetadata.create(value, METADATA_UNLIMITED_PROPAGATION);
186+
tags.put(key, valueWithMetadata);
187+
}
188+
}

impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagContextBinarySerializerImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ final class TagContextBinarySerializerImpl extends TagContextBinarySerializer {
3737
public byte[] toByteArray(TagContext tags) throws TagContextSerializationException {
3838
return state.getInternal() == State.DISABLED
3939
? EMPTY_BYTE_ARRAY
40-
: SerializationUtils.serializeBinary(tags);
40+
: BinarySerializationUtils.serializeBinary(tags);
4141
}
4242

4343
@Override
4444
public TagContext fromByteArray(byte[] bytes) throws TagContextDeserializationException {
4545
return state.getInternal() == State.DISABLED
4646
? TagMapImpl.EMPTY
47-
: SerializationUtils.deserializeBinary(bytes);
47+
: BinarySerializationUtils.deserializeBinary(bytes);
4848
}
4949
}

impl_core/src/main/java/io/opencensus/implcore/tags/propagation/TagPropagationComponentImpl.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
/** Implementation of {@link TagPropagationComponent}. */
2525
public final class TagPropagationComponentImpl extends TagPropagationComponent {
2626
private final TagContextBinarySerializer tagContextBinarySerializer;
27+
private final TagContextTextFormat tagContextTextFormat;
2728

2829
public TagPropagationComponentImpl(CurrentState state) {
2930
tagContextBinarySerializer = new TagContextBinarySerializerImpl(state);
31+
tagContextTextFormat = new CorrelationContextFormat(state);
3032
}
3133

3234
@Override
@@ -36,6 +38,6 @@ public TagContextBinarySerializer getBinarySerializer() {
3638

3739
@Override
3840
public TagContextTextFormat getCorrelationContextFormat() {
39-
throw new UnsupportedOperationException("not implemented");
41+
return tagContextTextFormat;
4042
}
4143
}

0 commit comments

Comments
 (0)