Sync docs from master to gh-pages

This commit is contained in:
buildmaster
2018-09-14 09:13:15 +00:00
parent e57b9a29bb
commit 3010e04bba
4 changed files with 184 additions and 104 deletions

View File

@@ -41,23 +41,32 @@ It also includes libraries to propagate the trace context over network boundarie
Your names have to be explicit and concrete.
Big names lead to latency issues and sometimes even thrown exceptions.</p></td></tr></table></div><p>The tracer creates and joins spans that model the latency of potentially distributed work.
It can employ sampling to reduce overhead during the process, to reduce the amount of data sent to Zipkin, or both.</p><p>Spans returned by a tracer report data to Zipkin when finished or do nothing if unsampled.
After starting a span, you can annotate events of interest or add tags containing details or lookup keys.</p><p>Spans have a context that includes trace identifiers that place the span at the correct spot in the tree representing the distributed operation.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_local_tracing" href="#_local_tracing"></a>3.1.2&nbsp;Local Tracing</h3></div></div></div><p>When tracing local code, you can run it inside a span, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
After starting a span, you can annotate events of interest or add tags containing details or lookup keys.</p><p>Spans have a context that includes trace identifiers that place the span at the correct spot in the tree representing the distributed operation.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_local_tracing" href="#_local_tracing"></a>3.1.2&nbsp;Local Tracing</h3></div></div></div><p>When tracing code that never leaves your process, run it inside a scoped span.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
Span span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Start a new trace or a span within an existing trace representing an operation</span>
ScopedSpan span = tracer.startScopedSpan(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
doSomethingExpensive();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// The span is in "scope" meaning downstream code such as loggers can see trace IDs</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoder.encode();
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
span.error(e); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Unless you handle exceptions, you might not know the operation failed!</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
span.finish();
}</pre><p>In the preceding example, the span is the root of the trace.
In many cases, the span is part of an existing trace.
When this is the case, call <code class="literal">newChild</code> instead of <code class="literal">newTrace</code>, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
span.finish(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// always finish the span</span>
}</pre><p>When you need more features, or finer control, use the <code class="literal">Span</code> type:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
Span span = tracer.newChild(root.context()).name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
doSomethingExpensive();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Start a new trace or a span within an existing trace representing an operation</span>
Span span = tracer.nextSpan().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Put the span in "scope" so that downstream code such as loggers can see trace IDs</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope ws = tracer.withSpanInScope(span)) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoder.encode();
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
span.error(e); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Unless you handle exceptions, you might not know the operation failed!</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
span.finish();
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_customizing_spans" href="#_customizing_spans"></a>3.1.3&nbsp;Customizing Spans</h3></div></div></div><p>Once you have a span, you can add tags to it.
span.finish(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// note the scope is independent of the span. Always finish a span.</span>
}</pre><p>Both of the above examples report the exact same span on finish!</p><p>In the above example, the span will be either a new root span or the
next child in an existing trace.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_customizing_spans" href="#_customizing_spans"></a>3.1.3&nbsp;Customizing Spans</h3></div></div></div><p>Once you have a span, you can add tags to it.
The tags can be used as lookup keys or details.
For example, you might add a tag with your runtime version, as shown in the following example:</p><pre class="programlisting">span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);</pre><p>When exposing the ability to customize spans to third parties, prefer <code class="literal">brave.SpanCustomizer</code> as opposed to <code class="literal">brave.Span</code>.
The former is simpler to understand and test and does not tempt users with span lifecycle hooks.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> MyTraceCallback {
@@ -71,32 +80,36 @@ The former is simpler to understand and test and does not tempt users with span
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> userCode() {
span.annotate(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tx.started"</span>);
...
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>3.1.5&nbsp;RPC tracing</h3></div></div></div><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>Check for <a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation" target="_top">instrumentation written here</a> and <a class="link" href="http://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin&#8217;s list</a> before rolling your own RPC instrumentation.</p></td></tr></table></div><p>RPC tracing is often done automatically by interceptors. Behind the scenes, they add tags and events that relate to their role in an RPC operation.</p><p>The following example shows how to add a client span:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>3.1.5&nbsp;RPC tracing</h3></div></div></div><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>Check for <a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation" target="_top">instrumentation written here</a> and <a class="link" href="http://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin&#8217;s list</a> before rolling your own RPC instrumentation.</p></td></tr></table></div><p>RPC tracing is often done automatically by interceptors. Behind the scenes, they add tags and events that relate to their role in an RPC operation.</p><p>The following example shows how to add a client span:</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">// before you send a request, add metadata that describes the operation</span>
span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"get"</span>).type(CLIENT);
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);
span.tag(TraceKeys.HTTP_PATH, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/api"</span>);
span.remoteEndpoint(Endpoint.builder()
.serviceName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"backend"</span>)
.ipv4(<span class="hl-number">127</span> &lt;&lt; <span class="hl-number">24</span> | <span class="hl-number">1</span>)
.port(<span class="hl-number">8080</span>).build());
span = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myrpc.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"1.0.0"</span>);
span.remoteServiceName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"backend"</span>);
span.remoteIpAndPort(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"172.3.4.1"</span>, <span class="hl-number">8108</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
tracing.propagation().injector(Request::addHeader)
.inject(span.context(), request);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the request is scheduled, start the span</span>
span.start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// if you have callbacks for when data is on the wire, note those events</span>
span.annotate(Constants.WIRE_SEND);
span.annotate(Constants.WIRE_RECV);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// if there is an error, tag the span</span>
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"error"</span>, error.getCode());
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// or if there is an exception</span>
span.error(exception);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the response is complete, finish the span</span>
span.finish();</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_one_way_tracing" href="#_one_way_tracing"></a>One-Way tracing</h4></div></div></div><p>Sometimes, you need to model an asynchronous operation where there is a
request but no response. In normal RPC tracing, you use <code class="literal">span.finish()</code>
to indicate that the response was received. In one-way tracing, you use
<code class="literal">span.flush()</code> instead, as you do not expect a response.</p><p>The following example shows how a client might model a one-way operation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
<code class="literal">span.flush()</code> instead, as you do not expect a response.</p><p>The following example shows how a client might model a one-way operation:</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">// start a new span representing a client request</span>
oneWaySend = tracer.newSpan(parent).kind(Span.Kind.CLIENT);
oneWaySend = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
tracing.propagation().injector(Request::addHeader)

