diff options
Diffstat (limited to 'api/src/main/java/io/opencensus/trace/propagation/TextFormat.java')
-rw-r--r-- | api/src/main/java/io/opencensus/trace/propagation/TextFormat.java | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/api/src/main/java/io/opencensus/trace/propagation/TextFormat.java b/api/src/main/java/io/opencensus/trace/propagation/TextFormat.java new file mode 100644 index 00000000..d52e71f1 --- /dev/null +++ b/api/src/main/java/io/opencensus/trace/propagation/TextFormat.java @@ -0,0 +1,204 @@ +/* + * 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.trace.propagation; + +import io.opencensus.common.ExperimentalApi; +import io.opencensus.internal.Utils; +import io.opencensus.trace.SpanContext; +import java.util.Collections; +import java.util.List; +import javax.annotation.Nullable; + +/*>>> +import org.checkerframework.checker.nullness.qual.NonNull; +*/ + +/** + * Injects and extracts {@link SpanContext trace identifiers} as text into carriers that travel + * in-band across process boundaries. Identifiers are often encoded as messaging or RPC request + * headers. + * + * <p>When using http, the carrier of propagated data on both the client (injector) and server + * (extractor) side is usually an http request. Propagation is usually implemented via library- + * specific request interceptors, where the client-side injects span identifiers and the server-side + * extracts them. + * + * <p>Example of usage on the client: + * + * <pre>{@code + * private static final Tracer tracer = Tracing.getTracer(); + * private static final TextFormat textFormat = Tracing.getPropagationComponent().getTextFormat(); + * private static final TextFormat.Setter setter = new TextFormat.Setter<HttpURLConnection>() { + * public void put(HttpURLConnection carrier, String key, String value) { + * carrier.setRequestProperty(field, value); + * } + * } + * + * void makeHttpRequest() { + * Span span = tracer.spanBuilder("Sent.MyRequest").startSpan(); + * try (Scope s = tracer.withSpan(span)) { + * HttpURLConnection connection = + * (HttpURLConnection) new URL("http://myserver").openConnection(); + * textFormat.inject(span.getContext(), connection, httpURLConnectionSetter); + * // Send the request, wait for response and maybe set the status if not ok. + * } + * span.end(); // Can set a status. + * } + * }</pre> + * + * <p>Example of usage on the server: + * + * <pre>{@code + * private static final Tracer tracer = Tracing.getTracer(); + * private static final TextFormat textFormat = Tracing.getPropagationComponent().getTextFormat(); + * private static final TextFormat.Getter<HttpRequest> getter = ...; + * + * void onRequestReceived(HttpRequest request) { + * SpanContext spanContext = textFormat.extract(request, getter); + * Span span = tracer.spanBuilderWithRemoteParent("Recv.MyRequest", spanContext).startSpan(); + * try (Scope s = tracer.withSpan(span)) { + * // Handle request and send response back. + * } + * span.end() + * } + * }</pre> + * + * @since 0.11 + */ +@ExperimentalApi +public abstract class TextFormat { + private static final NoopTextFormat NOOP_TEXT_FORMAT = new NoopTextFormat(); + + /** + * The propagation fields defined. If your carrier is reused, you should delete the fields here + * before calling {@link #inject(SpanContext, Object, Setter)}. + * + * <p>For example, if the carrier is a single-use or immutable request object, you don't need to + * clear fields as they couldn't have been set before. If it is a mutable, retryable object, + * successive calls should clear these fields first. + * + * @since 0.11 + */ + // The use cases of this are: + // * allow pre-allocation of fields, especially in systems like gRPC Metadata + // * allow a single-pass over an iterator (ex OpenTracing has no getter in TextMap) + public abstract List<String> fields(); + + /** + * Injects the span context downstream. For example, as http headers. + * + * @param spanContext possibly not sampled. + * @param carrier holds propagation fields. For example, an outgoing message or http request. + * @param setter invoked for each propagation key to add or remove. + * @since 0.11 + */ + public abstract <C /*>>> extends @NonNull Object*/> void inject( + SpanContext spanContext, C carrier, Setter<C> setter); + + /** + * Class that allows a {@code TextFormat} to set propagated fields into a carrier. + * + * <p>{@code Setter} is stateless and allows to be saved as a constant to avoid runtime + * allocations. + * + * @param <C> carrier of propagation fields, such as an http request + * @since 0.11 + */ + public abstract static class Setter<C> { + + /** + * Replaces a propagated field with the given value. + * + * <p>For example, a setter for an {@link java.net.HttpURLConnection} would be the method + * reference {@link java.net.HttpURLConnection#addRequestProperty(String, String)} + * + * @param carrier holds propagation fields. For example, an outgoing message or http request. + * @param key the key of the field. + * @param value the value of the field. + * @since 0.11 + */ + public abstract void put(C carrier, String key, String value); + } + + /** + * Extracts the span context from upstream. For example, as http headers. + * + * @param carrier holds propagation fields. For example, an outgoing message or http request. + * @param getter invoked for each propagation key to get. + * @throws SpanContextParseException if the input is invalid + * @since 0.11 + */ + public abstract <C /*>>> extends @NonNull Object*/> SpanContext extract( + C carrier, Getter<C> getter) throws SpanContextParseException; + + /** + * Class that allows a {@code TextFormat} to read propagated fields from a carrier. + * + * <p>{@code Getter} is stateless and allows to be saved as a constant to avoid runtime + * allocations. + * + * @param <C> carrier of propagation fields, such as an http request + * @since 0.11 + */ + public abstract static class Getter<C> { + + /** + * Returns the first value of the given propagation {@code key} or returns {@code null}. + * + * @param carrier carrier of propagation fields, such as an http request + * @param key the key of the field. + * @return the first value of the given propagation {@code key} or returns {@code null}. + * @since 0.11 + */ + @Nullable + public abstract String get(C carrier, String key); + } + + /** + * Returns the no-op implementation of the {@code TextFormat}. + * + * @return the no-op implementation of the {@code TextFormat}. + */ + static TextFormat getNoopTextFormat() { + return NOOP_TEXT_FORMAT; + } + + private static final class NoopTextFormat extends TextFormat { + + private NoopTextFormat() {} + + @Override + public List<String> fields() { + return Collections.emptyList(); + } + + @Override + public <C /*>>> extends @NonNull Object*/> void inject( + SpanContext spanContext, C carrier, Setter<C> setter) { + Utils.checkNotNull(spanContext, "spanContext"); + Utils.checkNotNull(carrier, "carrier"); + Utils.checkNotNull(setter, "setter"); + } + + @Override + public <C /*>>> extends @NonNull Object*/> SpanContext extract(C carrier, Getter<C> getter) { + Utils.checkNotNull(carrier, "carrier"); + Utils.checkNotNull(getter, "getter"); + return SpanContext.INVALID; + } + } +} |