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

Commit 44906aa

Browse files
authored
Tags: Add HTTP text serializer API. (#1800)
* Tags: Add HTTP text serializer API. * Add setter/getter and inject/extract to support encoding tags to multiple strings. * Import checker framework annotation. * Update changelog
1 parent 8564d81 commit 44906aa

6 files changed

Lines changed: 307 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
## Unreleased
2+
- Add HTTP text format serializer to Tag propagation component.
23

34
## 0.20.0 - 2019-03-28
45
- Add OpenCensus Java OC-Agent Trace Exporter.

api/src/main/java/io/opencensus/tags/NoopTags.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,20 @@
2020
import io.opencensus.internal.NoopScope;
2121
import io.opencensus.internal.Utils;
2222
import io.opencensus.tags.propagation.TagContextBinarySerializer;
23+
import io.opencensus.tags.propagation.TagContextDeserializationException;
24+
import io.opencensus.tags.propagation.TagContextSerializationException;
25+
import io.opencensus.tags.propagation.TagContextTextFormat;
2326
import io.opencensus.tags.propagation.TagPropagationComponent;
2427
import java.util.Collections;
2528
import java.util.Iterator;
29+
import java.util.List;
2630
import javax.annotation.concurrent.Immutable;
2731
import javax.annotation.concurrent.ThreadSafe;
2832

33+
/*>>>
34+
import org.checkerframework.checker.nullness.qual.NonNull;
35+
*/
36+
2937
/** No-op implementations of tagging classes. */
3038
final class NoopTags {
3139

@@ -80,8 +88,17 @@ static TagContextBinarySerializer getNoopTagContextBinarySerializer() {
8088
return NoopTagContextBinarySerializer.INSTANCE;
8189
}
8290

91+
/**
92+
* Returns a {@code TagContextTextFormat} that serializes all {@code TagContext}s to empty strings
93+
* and deserializes all inputs to empty {@code TagContext}s.
94+
*/
95+
static TagContextTextFormat getNoopTagContextTextSerializer() {
96+
return NoopTagContextTextFormat.INSTANCE;
97+
}
98+
8399
@ThreadSafe
84100
private static final class NoopTagsComponent extends TagsComponent {
101+
85102
private volatile boolean isRead;
86103

87104
@Override
@@ -110,6 +127,7 @@ public void setState(TaggingState state) {
110127

111128
@Immutable
112129
private static final class NoopTagger extends Tagger {
130+
113131
static final Tagger INSTANCE = new NoopTagger();
114132

115133
@Override
@@ -147,6 +165,7 @@ public Scope withTagContext(TagContext tags) {
147165

148166
@Immutable
149167
private static final class NoopTagContextBuilder extends TagContextBuilder {
168+
150169
static final TagContextBuilder INSTANCE = new NoopTagContextBuilder();
151170

152171
@Override
@@ -184,6 +203,7 @@ public Scope buildScoped() {
184203

185204
@Immutable
186205
private static final class NoopTagContext extends TagContext {
206+
187207
static final TagContext INSTANCE = new NoopTagContext();
188208

189209
// TODO(sebright): Is there any way to let the user know that their tags were ignored?
@@ -195,16 +215,23 @@ protected Iterator<Tag> getIterator() {
195215

196216
@Immutable
197217
private static final class NoopTagPropagationComponent extends TagPropagationComponent {
218+
198219
static final TagPropagationComponent INSTANCE = new NoopTagPropagationComponent();
199220

200221
@Override
201222
public TagContextBinarySerializer getBinarySerializer() {
202223
return getNoopTagContextBinarySerializer();
203224
}
225+
226+
@Override
227+
public TagContextTextFormat getCorrelationContextFormat() {
228+
return getNoopTagContextTextSerializer();
229+
}
204230
}
205231

206232
@Immutable
207233
private static final class NoopTagContextBinarySerializer extends TagContextBinarySerializer {
234+
208235
static final TagContextBinarySerializer INSTANCE = new NoopTagContextBinarySerializer();
209236
static final byte[] EMPTY_BYTE_ARRAY = {};
210237

@@ -220,4 +247,32 @@ public TagContext fromByteArray(byte[] bytes) {
220247
return getNoopTagContext();
221248
}
222249
}
250+
251+
@Immutable
252+
private static final class NoopTagContextTextFormat extends TagContextTextFormat {
253+
254+
static final NoopTagContextTextFormat INSTANCE = new NoopTagContextTextFormat();
255+
256+
@Override
257+
public List<String> fields() {
258+
return Collections.<String>emptyList();
259+
}
260+
261+
@Override
262+
public <C /*>>> extends @NonNull Object*/> void inject(
263+
TagContext tagContext, C carrier, Setter<C> setter)
264+
throws TagContextSerializationException {
265+
Utils.checkNotNull(tagContext, "tagContext");
266+
Utils.checkNotNull(carrier, "carrier");
267+
Utils.checkNotNull(setter, "setter");
268+
}
269+
270+
@Override
271+
public <C /*>>> extends @NonNull Object*/> TagContext extract(C carrier, Getter<C> getter)
272+
throws TagContextDeserializationException {
273+
Utils.checkNotNull(carrier, "carrier");
274+
Utils.checkNotNull(getter, "getter");
275+
return getNoopTagContext();
276+
}
277+
}
223278
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
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.tags.propagation;
18+
19+
import io.opencensus.tags.TagContext;
20+
import java.util.List;
21+
import javax.annotation.Nullable;
22+
23+
/*>>>
24+
import org.checkerframework.checker.nullness.qual.NonNull;
25+
*/
26+
27+
/**
28+
* Object for injecting and extracting {@link TagContext} as text into carriers that travel in-band
29+
* across process boundaries. Tags are often encoded as messaging or RPC request headers.
30+
*
31+
* <p>When using http, the carrier of propagated data on both the client (injector) and server
32+
* (extractor) side is usually an http request. Propagation is usually implemented via library-
33+
* specific request interceptors, where the client-side injects tags and the server-side extracts
34+
* them.
35+
*
36+
* <p>Example of usage on the client:
37+
*
38+
* <pre>{@code
39+
* private static final Tagger tagger = Tags.getTagger();
40+
* private static final TagContextTextFormat textFormat =
41+
* Tags.getPropagationComponent().getCorrelationContextFormat();
42+
* private static final TagContextTextFormat.Setter setter =
43+
* new TagContextTextFormat.Setter<HttpURLConnection>() {
44+
* public void put(HttpURLConnection carrier, String key, String value) {
45+
* carrier.setRequestProperty(field, value);
46+
* }
47+
* };
48+
*
49+
* void makeHttpRequest() {
50+
* TagContext tagContext = tagger.emptyBuilder().put(K, V).build();
51+
* try (Scope s = tagger.withTagContext(tagContext)) {
52+
* HttpURLConnection connection =
53+
* (HttpURLConnection) new URL("http://myserver").openConnection();
54+
* textFormat.inject(tagContext, connection, httpURLConnectionSetter);
55+
* // Send the request, wait for response and maybe set the status if not ok.
56+
* }
57+
* }
58+
* }</pre>
59+
*
60+
* <p>Example of usage on the server:
61+
*
62+
* <pre>{@code
63+
* private static final Tagger tagger = Tags.getTagger();
64+
* private static final TagContextTextFormat textFormat =
65+
* Tags.getPropagationComponent().getCorrelationContextFormat();
66+
* private static final TagContextTextFormat.Getter<HttpRequest> getter = ...;
67+
*
68+
* void onRequestReceived(HttpRequest request) {
69+
* TagContext tagContext = textFormat.extract(request, getter);
70+
* try (Scope s = tagger.withTagContext(tagContext)) {
71+
* // Handle request and send response back.
72+
* }
73+
* }
74+
* }</pre>
75+
*
76+
* @since 0.21
77+
*/
78+
public abstract class TagContextTextFormat {
79+
80+
/**
81+
* The propagation fields defined. If your carrier is reused, you should delete the fields here
82+
* before calling {@link #inject(TagContext, Object, Setter)}.
83+
*
84+
* <p>For example, if the carrier is a single-use or immutable request object, you don't need to
85+
* clear fields as they couldn't have been set before. If it is a mutable, retryable object,
86+
* successive calls should clear these fields first.
87+
*
88+
* @since 0.21
89+
*/
90+
// The use cases of this are:
91+
// * allow pre-allocation of fields, especially in systems like gRPC Metadata
92+
// * allow a single-pass over an iterator (ex OpenTracing has no getter in TextMap)
93+
public abstract List<String> fields();
94+
95+
/**
96+
* Injects the tag context downstream. For example, as http headers.
97+
*
98+
* @param tagContext the tag context.
99+
* @param carrier holds propagation fields. For example, an outgoing message or http request.
100+
* @param setter invoked for each propagation key to add or remove.
101+
* @throws TagContextSerializationException if the given tag context cannot be serialized.
102+
* @since 0.21
103+
*/
104+
public abstract <C /*>>> extends @NonNull Object*/> void inject(
105+
TagContext tagContext, C carrier, Setter<C> setter) throws TagContextSerializationException;
106+
107+
/**
108+
* Class that allows a {@code TagContextTextFormat} to set propagated fields into a carrier.
109+
*
110+
* <p>{@code Setter} is stateless and allows to be saved as a constant to avoid runtime
111+
* allocations.
112+
*
113+
* @param <C> carrier of propagation fields, such as an http request
114+
* @since 0.21
115+
*/
116+
public abstract static class Setter<C> {
117+
118+
/**
119+
* Replaces a propagated field with the given value.
120+
*
121+
* <p>For example, a setter for an {@link java.net.HttpURLConnection} would be the method
122+
* reference {@link java.net.HttpURLConnection#addRequestProperty(String, String)}
123+
*
124+
* @param carrier holds propagation fields. For example, an outgoing message or http request.
125+
* @param key the key of the field.
126+
* @param value the value of the field.
127+
* @since 0.21
128+
*/
129+
public abstract void put(C carrier, String key, String value);
130+
}
131+
132+
/**
133+
* Extracts the tag context from upstream. For example, as http headers.
134+
*
135+
* @param carrier holds propagation fields. For example, an outgoing message or http request.
136+
* @param getter invoked for each propagation key to get.
137+
* @throws TagContextDeserializationException if the input is invalid
138+
* @since 0.21
139+
*/
140+
public abstract <C /*>>> extends @NonNull Object*/> TagContext extract(
141+
C carrier, Getter<C> getter) throws TagContextDeserializationException;
142+
143+
/**
144+
* Class that allows a {@code TagContextTextFormat} to read propagated fields from a carrier.
145+
*
146+
* <p>{@code Getter} is stateless and allows to be saved as a constant to avoid runtime
147+
* allocations.
148+
*
149+
* @param <C> carrier of propagation fields, such as an http request
150+
* @since 0.21
151+
*/
152+
public abstract static class Getter<C> {
153+
154+
/**
155+
* Returns the first value of the given propagation {@code key} or returns {@code null}.
156+
*
157+
* @param carrier carrier of propagation fields, such as an http request
158+
* @param key the key of the field.
159+
* @return the first value of the given propagation {@code key} or returns {@code null}.
160+
* @since 0.21
161+
*/
162+
@Nullable
163+
public abstract String get(C carrier, String key);
164+
}
165+
}

api/src/main/java/io/opencensus/tags/propagation/TagPropagationComponent.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
*
2424
* @since 0.8
2525
*/
26-
// TODO(sebright): Add an HTTP serializer.
2726
public abstract class TagPropagationComponent {
2827

2928
/**
@@ -33,4 +32,15 @@ public abstract class TagPropagationComponent {
3332
* @since 0.8
3433
*/
3534
public abstract TagContextBinarySerializer getBinarySerializer();
35+
36+
/**
37+
* Returns the {@link TagContextTextFormat} for this implementation.
38+
*
39+
* <p>OpenCensus uses W3C Correlation Context as the HTTP text format. For more details, see <a
40+
* href="https://github.com/w3c/correlation-context">correlation-context</a>.
41+
*
42+
* @return the {@code TagContextTextFormat} for this implementation.
43+
* @since 0.21
44+
*/
45+
public abstract TagContextTextFormat getCorrelationContextFormat();
3646
}

0 commit comments

Comments
 (0)