View File

@@ -3,31 +3,44 @@
<title>4.&nbsp;Sampling</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__features.html" title="3.&nbsp;Features"><link rel="next" href="multi__propagation.html" title="5.&nbsp;Propagation"></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">4.&nbsp;Sampling</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__features.html">Prev</a>&nbsp;</td><th width="60%" align="center">&nbsp;</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="multi__propagation.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_sampling" href="#_sampling"></a>4.&nbsp;Sampling</h1></div></div></div><p>Sampling may be employed to reduce the data collected and reported out of process.
When a span is not sampled, it adds no overhead (a noop).</p><p>Sampling is an up-front decision, meaning that the decision to report data is made at the first operation in a trace and that decision is propagated downstream.</p><p>By default, a global sampler applies a single rate to all traced operations.
<code class="literal">Tracer.Builder.sampler</code> controls this setting, and it defaults to tracing every request.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_declarative_sampling" href="#_declarative_sampling"></a>4.1&nbsp;Declarative sampling</h2></div></div></div><p>Some applications need to sample based on the type or annotations of a java method.</p><p>Most users use a framework interceptor to automate this sort of policy.
The following example shows how that might work internally:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
The following example shows how that might work internally:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// derives a sample rate from an annotation on a java method</span>
DeclarativeSampler&lt;Traced&gt; sampler = DeclarativeSampler.create(Traced::sampleRate);
<em><span class="hl-annotation" style="color: gray">@Around("@annotation(traced)")</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Object traceThing(ProceedingJoinPoint pjp, Traced traced) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Throwable {
Span span = tracing.tracer().newTrace(sampler.sample(traced))...
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// When there is no trace in progress, this decides using an annotation</span>
Sampler decideUsingAnnotation = declarativeSampler.toSampler(traced);
Tracer tracer = tracer.withSampler(decideUsingAnnotation);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// This code looks the same as if there was no declarative override</span>
ScopedSpan span = tracer.startScopedSpan(spanName(pjp));
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> pjp.proceed();
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
span.error(e);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
span.finish();
}
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_custom_sampling" href="#_custom_sampling"></a>4.2&nbsp;Custom sampling</h2></div></div></div><p>Depending on what the operation is, you may want to apply different policies.
For example, you might not want to trace requests to static resources such as images, or you might want to trace all requests to a new api.</p><p>Most users use a framework interceptor to automate this sort of policy.
The following example shows how that might work internally:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Sampler fallback;
Span newTrace(Request input) {
SamplingFlags flags = SamplingFlags.NONE;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/experimental"</span>)) {
flags = SamplingFlags.SAMPLED;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/static"</span>)) {
flags = SamplingFlags.NOT_SAMPLED;
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> tracer.newTrace(flags);
Span nextSpan(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Request input) {
Sampler requestBased = Sampler() {
<em><span class="hl-annotation" style="color: gray">@Override</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> isSampled(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">long</span> traceId) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/experimental"</span>)) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/static"</span>)) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> false;
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> fallback.isSampled(traceId);
}
};
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> tracer.withSampler(requestBased).nextSpan();
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_sampling_in_spring_cloud_sleuth" href="#_sampling_in_spring_cloud_sleuth"></a>4.3&nbsp;Sampling in Spring Cloud Sleuth</h2></div></div></div><p>By default Spring Cloud Sleuth sets all spans to non-exportable.
That means that traces appear in logs but not in any remote store.
For testing the default is often enough, and it probably is all you need if you use only the logs (for example, with an ELK aggregator).

