• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017, 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.trace.propagation;
18 
19 import io.opencensus.common.ExperimentalApi;
20 import io.opencensus.internal.Utils;
21 import io.opencensus.trace.SpanContext;
22 import java.util.Collections;
23 import java.util.List;
24 import javax.annotation.Nullable;
25 
26 /*>>>
27 import org.checkerframework.checker.nullness.qual.NonNull;
28 */
29 
30 /**
31  * Injects and extracts {@link SpanContext trace identifiers} as text into carriers that travel
32  * in-band across process boundaries. Identifiers are often encoded as messaging or RPC request
33  * headers.
34  *
35  * <p>When using http, the carrier of propagated data on both the client (injector) and server
36  * (extractor) side is usually an http request. Propagation is usually implemented via library-
37  * specific request interceptors, where the client-side injects span identifiers and the server-side
38  * extracts them.
39  *
40  * <p>Example of usage on the client:
41  *
42  * <pre>{@code
43  * private static final Tracer tracer = Tracing.getTracer();
44  * private static final TextFormat textFormat = Tracing.getPropagationComponent().getTextFormat();
45  * private static final TextFormat.Setter setter = new TextFormat.Setter<HttpURLConnection>() {
46  *   public void put(HttpURLConnection carrier, String key, String value) {
47  *     carrier.setRequestProperty(field, value);
48  *   }
49  * }
50  *
51  * void makeHttpRequest() {
52  *   Span span = tracer.spanBuilder("Sent.MyRequest").startSpan();
53  *   try (Scope s = tracer.withSpan(span)) {
54  *     HttpURLConnection connection =
55  *         (HttpURLConnection) new URL("http://myserver").openConnection();
56  *     textFormat.inject(span.getContext(), connection, httpURLConnectionSetter);
57  *     // Send the request, wait for response and maybe set the status if not ok.
58  *   }
59  *   span.end();  // Can set a status.
60  * }
61  * }</pre>
62  *
63  * <p>Example of usage on the server:
64  *
65  * <pre>{@code
66  * private static final Tracer tracer = Tracing.getTracer();
67  * private static final TextFormat textFormat = Tracing.getPropagationComponent().getTextFormat();
68  * private static final TextFormat.Getter<HttpRequest> getter = ...;
69  *
70  * void onRequestReceived(HttpRequest request) {
71  *   SpanContext spanContext = textFormat.extract(request, getter);
72  *   Span span = tracer.spanBuilderWithRemoteParent("Recv.MyRequest", spanContext).startSpan();
73  *   try (Scope s = tracer.withSpan(span)) {
74  *     // Handle request and send response back.
75  *   }
76  *   span.end()
77  * }
78  * }</pre>
79  *
80  * @since 0.11
81  */
82 @ExperimentalApi
83 public abstract class TextFormat {
84   private static final NoopTextFormat NOOP_TEXT_FORMAT = new NoopTextFormat();
85 
86   /**
87    * The propagation fields defined. If your carrier is reused, you should delete the fields here
88    * before calling {@link #inject(SpanContext, Object, Setter)}.
89    *
90    * <p>For example, if the carrier is a single-use or immutable request object, you don't need to
91    * clear fields as they couldn't have been set before. If it is a mutable, retryable object,
92    * successive calls should clear these fields first.
93    *
94    * @since 0.11
95    */
96   // The use cases of this are:
97   // * allow pre-allocation of fields, especially in systems like gRPC Metadata
98   // * allow a single-pass over an iterator (ex OpenTracing has no getter in TextMap)
fields()99   public abstract List<String> fields();
100 
101   /**
102    * Injects the span context downstream. For example, as http headers.
103    *
104    * @param spanContext possibly not sampled.
105    * @param carrier holds propagation fields. For example, an outgoing message or http request.
106    * @param setter invoked for each propagation key to add or remove.
107    * @since 0.11
108    */
inject( SpanContext spanContext, C carrier, Setter<C> setter)109   public abstract <C /*>>> extends @NonNull Object*/> void inject(
110       SpanContext spanContext, C carrier, Setter<C> setter);
111 
112   /**
113    * Class that allows a {@code TextFormat} to set propagated fields into a carrier.
114    *
115    * <p>{@code Setter} is stateless and allows to be saved as a constant to avoid runtime
116    * allocations.
117    *
118    * @param <C> carrier of propagation fields, such as an http request
119    * @since 0.11
120    */
121   public abstract static class Setter<C> {
122 
123     /**
124      * Replaces a propagated field with the given value.
125      *
126      * <p>For example, a setter for an {@link java.net.HttpURLConnection} would be the method
127      * reference {@link java.net.HttpURLConnection#addRequestProperty(String, String)}
128      *
129      * @param carrier holds propagation fields. For example, an outgoing message or http request.
130      * @param key the key of the field.
131      * @param value the value of the field.
132      * @since 0.11
133      */
put(C carrier, String key, String value)134     public abstract void put(C carrier, String key, String value);
135   }
136 
137   /**
138    * Extracts the span context from upstream. For example, as http headers.
139    *
140    * @param carrier holds propagation fields. For example, an outgoing message or http request.
141    * @param getter invoked for each propagation key to get.
142    * @throws SpanContextParseException if the input is invalid
143    * @since 0.11
144    */
extract( C carrier, Getter<C> getter)145   public abstract <C /*>>> extends @NonNull Object*/> SpanContext extract(
146       C carrier, Getter<C> getter) throws SpanContextParseException;
147 
148   /**
149    * Class that allows a {@code TextFormat} to read propagated fields from a carrier.
150    *
151    * <p>{@code Getter} is stateless and allows to be saved as a constant to avoid runtime
152    * allocations.
153    *
154    * @param <C> carrier of propagation fields, such as an http request
155    * @since 0.11
156    */
157   public abstract static class Getter<C> {
158 
159     /**
160      * Returns the first value of the given propagation {@code key} or returns {@code null}.
161      *
162      * @param carrier carrier of propagation fields, such as an http request
163      * @param key the key of the field.
164      * @return the first value of the given propagation {@code key} or returns {@code null}.
165      * @since 0.11
166      */
167     @Nullable
get(C carrier, String key)168     public abstract String get(C carrier, String key);
169   }
170 
171   /**
172    * Returns the no-op implementation of the {@code TextFormat}.
173    *
174    * @return the no-op implementation of the {@code TextFormat}.
175    */
getNoopTextFormat()176   static TextFormat getNoopTextFormat() {
177     return NOOP_TEXT_FORMAT;
178   }
179 
180   private static final class NoopTextFormat extends TextFormat {
181 
NoopTextFormat()182     private NoopTextFormat() {}
183 
184     @Override
fields()185     public List<String> fields() {
186       return Collections.emptyList();
187     }
188 
189     @Override
inject( SpanContext spanContext, C carrier, Setter<C> setter)190     public <C /*>>> extends @NonNull Object*/> void inject(
191         SpanContext spanContext, C carrier, Setter<C> setter) {
192       Utils.checkNotNull(spanContext, "spanContext");
193       Utils.checkNotNull(carrier, "carrier");
194       Utils.checkNotNull(setter, "setter");
195     }
196 
197     @Override
extract(C carrier, Getter<C> getter)198     public <C /*>>> extends @NonNull Object*/> SpanContext extract(C carrier, Getter<C> getter) {
199       Utils.checkNotNull(carrier, "carrier");
200       Utils.checkNotNull(getter, "getter");
201       return SpanContext.INVALID;
202     }
203   }
204 }
205