98 lines
20 KiB
HTML
98 lines
20 KiB
HTML
<html><head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>5. Propagation</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud-sleuth.html" title="Spring Cloud Sleuth"><link rel="up" href="multi_spring-cloud-sleuth.html" title="Spring Cloud Sleuth"><link rel="prev" href="multi__sampling.html" title="4. Sampling"><link rel="next" href="multi__current_tracing_component.html" title="6. Current Tracing Component"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">5. Propagation</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__sampling.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__current_tracing_component.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_propagation" href="#_propagation"></a>5. Propagation</h1></div></div></div><p>Propagation is needed to ensure activity originating from the same root
|
|
are collected together in the same trace. The most common propagation
|
|
approach is to copy a trace context from a client sending an RPC request
|
|
to a server receiving it.</p><p>For example, when an downstream Http call is made, its trace context is
|
|
sent along with it, encoded as request headers:</p><pre class="screen"> Client Span Server Span
|
|
┌──────────────────┐ ┌──────────────────┐
|
|
│ │ │ │
|
|
│ TraceContext │ Http Request Headers │ TraceContext │
|
|
│ ┌──────────────┐ │ ┌───────────────────┐ │ ┌──────────────┐ │
|
|
│ │ TraceId │ │ │ X─B3─TraceId │ │ │ TraceId │ │
|
|
│ │ │ │ │ │ │ │ │ │
|
|
│ │ ParentSpanId │ │ Extract │ X─B3─ParentSpanId │ Inject │ │ ParentSpanId │ │
|
|
│ │ ├─┼─────────>│ ├────────┼>│ │ │
|
|
│ │ SpanId │ │ │ X─B3─SpanId │ │ │ SpanId │ │
|
|
│ │ │ │ │ │ │ │ │ │
|
|
│ │ Sampled │ │ │ X─B3─Sampled │ │ │ Sampled │ │
|
|
│ └──────────────┘ │ └───────────────────┘ │ └──────────────┘ │
|
|
│ │ │ │
|
|
└──────────────────┘ └──────────────────┘</pre><p>The names above are from <a class="link" href="https://github.com/openzipkin/b3-propagation" target="_top">B3 Propagation</a>,
|
|
which is built-in to Brave and has implementations in many languages and
|
|
frameworks.</p><p>Most users will use a framework interceptor which automates propagation.
|
|
Here’s how they might work internally.</p><p>Here’s what client-side propagation might look like</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// configure a function that injects a trace context into a request</span>
|
|
injector = tracing.propagation().injector(Request.Builder::addHeader);
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// before a request is sent, add the current span's context to it</span>
|
|
injector.inject(span.context(), request);</pre><p>Here’s what server-side propagation might look like</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// configure a function that extracts the trace context from a request</span>
|
|
extracted = tracing.propagation().extractor(Request::getHeader);
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when a server receives a request, it joins or starts a new trace</span>
|
|
span = tracer.nextSpan(extracted, request);</pre><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_propagating_extra_fields" href="#_propagating_extra_fields"></a>5.1 Propagating extra fields</h2></div></div></div><p>Sometimes you need to propagate extra fields, such as a request ID or an alternate trace context.
|
|
For example, if you are in a Cloud Foundry environment, you might want to pass the request ID:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when you initialize the builder, define the extra field you want to propagate</span>
|
|
tracingBuilder.propagationFactory(
|
|
ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-vcap-request-id"</span>)
|
|
);
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// later, you can tag that request ID or use it in log correlation</span>
|
|
requestId = ExtraFieldPropagation.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-vcap-request-id"</span>);</pre><p>You may also need to propagate a trace context you aren’t using. For example, you may be in an
|
|
Amazon Web Services environment, but not reporting data to X-Ray. To ensure X-Ray can co-exist
|
|
correctly, pass-through its tracing header like so.</p><pre class="programlisting">tracingBuilder.propagationFactory(
|
|
ExtraFieldPropagation.newFactory(B3Propagation.FACTORY, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-amzn-trace-id"</span>)
|
|
);</pre><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_prefixed_fields" href="#_prefixed_fields"></a>5.1.1 Prefixed fields</h3></div></div></div><p>You can also prefix fields, if they follow a common pattern. For example, the following will
|
|
propagate the field "x-vcap-request-id" as-is, but send the fields "country-code" and "user-id"
|
|
on the wire as "x-baggage-country-code" and "x-baggage-user-id" respectively.</p><p>Setup your tracing instance with allowed fields:</p><pre class="programlisting">tracingBuilder.propagationFactory(
|
|
ExtraFieldPropagation.newFactoryBuilder(B3Propagation.FACTORY)
|
|
.addField(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-vcap-request-id"</span>)
|
|
.addPrefixedFields(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"baggage-"</span>, Arrays.asList(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"country-code"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"user-id"</span>))
|
|
.build()
|
|
);</pre><p>Later, you can call below to affect the country code of the current trace context</p><pre class="programlisting">ExtraFieldPropagation.set(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"country-code"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FO"</span>);
|
|
String countryCode = ExtraFieldPropagation.get(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"country-code"</span>);</pre><p>Or, if you have a reference to a trace context, use it explicitly</p><pre class="programlisting">ExtraFieldPropagation.set(span.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"country-code"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"FO"</span>);
|
|
String countryCode = ExtraFieldPropagation.get(span.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"country-code"</span>);</pre><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>In comparison to previous versions of Sleuth, with
|
|
Brave it’s required to pass the list of baggage keys.
|
|
There are two properties to achieve this. Via the <code class="literal">spring.sleuth.baggage-keys</code> you set keys
|
|
that will get prefixed with <code class="literal">baggage-</code> for http calls and <code class="literal">baggage_</code> for messaging. You can also pass
|
|
a list of prefixed keys that will be whitelisted without any prefix via
|
|
<code class="literal">spring.sleuth.prefixed-keys</code> property.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_extracting_a_propagated_context" href="#_extracting_a_propagated_context"></a>5.1.2 Extracting a propagated context</h3></div></div></div><p>The <code class="literal">TraceContext.Extractor<C></code> reads trace identifiers and sampling status
|
|
from an incoming request or message. The carrier is usually a request object
|
|
or headers.</p><p>This utility is used in standard instrumentation like [HttpServerHandler](../instrumentation/http/src/main/java/sleuth/http/HttpServerHandler.java),
|
|
but can also be used for custom RPC or messaging code.</p><p><code class="literal">TraceContextOrSamplingFlags</code> is usually only used with <code class="literal">Tracer.nextSpan(extracted)</code>, unless you are
|
|
sharing span IDs between a client and a server.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_sharing_span_ids_between_client_and_server" href="#_sharing_span_ids_between_client_and_server"></a>5.1.3 Sharing span IDs between client and server</h3></div></div></div><p>A normal instrumentation pattern is creating a span representing the server
|
|
side of an RPC. <code class="literal">Extractor.extract</code> might return a complete trace context when
|
|
applied to an incoming client request. <code class="literal">Tracer.joinSpan</code> attempts to continue
|
|
the this trace, using the same span ID if supported, or creating a child span
|
|
if not. When span ID is shared, data reported includes a flag saying so.</p><p>Here’s an example of B3 propagation:</p><pre class="screen"> ┌───────────────────┐ ┌───────────────────┐
|
|
Incoming Headers │ TraceContext │ │ TraceContext │
|
|
┌───────────────────┐(extract)│ ┌───────────────┐ │(join)│ ┌───────────────┐ │
|
|
│ X─B3-TraceId │─────────┼─┼> TraceId │ │──────┼─┼> TraceId │ │
|
|
│ │ │ │ │ │ │ │ │ │
|
|
│ X─B3-ParentSpanId │─────────┼─┼> ParentSpanId │ │──────┼─┼> ParentSpanId │ │
|
|
│ │ │ │ │ │ │ │ │ │
|
|
│ X─B3-SpanId │─────────┼─┼> SpanId │ │──────┼─┼> SpanId │ │
|
|
└───────────────────┘ │ │ │ │ │ │ │ │
|
|
│ │ │ │ │ │ Shared: true │ │
|
|
│ └───────────────┘ │ │ └───────────────┘ │
|
|
└───────────────────┘ └───────────────────┘</pre><p>Some propagation systems only forward the parent span ID, detected when
|
|
<code class="literal">Propagation.Factory.supportsJoin() == false</code>. In this case, a new span ID is
|
|
always provisioned and the incoming context determines the parent ID.</p><p>Here’s an example of AWS propagation:</p><pre class="screen"> ┌───────────────────┐ ┌───────────────────┐
|
|
x-amzn-trace-id │ TraceContext │ │ TraceContext │
|
|
┌───────────────────┐(extract)│ ┌───────────────┐ │(join)│ ┌───────────────┐ │
|
|
│ Root │─────────┼─┼> TraceId │ │──────┼─┼> TraceId │ │
|
|
│ │ │ │ │ │ │ │ │ │
|
|
│ Parent │─────────┼─┼> SpanId │ │──────┼─┼> ParentSpanId │ │
|
|
└───────────────────┘ │ └───────────────┘ │ │ │ │ │
|
|
└───────────────────┘ │ │ SpanId: New │ │
|
|
│ └───────────────┘ │
|
|
└───────────────────┘</pre><p>Note: Some span reporters do not support sharing span IDs. For example, if you
|
|
set <code class="literal">Tracing.Builder.spanReporter(amazonXrayOrGoogleStackdrive)</code>, disable join
|
|
via <code class="literal">Tracing.Builder.supportsJoin(false)</code>. This will force a new child span on
|
|
<code class="literal">Tracer.joinSpan()</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_implementing_propagation" href="#_implementing_propagation"></a>5.1.4 Implementing Propagation</h3></div></div></div><p><code class="literal">TraceContext.Extractor<C></code> is implemented by a <code class="literal">Propagation.Factory</code> plugin. Internally, this code
|
|
will create the union type <code class="literal">TraceContextOrSamplingFlags</code> with one of the following:
|
|
* <code class="literal">TraceContext</code> if trace and span IDs were present.
|
|
* <code class="literal">TraceIdContext</code> if a trace ID was present, but not span IDs.
|
|
* <code class="literal">SamplingFlags</code> if no identifiers were present</p><p>Some <code class="literal">Propagation</code> implementations carry extra data from point of extraction (ex reading incoming
|
|
headers) to injection (ex writing outgoing headers). For example, it might carry a request ID. When
|
|
implementations have extra data, here’s how they handle it.
|
|
* If a <code class="literal">TraceContext</code> was extracted, add the extra data as <code class="literal">TraceContext.extra()</code>
|
|
* Otherwise, add it as <code class="literal">TraceContextOrSamplingFlags.extra()</code>, which <code class="literal">Tracer.nextSpan</code> handles.</p></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi__sampling.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__current_tracing_component.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">4. Sampling </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud-sleuth.html">Home</a></td><td width="40%" align="right" valign="top"> 6. Current Tracing Component</td></tr></table></div></body></html> |