View File

@@ -284,23 +284,32 @@ It also includes libraries to propagate the trace context over network boundarie
Your names have to be explicit and concrete.
Big names lead to latency issues and sometimes even thrown exceptions.</p></td></tr></table></div><p>The tracer creates and joins spans that model the latency of potentially distributed work.
It can employ sampling to reduce overhead during the process, to reduce the amount of data sent to Zipkin, or both.</p><p>Spans returned by a tracer report data to Zipkin when finished or do nothing if unsampled.
After starting a span, you can annotate events of interest or add tags containing details or lookup keys.</p><p>Spans have a context that includes trace identifiers that place the span at the correct spot in the tree representing the distributed operation.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_local_tracing" href="#_local_tracing"></a>3.1.2&nbsp;Local Tracing</h3></div></div></div><p>When tracing local code, you can run it inside a span, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
After starting a span, you can annotate events of interest or add tags containing details or lookup keys.</p><p>Spans have a context that includes trace identifiers that place the span at the correct spot in the tree representing the distributed operation.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_local_tracing" href="#_local_tracing"></a>3.1.2&nbsp;Local Tracing</h3></div></div></div><p>When tracing code that never leaves your process, run it inside a scoped span.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
Span span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Start a new trace or a span within an existing trace representing an operation</span>
ScopedSpan span = tracer.startScopedSpan(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
doSomethingExpensive();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// The span is in "scope" meaning downstream code such as loggers can see trace IDs</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoder.encode();
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
span.error(e); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Unless you handle exceptions, you might not know the operation failed!</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
span.finish();
}</pre><p>In the preceding example, the span is the root of the trace.
In many cases, the span is part of an existing trace.
When this is the case, call <code class="literal">newChild</code> instead of <code class="literal">newTrace</code>, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
span.finish(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// always finish the span</span>
}</pre><p>When you need more features, or finer control, use the <code class="literal">Span</code> type:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
Span span = tracer.newChild(root.context()).name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
doSomethingExpensive();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Start a new trace or a span within an existing trace representing an operation</span>
Span span = tracer.nextSpan().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"encode"</span>).start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Put the span in "scope" so that downstream code such as loggers can see trace IDs</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope ws = tracer.withSpanInScope(span)) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoder.encode();
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
span.error(e); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Unless you handle exceptions, you might not know the operation failed!</span>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
span.finish();
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_customizing_spans" href="#_customizing_spans"></a>3.1.3&nbsp;Customizing Spans</h3></div></div></div><p>Once you have a span, you can add tags to it.
span.finish(); <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// note the scope is independent of the span. Always finish a span.</span>
}</pre><p>Both of the above examples report the exact same span on finish!</p><p>In the above example, the span will be either a new root span or the
next child in an existing trace.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_customizing_spans" href="#_customizing_spans"></a>3.1.3&nbsp;Customizing Spans</h3></div></div></div><p>Once you have a span, you can add tags to it.
The tags can be used as lookup keys or details.
For example, you might add a tag with your runtime version, as shown in the following example:</p><pre class="programlisting">span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);</pre><p>When exposing the ability to customize spans to third parties, prefer <code class="literal">brave.SpanCustomizer</code> as opposed to <code class="literal">brave.Span</code>.
The former is simpler to understand and test and does not tempt users with span lifecycle hooks.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">interface</span> MyTraceCallback {
@@ -314,32 +323,36 @@ The former is simpler to understand and test and does not tempt users with span
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> userCode() {
span.annotate(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"tx.started"</span>);
...
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>3.1.5&nbsp;RPC tracing</h3></div></div></div><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>Check for <a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation" target="_top">instrumentation written here</a> and <a class="link" href="http://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin&#8217;s list</a> before rolling your own RPC instrumentation.</p></td></tr></table></div><p>RPC tracing is often done automatically by interceptors. Behind the scenes, they add tags and events that relate to their role in an RPC operation.</p><p>The following example shows how to add a client span:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>3.1.5&nbsp;RPC tracing</h3></div></div></div><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>Check for <a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation" target="_top">instrumentation written here</a> and <a class="link" href="http://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin&#8217;s list</a> before rolling your own RPC instrumentation.</p></td></tr></table></div><p>RPC tracing is often done automatically by interceptors. Behind the scenes, they add tags and events that relate to their role in an RPC operation.</p><p>The following example shows how to add a client span:</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">// before you send a request, add metadata that describes the operation</span>
span = tracer.newTrace().name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"get"</span>).type(CLIENT);
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"clnt/finagle.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"6.36.0"</span>);
span.tag(TraceKeys.HTTP_PATH, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/api"</span>);
span.remoteEndpoint(Endpoint.builder()
.serviceName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"backend"</span>)
.ipv4(<span class="hl-number">127</span> &lt;&lt; <span class="hl-number">24</span> | <span class="hl-number">1</span>)
.port(<span class="hl-number">8080</span>).build());
span = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"myrpc.version"</span>, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"1.0.0"</span>);
span.remoteServiceName(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"backend"</span>);
span.remoteIpAndPort(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"172.3.4.1"</span>, <span class="hl-number">8108</span>);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
tracing.propagation().injector(Request::addHeader)
.inject(span.context(), request);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the request is scheduled, start the span</span>
span.start();
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// if you have callbacks for when data is on the wire, note those events</span>
span.annotate(Constants.WIRE_SEND);
span.annotate(Constants.WIRE_RECV);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// if there is an error, tag the span</span>
span.tag(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"error"</span>, error.getCode());
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// or if there is an exception</span>
span.error(exception);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// when the response is complete, finish the span</span>
span.finish();</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_one_way_tracing" href="#_one_way_tracing"></a>One-Way tracing</h4></div></div></div><p>Sometimes, you need to model an asynchronous operation where there is a
request but no response. In normal RPC tracing, you use <code class="literal">span.finish()</code>
to indicate that the response was received. In one-way tracing, you use
<code class="literal">span.flush()</code> instead, as you do not expect a response.</p><p>The following example shows how a client might model a one-way operation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
<code class="literal">span.flush()</code> instead, as you do not expect a response.</p><p>The following example shows how a client might model a one-way operation:</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">// start a new span representing a client request</span>
oneWaySend = tracer.newSpan(parent).kind(Span.Kind.CLIENT);
oneWaySend = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// Add the trace context to the request, so it can be propagated in-band</span>
tracing.propagation().injector(Request::addHeader)
@@ -369,31 +382,44 @@ oneWayReceive.start().flush();
next = tracer.newSpan(oneWayReceive.context()).name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"step2"</span>).start();</pre></div></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_sampling" href="#_sampling"></a>4.&nbsp;Sampling</h1></div></div></div><p>Sampling may be employed to reduce the data collected and reported out of process.
When a span is not sampled, it adds no overhead (a noop).</p><p>Sampling is an up-front decision, meaning that the decision to report data is made at the first operation in a trace and that decision is propagated downstream.</p><p>By default, a global sampler applies a single rate to all traced operations.
<code class="literal">Tracer.Builder.sampler</code> controls this setting, and it defaults to tracing every request.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_declarative_sampling" href="#_declarative_sampling"></a>4.1&nbsp;Declarative sampling</h2></div></div></div><p>Some applications need to sample based on the type or annotations of a java method.</p><p>Most users use a framework interceptor to automate this sort of policy.
The following example shows how that might work internally:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracing tracing;
The following example shows how that might work internally:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// derives a sample rate from an annotation on a java method</span>
DeclarativeSampler&lt;Traced&gt; sampler = DeclarativeSampler.create(Traced::sampleRate);
<em><span class="hl-annotation" style="color: gray">@Around("@annotation(traced)")</span></em>
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Object traceThing(ProceedingJoinPoint pjp, Traced traced) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Throwable {
Span span = tracing.tracer().newTrace(sampler.sample(traced))...
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// When there is no trace in progress, this decides using an annotation</span>
Sampler decideUsingAnnotation = declarativeSampler.toSampler(traced);
Tracer tracer = tracer.withSampler(decideUsingAnnotation);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// This code looks the same as if there was no declarative override</span>
ScopedSpan span = tracer.startScopedSpan(spanName(pjp));
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> pjp.proceed();
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">catch</span> (RuntimeException | Error e) {
span.error(e);
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throw</span> e;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> {
span.finish();
}
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_custom_sampling" href="#_custom_sampling"></a>4.2&nbsp;Custom sampling</h2></div></div></div><p>Depending on what the operation is, you may want to apply different policies.
For example, you might not want to trace requests to static resources such as images, or you might want to trace all requests to a new api.</p><p>Most users use a framework interceptor to automate this sort of policy.
The following example shows how that might work internally:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Sampler fallback;
Span newTrace(Request input) {
SamplingFlags flags = SamplingFlags.NONE;
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/experimental"</span>)) {
flags = SamplingFlags.SAMPLED;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/static"</span>)) {
flags = SamplingFlags.NOT_SAMPLED;
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> tracer.newTrace(flags);
Span nextSpan(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Request input) {
Sampler requestBased = Sampler() {
<em><span class="hl-annotation" style="color: gray">@Override</span></em> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> isSampled(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">long</span> traceId) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/experimental"</span>)) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> true;
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">else</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">if</span> (input.url().startsWith(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/static"</span>)) {
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> false;
}
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> fallback.isSampled(traceId);
}
};
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> tracer.withSampler(requestBased).nextSpan();
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_sampling_in_spring_cloud_sleuth" href="#_sampling_in_spring_cloud_sleuth"></a>4.3&nbsp;Sampling in Spring Cloud Sleuth</h2></div></div></div><p>By default Spring Cloud Sleuth sets all spans to non-exportable.
That means that traces appear in logs but not in any remote store.
For testing the default is often enough, and it probably is all you need if you use only the logs (for example, with an ELK aggregator).

View File

@@ -757,26 +757,37 @@ After starting a span, you can annotate events of interest or add tags containin
</section>
<section xml:id="_local_tracing">
<title>Local Tracing</title>
<simpara>When tracing local code, you can run it inside a span, as shown in the following example:</simpara>
<simpara>When tracing code that never leaves your process, run it inside a scoped span.</simpara>
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracer tracer;
Span span = tracer.newTrace().name("encode").start();
// Start a new trace or a span within an existing trace representing an operation
ScopedSpan span = tracer.startScopedSpan("encode");
try {
doSomethingExpensive();
// The span is in "scope" meaning downstream code such as loggers can see trace IDs
return encoder.encode();
} catch (RuntimeException | Error e) {
span.error(e); // Unless you handle exceptions, you might not know the operation failed!
throw e;
} finally {
span.finish();
span.finish(); // always finish the span
}</programlisting>
<simpara>In the preceding example, the span is the root of the trace.
In many cases, the span is part of an existing trace.
When this is the case, call <literal>newChild</literal> instead of <literal>newTrace</literal>, as shown in the following example:</simpara>
<simpara>When you need more features, or finer control, use the <literal>Span</literal> type:</simpara>
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracer tracer;
Span span = tracer.newChild(root.context()).name("encode").start();
try {
doSomethingExpensive();
// Start a new trace or a span within an existing trace representing an operation
Span span = tracer.nextSpan().name("encode").start();
// Put the span in "scope" so that downstream code such as loggers can see trace IDs
try (SpanInScope ws = tracer.withSpanInScope(span)) {
return encoder.encode();
} catch (RuntimeException | Error e) {
span.error(e); // Unless you handle exceptions, you might not know the operation failed!
throw e;
} finally {
span.finish();
span.finish(); // note the scope is independent of the span. Always finish a span.
}</programlisting>
<simpara>Both of the above examples report the exact same span on finish!</simpara>
<simpara>In the above example, the span will be either a new root span or the
next child in an existing trace.</simpara>
</section>
<section xml:id="_customizing_spans">
<title>Customizing Spans</title>
@@ -814,23 +825,26 @@ void userCode() {
</tip>
<simpara>RPC tracing is often done automatically by interceptors. Behind the scenes, they add tags and events that relate to their role in an RPC operation.</simpara>
<simpara>The following example shows how to add a client span:</simpara>
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracer tracer;
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracing tracing;
@Autowired Tracer tracer;
// before you send a request, add metadata that describes the operation
span = tracer.newTrace().name("get").type(CLIENT);
span.tag("clnt/finagle.version", "6.36.0");
span.tag(TraceKeys.HTTP_PATH, "/api");
span.remoteEndpoint(Endpoint.builder()
.serviceName("backend")
.ipv4(127 &lt;&lt; 24 | 1)
.port(8080).build());
span = tracer.nextSpan().name(service + "/" + method).kind(CLIENT);
span.tag("myrpc.version", "1.0.0");
span.remoteServiceName("backend");
span.remoteIpAndPort("172.3.4.1", 8108);
// Add the trace context to the request, so it can be propagated in-band
tracing.propagation().injector(Request::addHeader)
.inject(span.context(), request);
// when the request is scheduled, start the span
span.start();
// if you have callbacks for when data is on the wire, note those events
span.annotate(Constants.WIRE_SEND);
span.annotate(Constants.WIRE_RECV);
// if there is an error, tag the span
span.tag("error", error.getCode());
// or if there is an exception
span.error(exception);
// when the response is complete, finish the span
span.finish();</programlisting>
@@ -841,10 +855,11 @@ request but no response. In normal RPC tracing, you use <literal>span.finish()</
to indicate that the response was received. In one-way tracing, you use
<literal>span.flush()</literal> instead, as you do not expect a response.</simpara>
<simpara>The following example shows how a client might model a one-way operation:</simpara>
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracer tracer;
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracing tracing;
@Autowired Tracer tracer;
// start a new span representing a client request
oneWaySend = tracer.newSpan(parent).kind(Span.Kind.CLIENT);
oneWaySend = tracer.nextSpan().name(service + "/" + method).kind(CLIENT);
// Add the trace context to the request, so it can be propagated in-band
tracing.propagation().injector(Request::addHeader)
@@ -890,16 +905,24 @@ When a span is not sampled, it adds no overhead (a noop).</simpara>
<simpara>Some applications need to sample based on the type or annotations of a java method.</simpara>
<simpara>Most users use a framework interceptor to automate this sort of policy.
The following example shows how that might work internally:</simpara>
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracing tracing;
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracer tracer;
// derives a sample rate from an annotation on a java method
DeclarativeSampler&lt;Traced&gt; sampler = DeclarativeSampler.create(Traced::sampleRate);
@Around("@annotation(traced)")
public Object traceThing(ProceedingJoinPoint pjp, Traced traced) throws Throwable {
Span span = tracing.tracer().newTrace(sampler.sample(traced))...
// When there is no trace in progress, this decides using an annotation
Sampler decideUsingAnnotation = declarativeSampler.toSampler(traced);
Tracer tracer = tracer.withSampler(decideUsingAnnotation);
// This code looks the same as if there was no declarative override
ScopedSpan span = tracer.startScopedSpan(spanName(pjp));
try {
return pjp.proceed();
} catch (RuntimeException | Error e) {
span.error(e);
throw e;
} finally {
span.finish();
}
@@ -912,15 +935,20 @@ For example, you might not want to trace requests to static resources such as im
<simpara>Most users use a framework interceptor to automate this sort of policy.
The following example shows how that might work internally:</simpara>
<programlisting language="java" linenumbering="unnumbered">@Autowired Tracer tracer;
@Autowired Sampler fallback;
Span newTrace(Request input) {
SamplingFlags flags = SamplingFlags.NONE;
if (input.url().startsWith("/experimental")) {
flags = SamplingFlags.SAMPLED;
} else if (input.url().startsWith("/static")) {
flags = SamplingFlags.NOT_SAMPLED;
}
return tracer.newTrace(flags);
Span nextSpan(final Request input) {
Sampler requestBased = Sampler() {
@Override public boolean isSampled(long traceId) {
if (input.url().startsWith("/experimental")) {
return true;
} else if (input.url().startsWith("/static")) {
return false;
}
return fallback.isSampled(traceId);
}
};
return tracer.withSampler(requestBased).nextSpan();
}</programlisting>
</section>
<section xml:id="_sampling_in_spring_cloud_sleuth">