Merge branch 'master' into 2.0.x
This commit is contained in:
@@ -29,6 +29,8 @@ public class SleuthProperties {
|
||||
private boolean enabled = true;
|
||||
/** When true, generate 128-bit trace IDs instead of 64-bit ones. */
|
||||
private boolean traceId128 = false;
|
||||
/** When true, your tracing system allows sharing a span ID between a client and server span */
|
||||
private boolean supportsJoin = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
@@ -45,4 +47,12 @@ public class SleuthProperties {
|
||||
public void setTraceId128(boolean traceId128) {
|
||||
this.traceId128 = traceId128;
|
||||
}
|
||||
|
||||
public boolean isSupportsJoin() {
|
||||
return this.supportsJoin;
|
||||
}
|
||||
|
||||
public void setSupportsJoin(boolean supportsJoin) {
|
||||
this.supportsJoin = supportsJoin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanReporter;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.sampler.NeverSampler;
|
||||
import org.springframework.core.Ordered;
|
||||
@@ -97,6 +98,7 @@ public class TraceFilter extends GenericFilterBean {
|
||||
private Tracer tracer;
|
||||
private TraceKeys traceKeys;
|
||||
private final Pattern skipPattern;
|
||||
private final boolean supportsJoin;
|
||||
private SpanReporter spanReporter;
|
||||
private HttpSpanExtractor spanExtractor;
|
||||
private HttpTraceKeysInjector httpTraceKeysInjector;
|
||||
@@ -111,6 +113,7 @@ public class TraceFilter extends GenericFilterBean {
|
||||
|
||||
public TraceFilter(BeanFactory beanFactory, Pattern skipPattern) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.supportsJoin = beanFactory.getBean(SleuthProperties.class).isSupportsJoin();
|
||||
this.skipPattern = skipPattern;
|
||||
}
|
||||
|
||||
@@ -344,10 +347,14 @@ public class TraceFilter extends GenericFilterBean {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a parent span " + parent + " in the request");
|
||||
}
|
||||
addRequestTagsForParentSpan(request, parent);
|
||||
spanFromRequest = parent;
|
||||
if (!this.supportsJoin) { // create a child span for this side of the RPC
|
||||
spanFromRequest = tracer().createSpan(parent.getName(), parent);
|
||||
} else {
|
||||
spanFromRequest = parent;
|
||||
}
|
||||
addRequestTagsForParentSpan(request, spanFromRequest);
|
||||
tracer().continueSpan(spanFromRequest);
|
||||
if (parent.isRemote()) {
|
||||
if (parent.isRemote()) { // then we are in a server span
|
||||
parent.logEvent(Span.SERVER_RECV);
|
||||
}
|
||||
request.setAttribute(TRACE_REQUEST_ATTR, spanFromRequest);
|
||||
|
||||
@@ -98,7 +98,7 @@ public class DefaultTracer implements Tracer {
|
||||
else {
|
||||
long id = createId();
|
||||
span = Span.builder().name(shortenedName)
|
||||
.traceIdHigh(this.traceId128 ? createId() : 0L)
|
||||
.traceIdHigh(this.traceId128 ? createTraceIdHigh() : 0L)
|
||||
.traceId(id)
|
||||
.spanId(id).build();
|
||||
if (sampler == null) {
|
||||
@@ -171,7 +171,7 @@ public class DefaultTracer implements Tracer {
|
||||
long id = createId();
|
||||
if (parent == null) {
|
||||
Span span = Span.builder().name(shortenedName)
|
||||
.traceIdHigh(this.traceId128 ? createId() : 0L)
|
||||
.traceIdHigh(this.traceId128 ? createTraceIdHigh() : 0L)
|
||||
.traceId(id)
|
||||
.spanId(id).build();
|
||||
span = sampledSpan(span, this.defaultSampler);
|
||||
@@ -208,6 +208,21 @@ public class DefaultTracer implements Tracer {
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes a timestamp into the upper 32-bits, so that it can be converted to an Amazon trace ID.
|
||||
*
|
||||
* <p>For example, an Amazon trace ID is composed of the following: {@code |-- 32 bits for epoch
|
||||
* seconds -- | -- 96 bits for random data -- |}
|
||||
*
|
||||
* <p>To support this, {@link Span#getTraceIdHigh() traceIdHigh} holds the epoch seconds and first
|
||||
* 32 random bits: and {@link Span#getTraceId()} traceId} holds the remaining 64 random bits.
|
||||
*/
|
||||
private long createTraceIdHigh() {
|
||||
long epochSeconds = System.currentTimeMillis() / 1000;
|
||||
int random = this.random.nextInt();
|
||||
return (epochSeconds & 0xffffffffL) << 32 | (random & 0xffffffffL);
|
||||
}
|
||||
|
||||
private long createId() {
|
||||
return this.random.nextLong();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanReporter;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.DefaultTestAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.common.AbstractMvcIntegrationTest;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
@@ -71,6 +72,7 @@ public class TraceFilterAlwaysSamplerIntegrationTests extends AbstractMvcIntegra
|
||||
BeanFactory beanFactory = Mockito.mock(BeanFactory.class);
|
||||
BDDMockito.given(beanFactory.getBean(SkipPatternProvider.class))
|
||||
.willThrow(new NoSuchBeanDefinitionException("foo"));
|
||||
BDDMockito.given(beanFactory.getBean(SleuthProperties.class)).willReturn(this.properties);
|
||||
BDDMockito.given(beanFactory.getBean(Tracer.class)).willReturn(this.tracer);
|
||||
BDDMockito.given(beanFactory.getBean(TraceKeys.class)).willReturn(this.traceKeys);
|
||||
BDDMockito.given(beanFactory.getBean(HttpSpanExtractor.class)).willReturn(this.spanExtractor);
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanReporter;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
|
||||
import org.springframework.cloud.sleuth.log.NoOpSpanLogger;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTracer;
|
||||
@@ -54,6 +55,7 @@ public class TraceFilterMockChainIntegrationTests {
|
||||
new Random(), new DefaultSpanNamer(),
|
||||
new NoOpSpanLogger(), new NoOpSpanReporter(), new TraceKeys());
|
||||
private TraceKeys traceKeys = new TraceKeys();
|
||||
private SleuthProperties properties = new SleuthProperties();
|
||||
private HttpTraceKeysInjector keysInjector = new HttpTraceKeysInjector(this.tracer, this.traceKeys);
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
@@ -94,6 +96,7 @@ public class TraceFilterMockChainIntegrationTests {
|
||||
|
||||
private BeanFactory beanFactory() {
|
||||
BeanFactory beanFactory = Mockito.mock(BeanFactory.class);
|
||||
BDDMockito.given(beanFactory.getBean(SleuthProperties.class)).willReturn(this.properties);
|
||||
BDDMockito.given(beanFactory.getBean(Tracer.class)).willReturn(this.tracer);
|
||||
BDDMockito.given(beanFactory.getBean(TraceKeys.class)).willReturn(this.traceKeys);
|
||||
BDDMockito.given(beanFactory.getBean(HttpSpanExtractor.class))
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.cloud.sleuth.SpanReporter;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.assertions.ListOfSpans;
|
||||
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
|
||||
import org.springframework.cloud.sleuth.log.SpanLogger;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.sampler.NeverSampler;
|
||||
@@ -67,7 +68,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
|
||||
public class TraceFilterTests {
|
||||
|
||||
public static final long PARENT_ID = 10L;
|
||||
public static final String PARENT_ID_AS_STRING = String.valueOf(PARENT_ID);
|
||||
|
||||
@Mock SpanLogger spanLogger;
|
||||
ArrayListSpanAccumulator spanReporter = new ArrayListSpanAccumulator();
|
||||
@@ -76,6 +76,7 @@ public class TraceFilterTests {
|
||||
|
||||
private Tracer tracer;
|
||||
private TraceKeys traceKeys = new TraceKeys();
|
||||
private SleuthProperties properties = new SleuthProperties();
|
||||
private HttpTraceKeysInjector httpTraceKeysInjector;
|
||||
|
||||
private Span span;
|
||||
@@ -200,15 +201,6 @@ public class TraceFilterTests {
|
||||
then(ExceptionUtils.getLastException()).isNull();
|
||||
}
|
||||
|
||||
private Span parentSpan() {
|
||||
Optional<Span> parent = this.spanReporter.getSpans().stream()
|
||||
.filter(span -> Span.idToHex(span.getSpanId()).equals(PARENT_ID_AS_STRING)
|
||||
|| span.getName().equals("http:/parent/"))
|
||||
.findFirst();
|
||||
assertThat(parent.isPresent()).isTrue();
|
||||
return parent.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void continuesSpanInRequestAttr() throws Exception {
|
||||
Span span = this.tracer.createSpan("http:foo");
|
||||
@@ -268,6 +260,21 @@ public class TraceFilterTests {
|
||||
then(TestSpanContextHolder.getCurrentSpan()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createsChildFromHeadersWhenJoinUnsupported() throws Exception {
|
||||
this.properties.setSupportsJoin(false);
|
||||
this.request = builder().header(Span.SPAN_ID_NAME, PARENT_ID)
|
||||
.header(Span.TRACE_ID_NAME, 20L).buildRequest(new MockServletContext());
|
||||
BeanFactory beanFactory = beanFactory();
|
||||
BDDMockito.given(beanFactory.getBean(SpanReporter.class)).willReturn(this.spanReporter);
|
||||
|
||||
TraceFilter filter = new TraceFilter(beanFactory);
|
||||
filter.doFilter(this.request, this.response, this.filterChain);
|
||||
|
||||
assertThat(this.spanReporter.getSpans().get(0).getParents().get(0))
|
||||
.isEqualTo(16); // test data is in hex!
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsAdditionalHeaders() throws Exception {
|
||||
this.request = builder().header(Span.SPAN_ID_NAME, PARENT_ID)
|
||||
@@ -556,6 +563,7 @@ public class TraceFilterTests {
|
||||
private BeanFactory beanFactory() {
|
||||
BDDMockito.given(beanFactory.getBean(SkipPatternProvider.class))
|
||||
.willThrow(new NoSuchBeanDefinitionException("foo"));
|
||||
BDDMockito.given(beanFactory.getBean(SleuthProperties.class)).willReturn(this.properties);
|
||||
BDDMockito.given(beanFactory.getBean(Tracer.class)).willReturn(this.tracer);
|
||||
BDDMockito.given(beanFactory.getBean(TraceKeys.class)).willReturn(this.traceKeys);
|
||||
BDDMockito.given(beanFactory.getBean(HttpSpanExtractor.class)).willReturn(this.spanExtractor);
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.springframework.cloud.sleuth.instrument.web.common;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.sleuth.autoconfig.SleuthProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpSpanExtractor;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
@@ -30,6 +31,7 @@ public abstract class AbstractMvcIntegrationTest {
|
||||
|
||||
@Autowired protected WebApplicationContext webApplicationContext;
|
||||
protected MockMvc mockMvc;
|
||||
@Autowired protected SleuthProperties properties;
|
||||
@Autowired protected Tracer tracer;
|
||||
@Autowired protected TraceKeys traceKeys;
|
||||
@Autowired protected HttpSpanExtractor spanExtractor;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.trace;
|
||||
|
||||
import java.util.Date;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
@@ -223,6 +224,20 @@ public class DefaultTracerTests {
|
||||
tracer.close(span);
|
||||
}
|
||||
|
||||
/**
|
||||
* To support conversion to Amazon trace IDs, the first 32 bits of the trace ID are epoch seconds.
|
||||
*/
|
||||
@Test
|
||||
public void creates128bitTraceIdWithEncodedTimestamp() {
|
||||
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
|
||||
this.spanNamer, this.spanLogger, this.spanReporter, true, new TraceKeys());
|
||||
Span span = tracer.createSpan(bigName());
|
||||
String traceId = span.traceIdString();
|
||||
long epochSeconds = Long.parseLong(traceId.substring(0, 8), 16);
|
||||
then(new Date(epochSeconds * 1000)).isToday();
|
||||
tracer.close(span);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateChildOfSpanWithShortenedName() {
|
||||
DefaultTracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
|
||||
|
||||
Reference in New Issue
Block a user