93 lines
21 KiB
HTML
93 lines
21 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 activities 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 by sending an RPC request to a server receiving it.</p><p>For example, when a downstream HTTP call is made, its trace context is encoded as request headers and sent along with it, as shown in the following image:</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 use a framework interceptor to automate propagation.
|
|
The next two examples show how that might work for a client and a server.</p><p>The following example shows how client-side propagation might work:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
|
|
|
<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>The following example shows how server-side propagation might work:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
|
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// configure a function that extracts the trace context from a request</span>
|
|
extractor = 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(extractor.extract(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, as shown in the following example:</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>
|
|
Tracing.newBuilder().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 that you are not using.
|
|
For example, you may be in an Amazon Web Services environment but not be reporting data to X-Ray.
|
|
To ensure X-Ray can co-exist correctly, pass-through its tracing header, as shown in the following example:</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="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="images/tip.png"></td><th align="left">Tip</th></tr><tr><td align="left" valign="top"><p>In Spring Cloud Sleuth all elements of the tracing builder <code class="literal">Tracing.newBuilder()</code>
|
|
are defined as beans. So if you want to pass a custom <code class="literal">PropagationFactory</code>, it’s enough
|
|
for you to create a bean of that type and we will set it in the <code class="literal">Tracing</code> bean.</p></td></tr></table></div><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>If they follow a common pattern, you can also prefix fields.
|
|
The following example shows how to propagate <code class="literal">x-vcap-request-id</code> the field as-is but send the <code class="literal">country-code</code> and <code class="literal">user-id</code> fields on the wire as <code class="literal">x-baggage-country-code</code> and <code class="literal">x-baggage-user-id</code>, respectively:</p><pre class="programlisting">Tracing.newBuilder().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">"x-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 the following code 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">"x-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">"x-country-code"</span>);</pre><p>Alternatively, if you have a reference to a trace context, you can use it explicitly, as shown in the following example:</p><pre class="programlisting">ExtraFieldPropagation.set(span.context(), <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"x-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">"x-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>A difference from previous versions of Sleuth is that, with Brave, you must pass the list of baggage keys.
|
|
There are two properties to achieve this.
|
|
With the <code class="literal">spring.sleuth.baggage-keys</code>, you set keys that get prefixed with <code class="literal">baggage-</code> for HTTP calls and <code class="literal">baggage_</code> for messaging.
|
|
You can also use the <code class="literal">spring.sleuth.propagation-keys</code> property to pass a list of prefixed keys that are whitelisted without any prefix.
|
|
Notice that there’s no <code class="literal">x-</code> in front of the header keys.</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 (such as <code class="literal">HttpServerHandler`</code>) but can also be used for custom RPC or messaging code.</p><p><code class="literal">TraceContextOrSamplingFlags</code> is usually used only 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 to create 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 this trace, using the same span ID if supported or creating a child span
|
|
if not. When the span ID is shared, the reported data includes a flag saying so.</p><p>The following image shows 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 forward only 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>The following image shows 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>, you should disable join by setting <code class="literal">Tracing.Builder.supportsJoin(false)</code>.
|
|
Doing so forces 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 creates 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 span IDs were not present.
|
|
* <code class="literal">SamplingFlags</code> if no identifiers were present.</p><p>Some <code class="literal">Propagation</code> implementations carry extra data from the point of extraction (for example, reading incoming headers) to injection (for example, writing outgoing headers).
|
|
For example, it might carry a request ID.
|
|
When implementations have extra data, they handle it as follows:
|
|
* If a <code class="literal">TraceContext</code> were 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> |