Sync docs from 2.1.x to gh-pages
This commit is contained in:
@@ -90,7 +90,7 @@ $(addBlockSwitches);
|
||||
<div id="preamble">
|
||||
<div class="sectionbody">
|
||||
<div class="paragraph">
|
||||
<p>2.1.2.BUILD-SNAPSHOT</p>
|
||||
<p>2.1.3.BUILD-SNAPSHOT</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,13 +6,13 @@ You can use <code class="literal">Tracer.currentSpan()</code> to add custom tags
|
||||
<code class="literal">tracer.currentSpan().context()</code>. To get the current trace id as String
|
||||
you can use the <code class="literal">traceIdString()</code> method like this: <code class="literal">tracer.currentSpan().context().traceIdString()</code>.</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_setting_a_span_in_scope_manually" href="#_setting_a_span_in_scope_manually"></a>7.1 Setting a span in scope manually</h2></div></div></div><p>When writing new instrumentation, it is important to place a span you created in scope as the current span.
|
||||
Not only does doing so let users access it with <code class="literal">Tracer.currentSpan()</code>, but it also allows customizations such as SLF4J MDC to see the current trace IDs.</p><p><code class="literal">Tracer.withSpanInScope(Span)</code> facilitates this and is most conveniently employed by using the try-with-resources idiom.
|
||||
Whenever external code might be invoked (such as proceeding an interceptor or otherwise), place the span in scope, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
Whenever external code might be invoked (such as proceeding an interceptor or otherwise), place the span in scope, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
|
||||
<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> inboundRequest.invoke();
|
||||
} <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">finally</span> { <span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// note the scope is independent of the span</span>
|
||||
span.finish();
|
||||
}</pre><p>In edge cases, you may need to clear the current span temporarily (for example, launching a task that should not be associated with the current request). To do tso, pass null to <code class="literal">withSpanInScope</code>, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> Tracer tracer;
|
||||
}</pre><p>In edge cases, you may need to clear the current span temporarily (for example, launching a task that should not be associated with the current request). To do tso, pass null to <code class="literal">withSpanInScope</code>, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">try</span> (SpanInScope cleared = tracer.withSpanInScope(null)) {
|
||||
startBackgroundThread();
|
||||
|
||||
@@ -10,14 +10,14 @@ register a bean of type <code class="literal">brave.http.HttpSampler</code> and
|
||||
reference the bean names via their static String <code class="literal">NAME</code> fields.</p><p>Check out Brave’s code to see an example of how to make a path-based sampler
|
||||
<a class="link" href="https://github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy" target="_top">https://github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy</a></p><p>If you want to completely rewrite the <code class="literal">HttpTracing</code> bean you can use the <code class="literal">SkipPatternProvider</code>
|
||||
interface to retrieve the URL <code class="literal">Pattern</code> for spans that should be not sampled. Below you can see
|
||||
an example of usage of <code class="literal">SkipPatternProvider</code> inside a server side, <code class="literal">HttpSampler</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
an example of usage of <code class="literal">SkipPatternProvider</code> inside a server side, <code class="literal">HttpSampler</code>.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = ServerSampler.NAME)</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean(name = ServerSampler.NAME)</xslthl:annotation>
|
||||
HttpSampler myHttpSampler(SkipPatternProvider provider) {
|
||||
Pattern pattern = provider.skipPattern();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> HttpSampler() {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <Req> Boolean trySample(HttpAdapter<Req, ?> adapter, Req request) {
|
||||
String url = adapter.path(request);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">boolean</span> shouldSkip = pattern.matcher(url).matches();
|
||||
@@ -29,8 +29,8 @@ an example of usage of <code class="literal">SkipPatternProvider</code> inside a
|
||||
};
|
||||
}
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_tracingfilter" href="#_tracingfilter"></a>12.2 <code class="literal">TracingFilter</code></h2></div></div></div><p>You can also modify the behavior of the <code class="literal">TracingFilter</code>, which is the component that is responsible for processing the input HTTP request and adding tags basing on the HTTP response.
|
||||
You can customize the tags or modify the response headers by registering your own instance of the <code class="literal">TracingFilter</code> bean.</p><p>In the following example, we register the <code class="literal">TracingFilter</code> bean, add the <code class="literal">ZIPKIN-TRACE-ID</code> response header containing the current Span’s trace id, and add a tag with key <code class="literal">custom</code> and a value <code class="literal">tag</code> to the span.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Component</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Order(TraceWebServletAutoConfiguration.TRACING_FILTER_ORDER + 1)</span></em>
|
||||
You can customize the tags or modify the response headers by registering your own instance of the <code class="literal">TracingFilter</code> bean.</p><p>In the following example, we register the <code class="literal">TracingFilter</code> bean, add the <code class="literal">ZIPKIN-TRACE-ID</code> response header containing the current Span’s trace id, and add a tag with key <code class="literal">custom</code> and a value <code class="literal">tag</code> to the span.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Component</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Order(TraceWebServletAutoConfiguration.TRACING_FILTER_ORDER + 1)</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyFilter <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> GenericFilterBean {
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">final</span> Tracer tracer;
|
||||
@@ -39,7 +39,7 @@ You can customize the tags or modify the response headers by registering your ow
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer = tracer;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> doFilter(ServletRequest request, ServletResponse response,
|
||||
FilterChain chain) <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> IOException, ServletException {
|
||||
Span currentSpan = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracer.currentSpan();
|
||||
@@ -61,10 +61,10 @@ There are situations in which you want to explicitly provide a different service
|
||||
To achieve that, you can pass the following property to your application to override that value (the example is for a service named <code class="literal">myService</code>):</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.service.name</span>: myService</pre></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_customization_of_reported_spans" href="#_customization_of_reported_spans"></a>12.4 Customization of Reported Spans</h2></div></div></div><p>Before reporting spans (for example, to Zipkin) you may want to modify that span in some way.
|
||||
You can do so by using the <code class="literal">FinishedSpanHandler</code> interface.</p><p>In Sleuth, we generate spans with a fixed name.
|
||||
Some users want to modify the name depending on values of tags.
|
||||
You can implement the <code class="literal">FinishedSpanHandler</code> interface to alter that name.</p><p>The following example shows how to register two beans that implement <code class="literal">FinishedSpanHandler</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
You can implement the <code class="literal">FinishedSpanHandler</code> interface to alter that name.</p><p>The following example shows how to register two beans that implement <code class="literal">FinishedSpanHandler</code>:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
FinishedSpanHandler handlerOne() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> FinishedSpanHandler() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<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> handle(TraceContext traceContext, MutableSpan span) {
|
||||
span.name(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"foo"</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-comment">// keep this span</span>
|
||||
@@ -72,10 +72,10 @@ FinishedSpanHandler handlerOne() {
|
||||
};
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
FinishedSpanHandler handlerTwo() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> FinishedSpanHandler() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<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> handle(TraceContext traceContext, MutableSpan span) {
|
||||
span.name(span.name() + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">" bar"</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-comment">// keep this span</span>
|
||||
|
||||
@@ -41,7 +41,7 @@ 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 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;
|
||||
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 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"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
|
||||
<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>);
|
||||
@@ -53,7 +53,7 @@ ScopedSpan span = tracer.startScopedSpan(<span xmlns:d="http://docbook.org/ns/do
|
||||
<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(); <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;
|
||||
}</pre><p>When you need more features, or finer control, use the <code class="literal">Span</code> type:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
|
||||
<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();
|
||||
@@ -75,19 +75,19 @@ The former is simpler to understand and test and does not tempt users with span
|
||||
callback.request(request, span);
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_implicitly_looking_up_the_current_span" href="#_implicitly_looking_up_the_current_span"></a>3.1.4 Implicitly Looking up the Current Span</h3></div></div></div><p>Sometimes, you do not know if a trace is in progress or not, and you do not want users to do null checks.
|
||||
<code class="literal">brave.CurrentSpanCustomizer</code> handles this problem by adding data to any span that’s in progress or drops, as shown in the following example:</p><p>Ex.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// The user code can then inject this without a chance of it being null.</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em> SpanCustomizer span;
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> SpanCustomizer 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 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="https://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin’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;
|
||||
}</pre></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_rpc_tracing" href="#_rpc_tracing"></a>3.1.5 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="https://zipkin.io/pages/existing_instrumentations.html" target="_top">Zipkin’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"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracing tracing;
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> 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.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.remoteIpAndPort(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"172.3.4.1"</span>, <xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">8108</xslthl:number>);
|
||||
|
||||
<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)
|
||||
@@ -105,8 +105,8 @@ span.error(exception);
|
||||
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> Tracing tracing;
|
||||
<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"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracing tracing;
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start a new span representing a client request</span>
|
||||
oneWaySend = tracer.nextSpan().name(service + <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"/"</span> + method).kind(CLIENT);
|
||||
@@ -119,8 +119,8 @@ tracing.propagation().injector(Request::addHeader)
|
||||
request.execute();
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// start the client side and flush instead of finish</span>
|
||||
oneWaySend.start().flush();</pre><p>The following example shows how a server might handle 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;
|
||||
oneWaySend.start().flush();</pre><p>The following example shows how a server might handle a one-way operation:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracing tracing;
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// pull the context out of the incoming request</span>
|
||||
extractor = tracing.propagation().extractor(Request::getHeader);
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<title>15. Integrations</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.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__zipkin_stream_span_consumer.html" title="14. Zipkin Stream Span Consumer"><link rel="next" href="multi__running_examples.html" title="16. Running examples"></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">15. Integrations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__zipkin_stream_span_consumer.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__running_examples.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_integrations" href="#_integrations"></a>15. Integrations</h1></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_opentracing" href="#_opentracing"></a>15.1 OpenTracing</h2></div></div></div><p>Spring Cloud Sleuth is compatible with <a class="link" href="https://opentracing.io/" target="_top">OpenTracing</a>.
|
||||
If you have OpenTracing on the classpath, we automatically register the OpenTracing <code class="literal">Tracer</code> bean.
|
||||
If you wish to disable this, set <code class="literal">spring.sleuth.opentracing.enabled</code> to <code class="literal">false</code></p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_runnable_and_callable" href="#_runnable_and_callable"></a>15.2 Runnable and Callable</h2></div></div></div><p>If you wrap your logic in <code class="literal">Runnable</code> or <code class="literal">Callable</code>, you can wrap those classes in their Sleuth representative, as shown in the following example for <code class="literal">Runnable</code>:</p><pre class="programlisting">Runnable runnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Runnable() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// do some work</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"spanNameFromToStringMethod"</span>;
|
||||
}
|
||||
@@ -20,12 +20,12 @@ Runnable traceRunnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// in the thread of `Runnable`</span>
|
||||
Runnable traceRunnableFromTracer = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing.currentTraceContext()
|
||||
.wrap(runnable);</pre><p>The following example shows how to do so for <code class="literal">Callable</code>:</p><pre class="programlisting">Callable<String> callable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Callable<String>() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String call() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"spanNameFromToStringMethod"</span>;
|
||||
}
|
||||
@@ -39,13 +39,13 @@ Callable<String> traceCallableFromTracer = <span xmlns:d="http://docbook.o
|
||||
.wrap(callable);</pre><p>That way, you ensure that a new span is created and closed for each execution.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_hystrix" href="#_hystrix"></a>15.3 Hystrix</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_custom_concurrency_strategy" href="#_custom_concurrency_strategy"></a>15.3.1 Custom Concurrency Strategy</h3></div></div></div><p>We register a custom <a class="link" href="https://github.com/Netflix/Hystrix/wiki/Plugins#concurrencystrategy" target="_top"><code class="literal">HystrixConcurrencyStrategy</code></a> called <code class="literal">TraceCallable</code> that wraps all <code class="literal">Callable</code> instances in their Sleuth representative.
|
||||
The strategy either starts or continues a span, depending on whether tracing was already going on before the Hystrix command was called.
|
||||
To disable the custom Hystrix Concurrency Strategy, set the <code class="literal">spring.sleuth.hystrix.strategy.enabled</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_manual_command_setting" href="#_manual_command_setting"></a>15.3.2 Manual Command setting</h3></div></div></div><p>Assume that you have the following <code class="literal">HystrixCommand</code>:</p><pre class="programlisting">HystrixCommand<String> hystrixCommand = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> HystrixCommand<String>(setter) {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">protected</span> String run() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
};</pre><p>To pass the tracing information, you have to wrap the same logic in the Sleuth version of the <code class="literal">HystrixCommand</code>, which is called
|
||||
<code class="literal">TraceCommand</code>, as shown in the following example:</p><pre class="programlisting">TraceCommand<String> traceCommand = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceCommand<String>(tracer, setter) {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String doRun() <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">throws</span> Exception {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> someLogic();
|
||||
}
|
||||
@@ -88,11 +88,11 @@ Then we instrument it.</p></td></tr></table></div><p>To block the <code class="l
|
||||
To disable creation of the default <code class="literal">TraceAsyncClientHttpRequestFactoryWrapper</code>, set <code class="literal">spring.sleuth.web.async.client.factory.enabled</code>
|
||||
to <code class="literal">false</code>.
|
||||
If you do not want to create <code class="literal">AsyncRestClient</code> at all, set <code class="literal">spring.sleuth.web.async.client.template.enabled</code> to <code class="literal">false</code>.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_multiple_asynchronous_rest_templates" href="#_multiple_asynchronous_rest_templates"></a>Multiple Asynchronous Rest Templates</h4></div></div></div><p>Sometimes you need to use multiple implementations of the Asynchronous Rest Template.
|
||||
In the following snippet, you can see an example of how to set up such a custom <code class="literal">AsyncRestTemplate</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
In the following snippet, you can see an example of how to set up such a custom <code class="literal">AsyncRestTemplate</code>:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@EnableAutoConfiguration</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Config {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(name = "customAsyncRestTemplate")</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean(name = "customAsyncRestTemplate")</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> AsyncRestTemplate traceAsyncRestTemplate() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> AsyncRestTemplate(asyncClientFactory(),
|
||||
clientHttpRequestFactory());
|
||||
@@ -113,7 +113,7 @@ In the following snippet, you can see an example of how to set up such a custom
|
||||
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_webclient" href="#_webclient"></a>15.6.3 <code class="literal">WebClient</code></h3></div></div></div><p>We inject a <code class="literal">ExchangeFilterFunction</code> implementation that creates a span and, through on-success and on-error callbacks, takes care of closing client-side spans.</p><p>To block this feature, set <code class="literal">spring.sleuth.web.client.enabled</code> to <code class="literal">false</code>.</p><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>You have to register <code class="literal">WebClient</code> as a bean so that the tracing instrumentation gets applied.
|
||||
If you create a <code class="literal">WebClient</code> instance with a <code class="literal">new</code> keyword, the instrumentation does NOT work.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_traverson" href="#_traverson"></a>15.6.4 Traverson</h3></div></div></div><p>If you use the <a class="link" href="https://docs.spring.io/spring-hateoas/docs/current/reference/html/#client.traverson" target="_top">Traverson</a> library, you can inject a <code class="literal">RestTemplate</code> as a bean into your Traverson object.
|
||||
Since <code class="literal">RestTemplate</code> is already intercepted, you get full support for tracing in your client. The following pseudo code
|
||||
shows how to do that:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em> RestTemplate restTemplate;
|
||||
shows how to do that:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> RestTemplate restTemplate;
|
||||
|
||||
Traverson traverson = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Traverson(URI.create(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"http://some/address"</span>),
|
||||
MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON_UTF8).setRestOperations(restTemplate);
|
||||
@@ -138,30 +138,30 @@ You can disable this behavior by setting the value of <code class="literal">spri
|
||||
If you use <code class="literal">spring-cloud-sleuth-stream</code> and <code class="literal">spring-cloud-netflix-hystrix-stream</code> together, a span is created for each Hystrix metrics and sent to Zipkin.
|
||||
This behavior may be annoying. That’s why, by default, <code class="literal">spring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_executor_executorservice_and_scheduledexecutorservice" href="#_executor_executorservice_and_scheduledexecutorservice"></a>15.9.3 Executor, ExecutorService, and ScheduledExecutorService</h3></div></div></div><p>We provide <code class="literal">LazyTraceExecutor</code>, <code class="literal">TraceableExecutorService</code>, and <code class="literal">TraceableScheduledExecutorService</code>. Those implementations create spans each time a new task is submitted, invoked, or scheduled.</p><p>The following example shows how to pass tracing information with <code class="literal">TraceableExecutorService</code> when working with <code class="literal">CompletableFuture</code>:</p><pre class="programlisting">CompletableFuture<Long> completableFuture = CompletableFuture.supplyAsync(() -> {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform some logic</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span class="hl-number">1</span>_<span class="hl-number">000</span>_<span class="hl-number">000L</span>;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">1</xslthl:number>_<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">000</xslthl:number>_<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">000L</xslthl:number>;
|
||||
}, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceableExecutorService(beanFactory, executorService,
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// 'calculateTax' explicitly names the span - this param is optional</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</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>Sleuth does not work with <code class="literal">parallelStream()</code> out of the box.
|
||||
If you want to have the tracing information propagated through the stream, you have to use the approach with <code class="literal">supplyAsync(...)</code>, as shown earlier.</p></td></tr></table></div><p>If there are beans that implement the <code class="literal">Executor</code> interface that you would like
|
||||
to exclude from span creation, you can use the <code class="literal">spring.sleuth.async.ignored-beans</code>
|
||||
property where you can provide a list of bean names.</p><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_customization_of_executors" href="#_customization_of_executors"></a>Customization of Executors</h4></div></div></div><p>Sometimes, you need to set up a custom instance of the <code class="literal">AsyncExecutor</code>.
|
||||
The following example shows how to set up such a custom <code class="literal">Executor</code>:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAutoConfiguration</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@EnableAsync</span></em>
|
||||
The following example shows how to set up such a custom <code class="literal">Executor</code>:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@EnableAutoConfiguration</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@EnableAsync</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// add the infrastructure role to ensure that the bean gets auto-proxied</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@Role(BeanDefinition.ROLE_INFRASTRUCTURE)</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Role(BeanDefinition.ROLE_INFRASTRUCTURE)</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> CustomExecutorConfig <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">extends</span> AsyncConfigurerSupport {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation>
|
||||
BeanFactory beanFactory;
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Executor getAsyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ThreadPoolTaskExecutor();
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// CUSTOMIZE HERE</span>
|
||||
executor.setCorePoolSize(<span class="hl-number">7</span>);
|
||||
executor.setMaxPoolSize(<span class="hl-number">42</span>);
|
||||
executor.setQueueCapacity(<span class="hl-number">11</span>);
|
||||
executor.setCorePoolSize(<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">7</xslthl:number>);
|
||||
executor.setMaxPoolSize(<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">42</xslthl:number>);
|
||||
executor.setQueueCapacity(<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">11</xslthl:number>);
|
||||
executor.setThreadNamePrefix(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"MyExecutor-"</span>);
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// DON'T FORGET TO INITIALIZE</span>
|
||||
executor.initialize();
|
||||
|
||||
@@ -53,7 +53,7 @@ An example from Kibana would resemble the following image:</p><div class="inform
|
||||
match => { "message" => "(?m)OUT\s+%{TIMESTAMP_ISO8601:timestamp}\s+%{LOGLEVEL:severity}\s+\[%{DATA:service},%{DATA:trace},%{DATA:span},%{DATA:exportable}\]\s+%{DATA:pid}\s+---\s+\[%{DATA:thread}\]\s+%{DATA:class}\s+:\s+%{GREEDYDATA:rest}" }
|
||||
}
|
||||
}</pre><div class="section"><div class="titlepage"><div><div><h4 class="title"><a name="_json_logback_with_logstash" href="#_json_logback_with_logstash"></a>JSON Logback with Logstash</h4></div></div></div><p>Often, you do not want to store your logs in a text file but in a JSON file that Logstash can immediately pick.
|
||||
To do so, you have to do the following (for readability, we pass the dependencies in the <code class="literal">groupId:artifactId:version</code> notation).</p><p><span class="strong"><strong>Dependencies Setup</strong></span></p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Ensure that Logback is on the classpath (<code class="literal">ch.qos.logback:logback-core</code>).</li><li class="listitem">Add Logstash Logback encode. For example, to use version <code class="literal">4.6</code>, add <code class="literal">net.logstash.logback:logstash-logback-encoder:4.6</code>.</li></ol></div><p><span class="strong"><strong>Logback Setup</strong></span></p><p>Consider the following example of a Logback configuration file (named <a class="link" href="https://github.com/spring-cloud-samples/sleuth-documentation-apps/blob/master/service1/src/main/resources/logback-spring.xml" target="_top">logback-spring.xml</a>).</p><pre class="programlisting"><span class="hl-directive" style="color: maroon"><?xml version="1.0" encoding="UTF-8"?></span>
|
||||
To do so, you have to do the following (for readability, we pass the dependencies in the <code class="literal">groupId:artifactId:version</code> notation).</p><p><span class="strong"><strong>Dependencies Setup</strong></span></p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Ensure that Logback is on the classpath (<code class="literal">ch.qos.logback:logback-core</code>).</li><li class="listitem">Add Logstash Logback encode. For example, to use version <code class="literal">4.6</code>, add <code class="literal">net.logstash.logback:logstash-logback-encoder:4.6</code>.</li></ol></div><p><span class="strong"><strong>Logback Setup</strong></span></p><p>Consider the following example of a Logback configuration file (named <a class="link" href="https://github.com/spring-cloud-samples/sleuth-documentation-apps/blob/master/service1/src/main/resources/logback-spring.xml" target="_top">logback-spring.xml</a>).</p><pre class="programlisting"><xslthl:directive xmlns:xslthl="http://xslthl.sourceforge.net/"><?xml version="1.0" encoding="UTF-8"?></xslthl:directive>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><configuration></span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><include</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">resource</span>=<span xmlns:d="http://docbook.org/ns/docbook" class="hl-value">"org/springframework/boot/logging/logback/defaults.xml"</span><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag">/></span>
|
||||
​
|
||||
@@ -244,15 +244,15 @@ dependencies {
|
||||
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO6-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>We recommend that you add the dependency management through the Spring BOM so that you need not manage versions yourself.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO6-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the dependency to <code class="literal">spring-cloud-starter-zipkin</code>. That way, all nested dependencies get downloaded.</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO6-3"><span><img src="images/callouts/3.png" alt="3" border="0"></span></a> </p></td><td valign="top" align="left"><p>To automatically configure RabbitMQ, add the <code class="literal">spring-rabbit</code> dependency.</p></td></tr></table></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_overriding_the_auto_configuration_of_zipkin" href="#_overriding_the_auto_configuration_of_zipkin"></a>1.4 Overriding the auto-configuration of Zipkin</h2></div></div></div><p>Spring Cloud Sleuth supports sending traces to multiple tracing systems as of version 2.1.0.
|
||||
In order to get this to work, every tracing system needs to have a <code class="literal">Reporter<Span></code> and <code class="literal">Sender</code>.
|
||||
If you want to override the provided beans you need to give them a specific name.
|
||||
To do this you can use respectively <code class="literal">ZipkinAutoConfiguration.REPORTER_BEAN_NAME</code> and <code class="literal">ZipkinAutoConfiguration.SENDER_BEAN_NAME</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
To do this you can use respectively <code class="literal">ZipkinAutoConfiguration.REPORTER_BEAN_NAME</code> and <code class="literal">ZipkinAutoConfiguration.SENDER_BEAN_NAME</code>.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">protected</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfig {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(ZipkinAutoConfiguration.REPORTER_BEAN_NAME)</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean(ZipkinAutoConfiguration.REPORTER_BEAN_NAME)</xslthl:annotation>
|
||||
Reporter<zipkin2.Span> myReporter() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> AsyncReporter.create(mySender());
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean(ZipkinAutoConfiguration.SENDER_BEAN_NAME)</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean(ZipkinAutoConfiguration.SENDER_BEAN_NAME)</xslthl:annotation>
|
||||
MySender mySender() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> MySender();
|
||||
}
|
||||
@@ -265,22 +265,22 @@ To do this you can use respectively <code class="literal">ZipkinAutoConfiguratio
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.spanSent;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Encoding encoding() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Encoding.JSON;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> messageMaxBytes() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">int</span> messageSizeInBytes(List<<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">byte</span>[]> encodedSpans) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> encoding().listSizeInBytes(encodedSpans);
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Call<Void> sendSpans(List<<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">byte</span>[]> encodedSpans) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.spanSent = true;
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Call.create(null);
|
||||
|
||||
@@ -5,23 +5,23 @@ Doing so lets Sleuth change its core API to create less impact to user code.</li
|
||||
By only exposing scope, tag, and log functionality, you can collaborate without accidentally breaking span lifecycle.</li><li class="listitem">Collaboration with runtime generated code. With libraries such as Spring Data and Feign, the implementations of interfaces are generated at runtime.
|
||||
Consequently, span wrapping of objects was tedious.
|
||||
Now you can provide annotations over interfaces and the arguments of those interfaces.</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_creating_new_spans" href="#_creating_new_spans"></a>11.2 Creating New Spans</h2></div></div></div><p>If you do not want to create local spans manually, you can use the <code class="literal">@NewSpan</code> annotation.
|
||||
Also, we provide the <code class="literal">@SpanTag</code> annotation to add tags in an automated fashion.</p><p>Now we can consider some examples of usage.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod();</pre><p>Annotating the method without any parameter leads to creating a new span whose name equals the annotated method name.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan("customNameOnTestMethod4")</span></em>
|
||||
Also, we provide the <code class="literal">@SpanTag</code> annotation to add tags in an automated fashion.</p><p>Now we can consider some examples of usage.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod();</pre><p>Annotating the method without any parameter leads to creating a new span whose name equals the annotated method name.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan("customNameOnTestMethod4")</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod4();</pre><p>If you provide the value in the annotation (either directly or by setting the <code class="literal">name</code> parameter), the created span has the provided value as the name.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// method declaration</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@NewSpan(name = "customNameOnTestMethod5")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod5(<em><span class="hl-annotation" style="color: gray">@SpanTag("testTag")</span></em> String param);
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan(name = "customNameOnTestMethod5")</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod5(<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@SpanTag("testTag")</xslthl:annotation> String param);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// and method execution</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.testBean.testMethod5(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"test"</span>);</pre><p>You can combine both the name and a tag. Let’s focus on the latter.
|
||||
In this case, the value of the annotated method’s parameter runtime value becomes the value of the tag.
|
||||
In our sample, the tag key is <code class="literal">testTag</code>, and the tag value is <code class="literal">test</code>.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan(name = "customNameOnTestMethod3")</span></em>
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
In our sample, the tag key is <code class="literal">testTag</code>, and the tag value is <code class="literal">test</code>.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan(name = "customNameOnTestMethod3")</xslthl:annotation>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod3() {
|
||||
}</pre><p>You can place the <code class="literal">@NewSpan</code> annotation on both the class and an interface.
|
||||
If you override the interface’s method and provide a different value for the <code class="literal">@NewSpan</code> annotation, the most
|
||||
concrete one wins (in this case <code class="literal">customNameOnTestMethod3</code> is set).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_continuing_spans" href="#_continuing_spans"></a>11.3 Continuing Spans</h2></div></div></div><p>If you want to add tags and annotations to an existing span, you can use the <code class="literal">@ContinueSpan</code> annotation, as shown in the following example:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// method declaration</span>
|
||||
<em><span class="hl-annotation" style="color: gray">@ContinueSpan(log = "testMethod11")</span></em>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod11(<em><span class="hl-annotation" style="color: gray">@SpanTag("testTag11")</span></em> String param);
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@ContinueSpan(log = "testMethod11")</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> testMethod11(<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@SpanTag("testTag11")</xslthl:annotation> String param);
|
||||
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// method execution</span>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.testBean.testMethod11(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"test"</span>);
|
||||
@@ -30,16 +30,16 @@ The precedence is as follows:</p><div class="orderedlist"><ol class="orderedlist
|
||||
We search for a <code class="literal">TagValueExpressionResolver</code> bean.
|
||||
The default implementation uses SPEL expression resolution.
|
||||
<span class="strong"><strong>IMPORTANT</strong></span> You can only reference properties from the SPEL expression. Method execution is not allowed due to security constraints.</li><li class="listitem">If we do not find any expression to evaluate, return the <code class="literal">toString()</code> value of the parameter.</li></ol></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_custom_extractor" href="#_custom_extractor"></a>11.4.1 Custom extractor</h3></div></div></div><p>The value of the tag for the following method is computed by an implementation of <code class="literal">TagValueResolver</code> interface.
|
||||
Its class name has to be passed as the value of the <code class="literal">resolver</code> attribute.</p><p>Consider the following annotated method:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
Its class name has to be passed as the value of the <code class="literal">resolver</code> attribute.</p><p>Consider the following annotated method:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> getAnnotationForTagValueResolver(
|
||||
<em><span class="hl-annotation" style="color: gray">@SpanTag(key = "test", resolver = TagValueResolver.class)</span></em> String test) {
|
||||
}</pre><p>Now further consider the following <code class="literal">TagValueResolver</code> bean implementation:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean(name = "myCustomTagValueResolver")</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@SpanTag(key = "test", resolver = TagValueResolver.class)</xslthl:annotation> String test) {
|
||||
}</pre><p>Now further consider the following <code class="literal">TagValueResolver</code> bean implementation:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean(name = "myCustomTagValueResolver")</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> TagValueResolver tagValueResolver() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> parameter -> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Value from myCustomTagValueResolver"</span>;
|
||||
}</pre><p>The two preceding examples lead to setting a tag value equal to <code class="literal">Value from myCustomTagValueResolver</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_resolving_expressions_for_a_value" href="#_resolving_expressions_for_a_value"></a>11.4.2 Resolving Expressions for a Value</h3></div></div></div><p>Consider the following annotated method:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</span></em>
|
||||
}</pre><p>The two preceding examples lead to setting a tag value equal to <code class="literal">Value from myCustomTagValueResolver</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_resolving_expressions_for_a_value" href="#_resolving_expressions_for_a_value"></a>11.4.2 Resolving Expressions for a Value</h3></div></div></div><p>Consider the following annotated method:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> getAnnotationForTagValueExpression(
|
||||
<em><span class="hl-annotation" style="color: gray">@SpanTag(key = "test", expression = "'hello' + ' characters'")</span></em> String test) {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@SpanTag(key = "test", expression = "'hello' + ' characters'")</xslthl:annotation> String test) {
|
||||
}</pre><p>No custom implementation of a <code class="literal">TagValueExpressionResolver</code> leads to evaluation of the SPEL expression, and a tag with a value of <code class="literal">4 characters</code> is set on the span.
|
||||
If you want to use some other expression resolution mechanism, you can create your own implementation of the bean.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_the_tostring_method" href="#_using_the_tostring_method"></a>11.4.3 Using the <code class="literal">toString()</code> method</h3></div></div></div><p>Consider the following annotated method:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@NewSpan</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">void</span> getAnnotationForArgumentToString(<em><span class="hl-annotation" style="color: gray">@SpanTag("test")</span></em> Long param) {
|
||||
If you want to use some other expression resolution mechanism, you can create your own implementation of the bean.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_the_tostring_method" href="#_using_the_tostring_method"></a>11.4.3 Using the <code class="literal">toString()</code> method</h3></div></div></div><p>Consider the following annotated method:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@NewSpan</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> getAnnotationForArgumentToString(<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@SpanTag("test")</xslthl:annotation> Long param) {
|
||||
}</pre><p>Running the preceding method with a value of <code class="literal">15</code> leads to setting a tag with a String value of <code class="literal">"15"</code>.</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__naming_spans.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__customizations.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">10. Naming spans </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"> 12. Customizations</td></tr></table></div></body></html>
|
||||
@@ -1,10 +1,10 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>10. Naming spans</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.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__span_lifecycle.html" title="9. Span lifecycle"><link rel="next" href="multi__managing_spans_with_annotations.html" title="11. Managing Spans with Annotations"></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">10. Naming spans</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__span_lifecycle.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__managing_spans_with_annotations.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_naming_spans" href="#_naming_spans"></a>10. Naming spans</h1></div></div></div><p>Picking a span name is not a trivial task. A span name should depict an operation name.
|
||||
The name should be low cardinality, so it should not include identifiers.</p><p>Since there is a lot of instrumentation going on, some span names are artificial:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">controller-method-name</code> when received by a Controller with a method name of <code class="literal">controllerMethodName</code></li><li class="listitem"><code class="literal">async</code> for asynchronous operations done with wrapped <code class="literal">Callable</code> and <code class="literal">Runnable</code> interfaces.</li><li class="listitem">Methods annotated with <code class="literal">@Scheduled</code> return the simple name of the class.</li></ul></div><p>Fortunately, for asynchronous processing, you can provide explicit naming.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spanname_annotation" href="#_spanname_annotation"></a>10.1 <code class="literal">@SpanName</code> Annotation</h2></div></div></div><p>You can name the span explicitly by using the <code class="literal">@SpanName</code> annotation, as shown in the following example:</p><pre class="programlisting"> <em><span class="hl-annotation" style="color: gray">@SpanName("calculateTax")</span></em>
|
||||
The name should be low cardinality, so it should not include identifiers.</p><p>Since there is a lot of instrumentation going on, some span names are artificial:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">controller-method-name</code> when received by a Controller with a method name of <code class="literal">controllerMethodName</code></li><li class="listitem"><code class="literal">async</code> for asynchronous operations done with wrapped <code class="literal">Callable</code> and <code class="literal">Runnable</code> interfaces.</li><li class="listitem">Methods annotated with <code class="literal">@Scheduled</code> return the simple name of the class.</li></ul></div><p>Fortunately, for asynchronous processing, you can provide explicit naming.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_spanname_annotation" href="#_spanname_annotation"></a>10.1 <code class="literal">@SpanName</code> Annotation</h2></div></div></div><p>You can name the span explicitly by using the <code class="literal">@SpanName</code> annotation, as shown in the following example:</p><pre class="programlisting"> <xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@SpanName("calculateTax")</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> TaxCountingRunnable <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">implements</span> Runnable {
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform logic</span>
|
||||
}
|
||||
@@ -19,12 +19,12 @@ future.get();</pre></div><div class="section"><div class="titlepage"><div><div><
|
||||
Typically, one creates an anonymous instance of those classes.
|
||||
You cannot annotate such classes.
|
||||
To overcome that limitation, if there is no <code class="literal">@SpanName</code> annotation present, we check whether the class has a custom implementation of the <code class="literal">toString()</code> method.</p><p>Running such code leads to creating a span named <code class="literal">calculateTax</code>, as shown in the following example:</p><pre class="programlisting">Runnable runnable = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> TraceRunnable(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">this</span>.tracing, spanNamer, <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> Runnable() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> run() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// perform logic</span>
|
||||
}
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String toString() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"calculateTax"</span>;
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@ The most common propagation approach is to copy a trace context from a client by
|
||||
│ └──────────────┘ │ └───────────────────┘ │ └──────────────┘ │
|
||||
│ │ │ │
|
||||
└──────────────────┘ └──────────────────┘</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;
|
||||
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"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> 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;
|
||||
injector.inject(span.context(), request);</pre><p>The following example shows how server-side propagation might work:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracing tracing;
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> 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);
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<title>4. Sampling</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.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. Features"><link rel="next" href="multi__propagation.html" title="5. 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. Sampling</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__features.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <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. 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 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> Tracer tracer;
|
||||
The following example shows how that might work internally:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> 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<Traced> sampler = DeclarativeSampler.create(Traced::sampleRate);
|
||||
|
||||
<em><span class="hl-annotation" style="color: gray">@Around("@annotation(traced)")</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Around("@annotation(traced)")</xslthl:annotation>
|
||||
<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 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);
|
||||
@@ -26,12 +26,12 @@ DeclarativeSampler<Traced> sampler = DeclarativeSampler.create(Traced::sam
|
||||
}
|
||||
}</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 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;
|
||||
The following example shows how that might work internally:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Tracer tracer;
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Autowired</xslthl:annotation> Sampler fallback;
|
||||
|
||||
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) {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation> <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>)) {
|
||||
@@ -46,7 +46,7 @@ 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).
|
||||
If you export span data to Zipkin, there is also an <code class="literal">Sampler.ALWAYS_SAMPLE</code> setting that exports everything and a <code class="literal">ProbabilityBasedSampler</code> setting that samples a fixed fraction of spans.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>The <code class="literal">ProbabilityBasedSampler</code> is the default if you use <code class="literal">spring-cloud-sleuth-zipkin</code>.
|
||||
You can configure the exports by setting <code class="literal">spring.sleuth.sampler.probability</code>.
|
||||
The passed value needs to be a double from <code class="literal">0.0</code> to <code class="literal">1.0</code>.</p></td></tr></table></div><p>A sampler can be installed by creating a bean definition, as shown in the following example:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Bean</span></em>
|
||||
The passed value needs to be a double from <code class="literal">0.0</code> to <code class="literal">1.0</code>.</p></td></tr></table></div><p>A sampler can be installed by creating a bean definition, as shown in the following example:</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> Sampler defaultSampler() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> Sampler.ALWAYS_SAMPLE;
|
||||
}</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>You can set the HTTP header <code class="literal">X-B3-Flags</code> to <code class="literal">1</code>, or, when doing messaging, you can set the <code class="literal">spanFlags</code> header to <code class="literal">1</code>.
|
||||
|
||||
@@ -2,25 +2,25 @@
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title>13. Sending Spans to Zipkin</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.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__customizations.html" title="12. Customizations"><link rel="next" href="multi__zipkin_stream_span_consumer.html" title="14. Zipkin Stream Span Consumer"></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">13. Sending Spans to Zipkin</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi__customizations.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__zipkin_stream_span_consumer.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_sending_spans_to_zipkin" href="#_sending_spans_to_zipkin"></a>13. Sending Spans to Zipkin</h1></div></div></div><p>By default, if you add <code class="literal">spring-cloud-starter-zipkin</code> as a dependency to your project, when the span is closed, it is sent to Zipkin over HTTP.
|
||||
The communication is asynchronous.
|
||||
You can configure the URL by setting the <code class="literal">spring.zipkin.baseUrl</code> property, as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.baseUrl</span>: https://<span class="hl-number">192.168</span>.<span class="hl-number">99.100</span>:<span class="hl-number">9411</span>/</pre><p>If you want to find Zipkin through service discovery, you can pass the Zipkin’s service ID inside the URL, as shown in the following example for <code class="literal">zipkinserver</code> service ID:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.baseUrl</span>: http://zipkinserver/</pre><p>To disable this feature just set <code class="literal">spring.zipkin.discoveryClientEnabled</code> to `false.</p><p>When the Discovery Client feature is enabled, Sleuth uses
|
||||
You can configure the URL by setting the <code class="literal">spring.zipkin.baseUrl</code> property, as follows:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.baseUrl</span>: https://<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">192.168</xslthl:number>.<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">99.100</xslthl:number>:<xslthl:number xmlns:xslthl="http://xslthl.sourceforge.net/">9411</xslthl:number>/</pre><p>If you want to find Zipkin through service discovery, you can pass the Zipkin’s service ID inside the URL, as shown in the following example for <code class="literal">zipkinserver</code> service ID:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.baseUrl</span>: http://zipkinserver/</pre><p>To disable this feature just set <code class="literal">spring.zipkin.discoveryClientEnabled</code> to `false.</p><p>When the Discovery Client feature is enabled, Sleuth uses
|
||||
<code class="literal">LoadBalancerClient</code> to find the URL of the Zipkin Server. It means
|
||||
that you can set up the load balancing configuration e.g. via Ribbon.</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">zipkinserver</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> ribbon</span>:
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> ListOfServers</span>: host1,host2</pre><p>If you have web, rabbit, or kafka together on the classpath, you might need to pick the means by which you would like to send spans to zipkin.
|
||||
To do so, set <code class="literal">web</code>, <code class="literal">rabbit</code>, or <code class="literal">kafka</code> to the <code class="literal">spring.zipkin.sender.type</code> property.
|
||||
The following example shows setting the sender type for <code class="literal">web</code>:</p><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring.zipkin.sender.type</span>: web</pre><p>To customize the <code class="literal">RestTemplate</code> that sends spans to Zipkin via HTTP, you can register
|
||||
the <code class="literal">ZipkinRestTemplateCustomizer</code> bean.</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Configuration</span></em>
|
||||
the <code class="literal">ZipkinRestTemplateCustomizer</code> bean.</p><pre class="programlisting"><xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Configuration</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyConfig {
|
||||
<em><span class="hl-annotation" style="color: gray">@Bean</span></em> ZipkinRestTemplateCustomizer myCustomizer() {
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation> ZipkinRestTemplateCustomizer myCustomizer() {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> ZipkinRestTemplateCustomizer() {
|
||||
<em><span class="hl-annotation" style="color: gray">@Override</span></em>
|
||||
<xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Override</xslthl:annotation>
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> customize(RestTemplate restTemplate) {
|
||||
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment">// customize the RestTemplate</span>
|
||||
}
|
||||
};
|
||||
}
|
||||
}</pre><p>If, however, you would like to control the full process of creating the <code class="literal">RestTemplate</code>
|
||||
object, you will have to create a bean of <code class="literal">zipkin2.reporter.Sender</code> type.</p><pre class="programlisting"> <em><span class="hl-annotation" style="color: gray">@Bean</span></em> Sender myRestTemplateSender(ZipkinProperties zipkin,
|
||||
object, you will have to create a bean of <code class="literal">zipkin2.reporter.Sender</code> type.</p><pre class="programlisting"> <xslthl:annotation xmlns:xslthl="http://xslthl.sourceforge.net/">@Bean</xslthl:annotation> Sender myRestTemplateSender(ZipkinProperties zipkin,
|
||||
ZipkinRestTemplateCustomizer zipkinRestTemplateCustomizer) {
|
||||
RestTemplate restTemplate = mySuperCustomRestTemplate();
|
||||
zipkinRestTemplateCustomizer.customize(restTemplate);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<html><head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
||||
<title></title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.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_spring-cloud-sleuth.html" title="Spring Cloud Sleuth"><link rel="next" href="multi__introduction.html" title="1. Introduction"></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"></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-sleuth.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__introduction.html">Next</a></td></tr></table><hr></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a name="d0e17" href="#d0e17"></a></h1></div></div></div><p><span class="strong"><strong>2.1.2.BUILD-SNAPSHOT</strong></span></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-sleuth.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__introduction.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Spring Cloud Sleuth </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"> 1. Introduction</td></tr></table></div></body></html>
|
||||
<title></title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.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_spring-cloud-sleuth.html" title="Spring Cloud Sleuth"><link rel="next" href="multi__introduction.html" title="1. Introduction"></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"></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-sleuth.html">Prev</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="multi__introduction.html">Next</a></td></tr></table><hr></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a name="d0e17" href="#d0e17"></a></h1></div></div></div><p><span class="strong"><strong>2.1.3.BUILD-SNAPSHOT</strong></span></p></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-sleuth.html">Prev</a> </td><td width="20%" align="center"> </td><td width="40%" align="right"> <a accesskey="n" href="multi__introduction.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Spring Cloud Sleuth </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"> 1. Introduction</td></tr></table></div></body></html>
|
||||
File diff suppressed because one or more lines are too long
@@ -4,7 +4,7 @@
|
||||
<book xmlns="http://docbook.org/ns/docbook" xmlns:xl="http://www.w3.org/1999/xlink" version="5.0" xml:lang="en">
|
||||
<info>
|
||||
<title>Spring Cloud Sleuth</title>
|
||||
<date>2019-06-06</date>
|
||||
<date>2019-06-28</date>
|
||||
<author>
|
||||
<personname>
|
||||
<firstname>Adrian Cole, Spencer Gibb, Marcin Grzejszczak, Dave Syer, Jay Bryant</firstname>
|
||||
@@ -14,7 +14,7 @@
|
||||
</info>
|
||||
<preface>
|
||||
<title></title>
|
||||
<simpara><emphasis role="strong">2.1.2.BUILD-SNAPSHOT</emphasis></simpara>
|
||||
<simpara><emphasis role="strong">2.1.3.BUILD-SNAPSHOT</emphasis></simpara>
|
||||
</preface>
|
||||
<chapter xml:id="_introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
Reference in New Issue
Block a user