Merge branch 'master' into 2.0.x

This commit is contained in:
Adrian Cole
2017-10-06 14:35:21 +08:00
8 changed files with 77 additions and 15 deletions

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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))

View File

@@ -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);

View File

@@ -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;

View File

@@ -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(),