Fix some compiler warnings and tidy up a few javadocs
This commit is contained in:
@@ -17,23 +17,27 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
|
||||
/**
|
||||
* Adopted from <a href="https://github.com/opentracing/opentracing-java/pull/11/files#diff-eb9c3460aba76aabc0de04b05e4a2b3d"></a>OpenTracing</a>
|
||||
* Adopted from <a href=
|
||||
* "https://github.com/opentracing/opentracing-java/pull/11/files#diff-eb9c3460aba76aabc0de04b05e4a2b3d">
|
||||
* </a>OpenTracing</a>
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface SpanExtractor<T> {
|
||||
/** Returns a SpanBuilder provided
|
||||
* a “carrier” object from which to extract identifying information needed by the new Span instance.
|
||||
/**
|
||||
* Returns a SpanBuilder provided a “carrier” object from which to extract identifying
|
||||
* information needed by the new Span instance.
|
||||
*
|
||||
* If the carrier object has no such span stored within it, a new Span is created.
|
||||
*
|
||||
* Unless there’s an error, it returns a Span.
|
||||
* The Span generated from the builder can be used in the host process like any other.
|
||||
* Unless there’s an error, it returns a Span. The Span generated from the builder can
|
||||
* be used in the host process like any other.
|
||||
*
|
||||
* (Note that some OpenTracing implementations consider the Spans on either side of an RPC to have the same identity,
|
||||
* and others consider the caller to be the parent and the receiver to be the child).
|
||||
* (Note that some OpenTracing implementations consider the Spans on either side of an
|
||||
* RPC to have the same identity, and others consider the caller to be the parent and
|
||||
* the receiver to be the child).
|
||||
*/
|
||||
Span joinTrace(T carrier);
|
||||
}
|
||||
|
||||
@@ -17,21 +17,28 @@
|
||||
package org.springframework.cloud.sleuth;
|
||||
|
||||
/**
|
||||
* Adopted from <a href="https://github.com/opentracing/opentracing-java/blob/master/opentracing/src/main/java/opentracing/Tracer.java"></a>OpenTracing</a>
|
||||
* Adopted from <a href=
|
||||
* "https://github.com/opentracing/opentracing-java/blob/master/opentracing/src/main/java/opentracing/Tracer.java">
|
||||
* </a>OpenTracing</a>
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public interface SpanInjector<T> {
|
||||
/** Takes two arguments:
|
||||
* a Span instance, and
|
||||
* a “carrier” object in which to inject that Span for cross-process propagation.
|
||||
/**
|
||||
* Takes two arguments:
|
||||
* <ul>
|
||||
* <li>a Span instance, and</li>
|
||||
* <li>a “carrier” object in which to inject that Span for cross-process propagation.
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* A “carrier” object is some sort of http or rpc envelope, for example HeaderGroup (from Apache HttpComponents).
|
||||
* A “carrier” object is some sort of http or rpc envelope, for example HeaderGroup
|
||||
* (from Apache HttpComponents).
|
||||
*
|
||||
* Attempting to inject to a carrier that has been registered/configured to this Tracer will result in a
|
||||
* IllegalStateException.
|
||||
* Attempting to inject to a carrier that has been registered/configured to this
|
||||
* Tracer will result in a IllegalStateException.
|
||||
*/
|
||||
void inject(Span span, T carrier);
|
||||
}
|
||||
|
||||
@@ -19,16 +19,16 @@ package org.springframework.cloud.sleuth;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Names of default headers that need to be sent between processes
|
||||
* for tracing to be operational.
|
||||
* Names of default headers that need to be sent between processes for tracing to be
|
||||
* operational.
|
||||
*
|
||||
* Default Zipkin Headers are
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@code X-B3-TraceId} 64 encoded bits</li>
|
||||
* <li>{@code X-B3-SpanId} 64 encoded bits</li>
|
||||
* <li>{@code X-B3-ParentSpanId} 64 encoded bits</li>
|
||||
* <li>{@code X-B3-Sampled} Boolean (either “1” or “0”)</li>
|
||||
* <li>{@code X-B3-TraceId} 64 encoded bits</li>
|
||||
* <li>{@code X-B3-SpanId} 64 encoded bits</li>
|
||||
* <li>{@code X-B3-ParentSpanId} 64 encoded bits</li>
|
||||
* <li>{@code X-B3-Sampled} Boolean (either “1” or “0”)</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
@@ -57,7 +57,7 @@ public class TraceHeaders {
|
||||
this.sleuth = sleuth;
|
||||
}
|
||||
|
||||
private static class Zipkin {
|
||||
protected static class Zipkin {
|
||||
private String traceId = "X-B3-TraceId";
|
||||
private String spanId = "X-B3-SpanId";
|
||||
private String parentSpanId = "X-B3-ParentSpanId";
|
||||
@@ -96,7 +96,7 @@ public class TraceHeaders {
|
||||
}
|
||||
}
|
||||
|
||||
private static class Sleuth {
|
||||
protected static class Sleuth {
|
||||
private String processId = "X-Process-Id";
|
||||
private String spanName = "X-Span-Name";
|
||||
private String exportable = "X-Span-Export";
|
||||
|
||||
@@ -19,11 +19,12 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter implements ExecutorChannelInterceptor {
|
||||
abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
|
||||
implements ExecutorChannelInterceptor {
|
||||
|
||||
/**
|
||||
* If a span comes from messaging components then it will have this value
|
||||
* as a prefix to its name.
|
||||
* If a span comes from messaging components then it will have this value as a prefix
|
||||
* to its name.
|
||||
* <p>
|
||||
* Example of a Span name: {@code message:foo}
|
||||
* <p>
|
||||
@@ -33,12 +34,12 @@ abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
|
||||
|
||||
private final Tracer tracer;
|
||||
private final TraceKeys traceKeys;
|
||||
private final SpanExtractor<Message> spanExtractor;
|
||||
private final SpanInjector<MessageBuilder> spanInjector;
|
||||
private final SpanExtractor<Message<?>> spanExtractor;
|
||||
private final SpanInjector<MessageBuilder<?>> spanInjector;
|
||||
|
||||
protected AbstractTraceChannelInterceptor(Tracer tracer, TraceKeys traceKeys,
|
||||
SpanExtractor<Message> spanExtractor,
|
||||
SpanInjector<MessageBuilder> spanInjector) {
|
||||
SpanExtractor<Message<?>> spanExtractor,
|
||||
SpanInjector<MessageBuilder<?>> spanInjector) {
|
||||
this.tracer = tracer;
|
||||
this.traceKeys = traceKeys;
|
||||
this.spanExtractor = spanExtractor;
|
||||
@@ -53,13 +54,13 @@ abstract class AbstractTraceChannelInterceptor extends ChannelInterceptorAdapter
|
||||
return this.traceKeys;
|
||||
}
|
||||
|
||||
protected SpanInjector<MessageBuilder> getSpanInjector() {
|
||||
protected SpanInjector<MessageBuilder<?>> getSpanInjector() {
|
||||
return this.spanInjector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a span given the message and a channel. Returns {@code null} if ids
|
||||
* are missing.
|
||||
* Returns a span given the message and a channel. Returns {@code null} if ids are
|
||||
* missing.
|
||||
*/
|
||||
protected Span buildSpan(Message<?> message) {
|
||||
return this.spanExtractor.joinTrace(message);
|
||||
|
||||
@@ -22,20 +22,20 @@ import org.springframework.messaging.support.MessageBuilder;
|
||||
/**
|
||||
* Utility class to contain both {@link MessageBuilder} and the {@link Message}.
|
||||
*
|
||||
* {@link MessageBuilder} is mutable
|
||||
* {@link Message} is immutable
|
||||
* {@link MessageBuilder} is mutable {@link Message} is immutable
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
public class MessageBuilderHolder {
|
||||
final MessageBuilder messageBuilder;
|
||||
final Message message;
|
||||
final MessageBuilder<?> messageBuilder;
|
||||
final Message<?> message;
|
||||
|
||||
public MessageBuilderHolder(MessageBuilder messageBuilder, Message message) {
|
||||
public MessageBuilderHolder(MessageBuilder<?> messageBuilder, Message<?> message) {
|
||||
this.messageBuilder = messageBuilder;
|
||||
this.message = message;
|
||||
}
|
||||
public MessageBuilderHolder(MessageBuilder messageBuilder) {
|
||||
|
||||
public MessageBuilderHolder(MessageBuilder<?> messageBuilder) {
|
||||
this.messageBuilder = messageBuilder;
|
||||
this.message = messageBuilder.build();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.messaging.Message;
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class MessagingSpanExtractor implements SpanExtractor<Message> {
|
||||
public class MessagingSpanExtractor implements SpanExtractor<Message<?>> {
|
||||
|
||||
private final Random random;
|
||||
|
||||
@@ -38,19 +38,20 @@ public class MessagingSpanExtractor implements SpanExtractor<Message> {
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Span joinTrace(Message carrier) {
|
||||
@Override
|
||||
public Span joinTrace(Message<?> carrier) {
|
||||
if (!hasHeader(carrier, Span.TRACE_ID_NAME)
|
||||
|| !hasHeader(carrier, Span.SPAN_ID_NAME)) {
|
||||
return null;
|
||||
//TODO: Consider throwing IllegalArgumentException;
|
||||
// TODO: Consider throwing IllegalArgumentException;
|
||||
}
|
||||
long spanId = hasHeader(carrier, Span.SPAN_ID_NAME)
|
||||
? Span.hexToId(getHeader(carrier, Span.SPAN_ID_NAME))
|
||||
: this.random.nextLong();
|
||||
long traceId = Span.hexToId(getHeader(carrier, Span.TRACE_ID_NAME));
|
||||
SpanBuilder spanBuilder = Span.builder().traceId(traceId).spanId(spanId);
|
||||
spanBuilder.exportable(Span.SPAN_SAMPLED.equals(getHeader(carrier, Span.SAMPLED_NAME)));
|
||||
spanBuilder.exportable(
|
||||
Span.SPAN_SAMPLED.equals(getHeader(carrier, Span.SAMPLED_NAME)));
|
||||
String parentId = getHeader(carrier, Span.PARENT_ID_NAME);
|
||||
String processId = getHeader(carrier, Span.PROCESS_ID_NAME);
|
||||
String spanName = getHeader(carrier, Span.SPAN_NAME_NAME);
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class MessagingSpanInjector implements SpanInjector<MessageBuilder> {
|
||||
class MessagingSpanInjector implements SpanInjector<MessageBuilder<?>> {
|
||||
|
||||
public static final String SPAN_HEADER = "X-Current-Span";
|
||||
|
||||
@@ -47,12 +47,13 @@ class MessagingSpanInjector implements SpanInjector<MessageBuilder> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inject(Span span, MessageBuilder carrier) {
|
||||
Message initialMessage = carrier.build();
|
||||
public void inject(Span span, MessageBuilder<?> carrier) {
|
||||
Message<?> initialMessage = carrier.build();
|
||||
MessageHeaderAccessor accessor = MessageHeaderAccessor
|
||||
.getMutableAccessor(initialMessage);
|
||||
if (span == null) {
|
||||
if (!Span.SPAN_SAMPLED.equals(initialMessage.getHeaders().get(Span.SAMPLED_NAME))) {
|
||||
if (!Span.SPAN_SAMPLED
|
||||
.equals(initialMessage.getHeaders().get(Span.SAMPLED_NAME))) {
|
||||
accessor.setHeader(Span.SAMPLED_NAME, Span.SPAN_NOT_SAMPLED);
|
||||
carrier.setHeaders(accessor);
|
||||
return;
|
||||
@@ -86,8 +87,7 @@ class MessagingSpanInjector implements SpanInjector<MessageBuilder> {
|
||||
carrier.setHeaders(accessor);
|
||||
}
|
||||
|
||||
private void addAnnotations(TraceKeys traceKeys, Message<?> message,
|
||||
Span span) {
|
||||
private void addAnnotations(TraceKeys traceKeys, Message<?> message, Span span) {
|
||||
for (String name : traceKeys.getMessage().getHeaders()) {
|
||||
if (message.getHeaders().containsKey(name)) {
|
||||
String key = traceKeys.getMessage().getPrefix() + name.toLowerCase();
|
||||
@@ -95,7 +95,8 @@ class MessagingSpanInjector implements SpanInjector<MessageBuilder> {
|
||||
if (value == null) {
|
||||
value = "null";
|
||||
}
|
||||
tagIfEntryMissing(span, key, value.toString()); // TODO: better way to serialize?
|
||||
// TODO: better way to serialize?
|
||||
tagIfEntryMissing(span, key, value.toString());
|
||||
}
|
||||
}
|
||||
addPayloadAnnotations(traceKeys, message.getPayload(), span);
|
||||
@@ -122,8 +123,7 @@ class MessagingSpanInjector implements SpanInjector<MessageBuilder> {
|
||||
}
|
||||
}
|
||||
|
||||
private void addHeader(Map<String, String> headers, String name,
|
||||
String value) {
|
||||
private void addHeader(Map<String, String> headers, String name, String value) {
|
||||
if (StringUtils.hasText(value)) {
|
||||
headers.put(name, value);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* A channel interceptor that automatically starts / continues / closes and detaches spans.
|
||||
* A channel interceptor that automatically starts / continues / closes and detaches
|
||||
* spans.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
@@ -38,8 +39,8 @@ public class TraceChannelInterceptor extends AbstractTraceChannelInterceptor {
|
||||
private static final String SPAN_HEADER = "X-Current-Span";
|
||||
|
||||
public TraceChannelInterceptor(Tracer tracer, TraceKeys traceKeys,
|
||||
SpanExtractor<Message> spanExtractor,
|
||||
SpanInjector<MessageBuilder> spanInjector) {
|
||||
SpanExtractor<Message<?>> spanExtractor,
|
||||
SpanInjector<MessageBuilder<?>> spanInjector) {
|
||||
super(tracer, traceKeys, spanExtractor, spanInjector);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,24 +28,24 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* AutoConfiguration containing Span extractor and injector for messaging.
|
||||
* Will be reused by Messaging and WebSockets
|
||||
* AutoConfiguration containing Span extractor and injector for messaging. Will be reused
|
||||
* by Messaging and WebSockets
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnBean({TraceKeys.class, Random.class})
|
||||
@ConditionalOnBean({ TraceKeys.class, Random.class })
|
||||
public class TraceSpanMessagingAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public SpanExtractor<Message> messagingSpanExtractor(Random random) {
|
||||
public SpanExtractor<Message<?>> messagingSpanExtractor(Random random) {
|
||||
return new MessagingSpanExtractor(random);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpanInjector<MessageBuilder> messagingSpanInjector(TraceKeys traceKeys) {
|
||||
public SpanInjector<MessageBuilder<?>> messagingSpanInjector(TraceKeys traceKeys) {
|
||||
return new MessagingSpanInjector(traceKeys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,11 +23,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.sleuth.SpanInjector;
|
||||
import org.springframework.cloud.sleuth.SpanExtractor;
|
||||
import org.springframework.cloud.sleuth.SpanInjector;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.integration.config.GlobalChannelInterceptor;
|
||||
@@ -35,8 +35,9 @@ import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration Auto-configuration}
|
||||
* that registers a Sleuth version of the {@link org.springframework.messaging.support.ChannelInterceptor}.
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} that registers a Sleuth version of the
|
||||
* {@link org.springframework.messaging.support.ChannelInterceptor}.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @since 1.0.0
|
||||
@@ -46,7 +47,8 @@ import org.springframework.messaging.support.MessageBuilder;
|
||||
@Configuration
|
||||
@ConditionalOnClass(GlobalChannelInterceptor.class)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter({TraceAutoConfiguration.class, TraceSpanMessagingAutoConfiguration.class})
|
||||
@AutoConfigureAfter({ TraceAutoConfiguration.class,
|
||||
TraceSpanMessagingAutoConfiguration.class })
|
||||
@ConditionalOnProperty(value = "spring.sleuth.integration.enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties(TraceKeys.class)
|
||||
public class TraceSpringIntegrationAutoConfiguration {
|
||||
@@ -54,10 +56,10 @@ public class TraceSpringIntegrationAutoConfiguration {
|
||||
@Bean
|
||||
@GlobalChannelInterceptor
|
||||
public TraceChannelInterceptor traceChannelInterceptor(Tracer tracer,
|
||||
TraceKeys traceKeys, Random random,
|
||||
SpanExtractor<Message> spanExtractor,
|
||||
SpanInjector<MessageBuilder> spanInjector) {
|
||||
return new TraceChannelInterceptor(tracer, traceKeys, spanExtractor, spanInjector);
|
||||
TraceKeys traceKeys, Random random, SpanExtractor<Message<?>> spanExtractor,
|
||||
SpanInjector<MessageBuilder<?>> spanInjector) {
|
||||
return new TraceChannelInterceptor(tracer, traceKeys, spanExtractor,
|
||||
spanInjector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ import org.springframework.web.socket.config.annotation.DelegatingWebSocketMessa
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration Auto-configuration}
|
||||
* that enables tracing for WebSockets.
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} that enables tracing for WebSockets.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @since 1.0.0
|
||||
@@ -38,10 +38,14 @@ import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
public class TraceWebSocketAutoConfiguration
|
||||
extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Autowired Tracer tracer;
|
||||
@Autowired TraceKeys traceKeys;
|
||||
@Autowired SpanExtractor<Message> spanExtractor;
|
||||
@Autowired SpanInjector<MessageBuilder> spanInjector;
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
@Autowired
|
||||
TraceKeys traceKeys;
|
||||
@Autowired
|
||||
SpanExtractor<Message<?>> spanExtractor;
|
||||
@Autowired
|
||||
SpanInjector<MessageBuilder<?>> spanInjector;
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
@@ -50,13 +54,13 @@ public class TraceWebSocketAutoConfiguration
|
||||
|
||||
@Override
|
||||
public void configureClientOutboundChannel(ChannelRegistration registration) {
|
||||
registration.setInterceptors(
|
||||
new TraceChannelInterceptor(this.tracer, this.traceKeys, this.spanExtractor, this.spanInjector));
|
||||
registration.setInterceptors(new TraceChannelInterceptor(this.tracer,
|
||||
this.traceKeys, this.spanExtractor, this.spanInjector));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureClientInboundChannel(ChannelRegistration registration) {
|
||||
registration.setInterceptors(
|
||||
new TraceChannelInterceptor(this.tracer, this.traceKeys, this.spanExtractor, this.spanInjector));
|
||||
registration.setInterceptors(new TraceChannelInterceptor(this.tracer,
|
||||
this.traceKeys, this.spanExtractor, this.spanInjector));
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -30,61 +35,73 @@ import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.BDDMockito.then;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyLong;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TraceableScheduledExecutorServiceTest {
|
||||
|
||||
@Mock Tracer tracer;
|
||||
@Mock TraceKeys traceKeys;
|
||||
@Mock SpanNamer spanNamer;
|
||||
@Mock ScheduledExecutorService scheduledExecutorService;
|
||||
@InjectMocks TraceableScheduledExecutorService traceableScheduledExecutorService;
|
||||
@Mock
|
||||
Tracer tracer;
|
||||
@Mock
|
||||
TraceKeys traceKeys;
|
||||
@Mock
|
||||
SpanNamer spanNamer;
|
||||
@Mock
|
||||
ScheduledExecutorService scheduledExecutorService;
|
||||
@InjectMocks
|
||||
TraceableScheduledExecutorService traceableScheduledExecutorService;
|
||||
|
||||
@Test
|
||||
public void should_schedule_a_local_component_trace_runnable() throws Exception {
|
||||
this.traceableScheduledExecutorService.schedule(aRunnable(), 1L, TimeUnit.DAYS);
|
||||
|
||||
then(this.scheduledExecutorService).should().schedule(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(LocalComponentTraceRunnable.class)), anyLong(), any(TimeUnit.class));
|
||||
then(this.scheduledExecutorService).should().schedule(
|
||||
BDDMockito
|
||||
.<Runnable>argThat(instanceOf(LocalComponentTraceRunnable.class)),
|
||||
anyLong(), any(TimeUnit.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void should_schedule_a_local_component_trace_callable() throws Exception {
|
||||
this.traceableScheduledExecutorService.schedule(aCallable(), 1L, TimeUnit.DAYS);
|
||||
|
||||
then(this.scheduledExecutorService).should().schedule(BDDMockito.<Callable>argThat(
|
||||
instanceOf(LocalComponentTraceCallable.class)), anyLong(), any(TimeUnit.class));
|
||||
then(this.scheduledExecutorService).should().schedule(
|
||||
BDDMockito.<Callable<?>>argThat(
|
||||
instanceOf(LocalComponentTraceCallable.class)),
|
||||
anyLong(), any(TimeUnit.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_at_fixed_rate_a_local_component_trace_runnable() throws Exception {
|
||||
this.traceableScheduledExecutorService.scheduleAtFixedRate(aRunnable(), 1L, 1L, TimeUnit.DAYS);
|
||||
public void should_schedule_at_fixed_rate_a_local_component_trace_runnable()
|
||||
throws Exception {
|
||||
this.traceableScheduledExecutorService.scheduleAtFixedRate(aRunnable(), 1L, 1L,
|
||||
TimeUnit.DAYS);
|
||||
|
||||
then(this.scheduledExecutorService).should().scheduleAtFixedRate(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(LocalComponentTraceRunnable.class)), anyLong(), anyLong(), any(TimeUnit.class));
|
||||
then(this.scheduledExecutorService).should().scheduleAtFixedRate(
|
||||
BDDMockito
|
||||
.<Runnable>argThat(instanceOf(LocalComponentTraceRunnable.class)),
|
||||
anyLong(), anyLong(), any(TimeUnit.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_schedule_with_fixed_delay_a_local_component_trace_runnable() throws Exception {
|
||||
this.traceableScheduledExecutorService.scheduleWithFixedDelay(aRunnable(), 1L, 1L, TimeUnit.DAYS);
|
||||
public void should_schedule_with_fixed_delay_a_local_component_trace_runnable()
|
||||
throws Exception {
|
||||
this.traceableScheduledExecutorService.scheduleWithFixedDelay(aRunnable(), 1L, 1L,
|
||||
TimeUnit.DAYS);
|
||||
|
||||
then(this.scheduledExecutorService).should().scheduleWithFixedDelay(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(LocalComponentTraceRunnable.class)), anyLong(), anyLong(), any(TimeUnit.class));
|
||||
then(this.scheduledExecutorService).should().scheduleWithFixedDelay(
|
||||
BDDMockito
|
||||
.<Runnable>argThat(instanceOf(LocalComponentTraceRunnable.class)),
|
||||
anyLong(), anyLong(), any(TimeUnit.class));
|
||||
}
|
||||
|
||||
Runnable aRunnable() {
|
||||
return () -> {};
|
||||
return () -> {
|
||||
};
|
||||
}
|
||||
|
||||
Callable aCallable() {
|
||||
Callable<?> aCallable() {
|
||||
return () -> null;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.messaging;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
@@ -26,8 +29,6 @@ import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.messaging.support.NativeMessageHeaderAccessor;
|
||||
|
||||
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
@@ -35,7 +36,8 @@ import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.asser
|
||||
public class MessagingSpanInjectorTests {
|
||||
|
||||
private TraceKeys traceKeys = new TraceKeys();
|
||||
private MessagingSpanInjector messagingSpanInjector = new MessagingSpanInjector(this.traceKeys);
|
||||
private MessagingSpanInjector messagingSpanInjector = new MessagingSpanInjector(
|
||||
this.traceKeys);
|
||||
|
||||
@Test
|
||||
public void spanHeadersAdded() {
|
||||
@@ -51,12 +53,12 @@ public class MessagingSpanInjectorTests {
|
||||
@Test
|
||||
public void shouldNotOverrideSpanTags() {
|
||||
Span span = spanWithStringPayloadType();
|
||||
MessageBuilder messageBuilder = messageWithIntegerPayloadType();
|
||||
MessageBuilder<?> messageBuilder = messageWithIntegerPayloadType();
|
||||
|
||||
this.messagingSpanInjector.inject(span, messageBuilder);
|
||||
|
||||
assertThat(messageBuilder.build().getHeaders())
|
||||
.containsKeys(Span.SPAN_ID_NAME, "message/payload-type");
|
||||
assertThat(messageBuilder.build().getHeaders()).containsKeys(Span.SPAN_ID_NAME,
|
||||
"message/payload-type");
|
||||
assertThat(span).hasATag("message/payload-type", "java.lang.String");
|
||||
}
|
||||
|
||||
@@ -66,7 +68,7 @@ public class MessagingSpanInjectorTests {
|
||||
return span;
|
||||
}
|
||||
|
||||
private MessageBuilder messageWithIntegerPayloadType() {
|
||||
private MessageBuilder<?> messageWithIntegerPayloadType() {
|
||||
MessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create();
|
||||
accessor.setHeader("message/payload-type", "java.lang.Integer");
|
||||
return MessageBuilder.withPayload("Hello World").setHeaders(accessor);
|
||||
@@ -76,8 +78,10 @@ public class MessagingSpanInjectorTests {
|
||||
public void nativeSpanHeadersAdded() {
|
||||
Span span = Span.builder().name("http:foo").spanId(1L).traceId(2L).build();
|
||||
MessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create();
|
||||
Message messageToBuild = MessageBuilder.createMessage("Hello World", accessor.getMessageHeaders());
|
||||
MessageBuilder<String> messageBuilder = MessageBuilder.fromMessage(messageToBuild);
|
||||
Message<String> messageToBuild = MessageBuilder.createMessage("Hello World",
|
||||
accessor.getMessageHeaders());
|
||||
MessageBuilder<String> messageBuilder = MessageBuilder
|
||||
.fromMessage(messageToBuild);
|
||||
|
||||
this.messagingSpanInjector.inject(span, messageBuilder);
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -49,47 +52,48 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(TraceFilterCustomExtractorTests.Config.class)
|
||||
@WebIntegrationTest(randomPort = true)
|
||||
public class TraceFilterCustomExtractorTests {
|
||||
@Autowired Random random;
|
||||
@Autowired RestTemplate restTemplate;
|
||||
@Autowired Config config;
|
||||
@Autowired CustomRestController customRestController;
|
||||
public class TraceFilterCustomExtractorTests {
|
||||
@Autowired
|
||||
Random random;
|
||||
@Autowired
|
||||
RestTemplate restTemplate;
|
||||
@Autowired
|
||||
Config config;
|
||||
@Autowired
|
||||
CustomRestController customRestController;
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void should_create_a_valid_span_from_custom_headers() {
|
||||
long spanId = this.random.nextLong();
|
||||
long traceId = this.random.nextLong();
|
||||
RequestEntity requestEntity = RequestEntity.get(
|
||||
URI.create("http://localhost:" + this.config.port + "/headers"))
|
||||
RequestEntity<?> requestEntity = RequestEntity
|
||||
.get(URI.create("http://localhost:" + this.config.port + "/headers"))
|
||||
.header("correlationId", Span.idToHex(traceId))
|
||||
.header("mySpanId", Span.idToHex(spanId))
|
||||
.build();
|
||||
.header("mySpanId", Span.idToHex(spanId)).build();
|
||||
|
||||
ResponseEntity<Map> requestHeaders =
|
||||
this.restTemplate.exchange(requestEntity, Map.class);
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity<Map> requestHeaders = this.restTemplate.exchange(requestEntity,
|
||||
Map.class);
|
||||
|
||||
then(this.customRestController.span)
|
||||
.hasTraceIdEqualTo(traceId);
|
||||
then(this.customRestController.span).hasTraceIdEqualTo(traceId);
|
||||
then(requestHeaders.getBody())
|
||||
.containsEntry("correlationId", Span.idToHex(traceId))
|
||||
.containsEntry("mySpanId", Span.idToHex(spanId))
|
||||
.as("input request headers");
|
||||
then(requestHeaders.getHeaders())
|
||||
.containsEntry("correlationId", Collections.singletonList(Span.idToHex(traceId)))
|
||||
.containsKey("mySpanId")
|
||||
.as("response headers");
|
||||
.containsEntry("correlationId",
|
||||
Collections.singletonList(Span.idToHex(traceId)))
|
||||
.containsKey("mySpanId").as("response headers");
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
static class Config implements
|
||||
ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
static class Config
|
||||
implements ApplicationListener<EmbeddedServletContainerInitializedEvent> {
|
||||
int port;
|
||||
|
||||
// tag::configuration[]
|
||||
@@ -111,13 +115,15 @@ public class TraceFilterCustomExtractorTests {
|
||||
this.port = event.getEmbeddedServletContainer().getPort();
|
||||
}
|
||||
|
||||
@Bean CustomRestController customRestController() {
|
||||
@Bean
|
||||
CustomRestController customRestController() {
|
||||
return new CustomRestController();
|
||||
}
|
||||
}
|
||||
|
||||
// tag::extractor[]
|
||||
static class CustomHttpServletRequestSpanExtractor implements SpanExtractor<HttpServletRequest> {
|
||||
static class CustomHttpServletRequestSpanExtractor
|
||||
implements SpanExtractor<HttpServletRequest> {
|
||||
|
||||
@Override
|
||||
public Span joinTrace(HttpServletRequest carrier) {
|
||||
@@ -132,7 +138,8 @@ public class TraceFilterCustomExtractorTests {
|
||||
// end::extractor[]
|
||||
|
||||
// tag::injector[]
|
||||
static class CustomHttpServletResponseSpanInjector implements SpanInjector<HttpServletResponse> {
|
||||
static class CustomHttpServletResponseSpanInjector
|
||||
implements SpanInjector<HttpServletResponse> {
|
||||
|
||||
@Override
|
||||
public void inject(Span span, HttpServletResponse carrier) {
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -31,9 +34,6 @@ import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.trace.DefaultTracer;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.mockito.BDDMockito.mock;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@@ -42,59 +42,61 @@ public class TraceAsyncListenableTaskExecutorTest {
|
||||
AsyncListenableTaskExecutor delegate = mock(AsyncListenableTaskExecutor.class);
|
||||
Tracer tracer = new DefaultTracer(new AlwaysSampler(), new Random(),
|
||||
new DefaultSpanNamer(), new NoOpSpanLogger(), new NoOpSpanReporter()) {
|
||||
@Override public boolean isTracing() {
|
||||
@Override
|
||||
public boolean isTracing() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
TraceAsyncListenableTaskExecutor traceAsyncListenableTaskExecutor =
|
||||
new TraceAsyncListenableTaskExecutor(this.delegate, this.tracer);
|
||||
TraceAsyncListenableTaskExecutor traceAsyncListenableTaskExecutor = new TraceAsyncListenableTaskExecutor(
|
||||
this.delegate, this.tracer);
|
||||
|
||||
@Test
|
||||
public void should_submit_listenable_trace_runnable() throws Exception {
|
||||
this.traceAsyncListenableTaskExecutor.submitListenable(aRunnable());
|
||||
|
||||
BDDMockito.then(this.delegate).should().submitListenable(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(TraceRunnable.class)));
|
||||
BDDMockito.then(this.delegate).should().submitListenable(
|
||||
BDDMockito.<Runnable>argThat(instanceOf(TraceRunnable.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_listenable_trace_callable() throws Exception {
|
||||
this.traceAsyncListenableTaskExecutor.submitListenable(aCallable());
|
||||
|
||||
BDDMockito.then(this.delegate).should().submitListenable(BDDMockito.<Callable>argThat(
|
||||
instanceOf(TraceCallable.class)));
|
||||
BDDMockito.then(this.delegate).should().submitListenable(
|
||||
BDDMockito.<Callable<?>>argThat(instanceOf(TraceCallable.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_a_trace_runnable() throws Exception {
|
||||
this.traceAsyncListenableTaskExecutor.execute(aRunnable());
|
||||
|
||||
BDDMockito.then(this.delegate).should().execute(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(TraceRunnable.class)));
|
||||
BDDMockito.then(this.delegate).should()
|
||||
.execute(BDDMockito.<Runnable>argThat(instanceOf(TraceRunnable.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_execute_with_timeout_a_trace_runnable() throws Exception {
|
||||
this.traceAsyncListenableTaskExecutor.execute(aRunnable(), 1L);
|
||||
|
||||
BDDMockito.then(this.delegate).should().execute(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(TraceRunnable.class)), BDDMockito.anyLong());
|
||||
BDDMockito.then(this.delegate).should().execute(
|
||||
BDDMockito.<Runnable>argThat(instanceOf(TraceRunnable.class)),
|
||||
BDDMockito.anyLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_callable() throws Exception {
|
||||
this.traceAsyncListenableTaskExecutor.submit(aCallable());
|
||||
|
||||
BDDMockito.then(this.delegate).should().submit(BDDMockito.<Callable>argThat(
|
||||
instanceOf(TraceCallable.class)));
|
||||
BDDMockito.then(this.delegate).should()
|
||||
.submit(BDDMockito.<Callable<?>>argThat(instanceOf(TraceCallable.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_submit_trace_runnable() throws Exception {
|
||||
this.traceAsyncListenableTaskExecutor.submit(aRunnable());
|
||||
|
||||
BDDMockito.then(this.delegate).should().submit(BDDMockito.<Runnable>argThat(
|
||||
instanceOf(TraceRunnable.class)));
|
||||
BDDMockito.then(this.delegate).should()
|
||||
.submit(BDDMockito.<Runnable>argThat(instanceOf(TraceRunnable.class)));
|
||||
}
|
||||
|
||||
Runnable aRunnable() {
|
||||
@@ -103,7 +105,7 @@ public class TraceAsyncListenableTaskExecutorTest {
|
||||
};
|
||||
}
|
||||
|
||||
Callable aCallable() {
|
||||
Callable<?> aCallable() {
|
||||
return () -> null;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import static junitparams.JUnitParamsRunner.$;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
@@ -54,19 +56,25 @@ import com.netflix.loadbalancer.Server;
|
||||
import junitparams.JUnitParamsRunner;
|
||||
import junitparams.Parameters;
|
||||
|
||||
import static junitparams.JUnitParamsRunner.$;
|
||||
|
||||
@RunWith(JUnitParamsRunner.class)
|
||||
@SpringApplicationConfiguration(classes = { WebClientExceptionTests.TestConfiguration.class })
|
||||
@WebIntegrationTest(value = { "spring.application.name=exceptionservice" }, randomPort = true)
|
||||
@SpringApplicationConfiguration(classes = {
|
||||
WebClientExceptionTests.TestConfiguration.class })
|
||||
@WebIntegrationTest(value = {
|
||||
"spring.application.name=exceptionservice" }, randomPort = true)
|
||||
public class WebClientExceptionTests {
|
||||
|
||||
@ClassRule public static final SpringClassRule SCR = new SpringClassRule();
|
||||
@Rule public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Autowired TestFeignInterfaceWithException testFeignInterfaceWithException;
|
||||
@Autowired @LoadBalanced RestTemplate template;
|
||||
@Autowired Tracer tracer;
|
||||
@ClassRule
|
||||
public static final SpringClassRule SCR = new SpringClassRule();
|
||||
@Rule
|
||||
public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Autowired
|
||||
TestFeignInterfaceWithException testFeignInterfaceWithException;
|
||||
@Autowired
|
||||
@LoadBalanced
|
||||
RestTemplate template;
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
@@ -76,14 +84,15 @@ public class WebClientExceptionTests {
|
||||
// issue #198
|
||||
@Test
|
||||
@Parameters
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldCloseSpanUponException(ResponseEntityProvider provider) throws IOException {
|
||||
public void shouldCloseSpanUponException(ResponseEntityProvider provider)
|
||||
throws IOException {
|
||||
Span span = this.tracer.createSpan("new trace");
|
||||
|
||||
try {
|
||||
provider.get(this);
|
||||
Assert.fail("should throw an exception");
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
SleuthAssertions.then(e).hasRootCauseInstanceOf(IOException.class);
|
||||
}
|
||||
|
||||
@@ -91,9 +100,12 @@ public class WebClientExceptionTests {
|
||||
this.tracer.close(span);
|
||||
}
|
||||
|
||||
private Object[] parametersForShouldCloseSpanUponException() {
|
||||
return $((ResponseEntityProvider) (tests) -> tests.testFeignInterfaceWithException.shouldFailToConnect(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template.getForEntity("http://exceptionservice/", Map.class));
|
||||
Object[] parametersForShouldCloseSpanUponException() {
|
||||
return $(
|
||||
(ResponseEntityProvider) (tests) -> tests.testFeignInterfaceWithException
|
||||
.shouldFailToConnect(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template
|
||||
.getForEntity("http://exceptionservice/", Map.class));
|
||||
}
|
||||
|
||||
@FeignClient("exceptionservice")
|
||||
@@ -111,19 +123,18 @@ public class WebClientExceptionTests {
|
||||
@LoadBalanced
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
public static class ExceptionServiceRibbonClientConfiguration {
|
||||
|
||||
@Bean
|
||||
public ILoadBalancer exceptionServiceRibbonLoadBalancer() {
|
||||
BaseLoadBalancer balancer = new BaseLoadBalancer();
|
||||
balancer.setServersList(
|
||||
Collections.singletonList(new Server("invalid.host.to.break.tests", 1234)));
|
||||
balancer.setServersList(Collections
|
||||
.singletonList(new Server("invalid.host.to.break.tests", 1234)));
|
||||
return balancer;
|
||||
}
|
||||
|
||||
@@ -131,6 +142,6 @@ public class WebClientExceptionTests {
|
||||
|
||||
@FunctionalInterface
|
||||
interface ResponseEntityProvider {
|
||||
ResponseEntity get(WebClientExceptionTests webClientTests);
|
||||
ResponseEntity<?> get(WebClientExceptionTests webClientTests);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import static junitparams.JUnitParamsRunner.$;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -61,21 +65,25 @@ import com.netflix.loadbalancer.Server;
|
||||
import junitparams.JUnitParamsRunner;
|
||||
import junitparams.Parameters;
|
||||
|
||||
import static junitparams.JUnitParamsRunner.$;
|
||||
import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then;
|
||||
|
||||
@RunWith(JUnitParamsRunner.class)
|
||||
@SpringApplicationConfiguration(classes = { WebClientTests.TestConfiguration.class })
|
||||
@WebIntegrationTest(value = { "spring.application.name=fooservice" }, randomPort = true)
|
||||
public class WebClientTests {
|
||||
|
||||
@ClassRule public static final SpringClassRule SCR = new SpringClassRule();
|
||||
@Rule public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Autowired TestFeignInterface testFeignInterface;
|
||||
@Autowired @LoadBalanced RestTemplate template;
|
||||
@Autowired Listener listener;
|
||||
@Autowired Tracer tracer;
|
||||
@ClassRule
|
||||
public static final SpringClassRule SCR = new SpringClassRule();
|
||||
@Rule
|
||||
public final SpringMethodRule springMethodRule = new SpringMethodRule();
|
||||
|
||||
@Autowired
|
||||
TestFeignInterface testFeignInterface;
|
||||
@Autowired
|
||||
@LoadBalanced
|
||||
RestTemplate template;
|
||||
@Autowired
|
||||
Listener listener;
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
@@ -86,7 +94,8 @@ public class WebClientTests {
|
||||
@Test
|
||||
@Parameters
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldCreateANewSpanWhenNoPreviousTracingWasPresent(ResponseEntityProvider provider) {
|
||||
public void shouldCreateANewSpanWhenNoPreviousTracingWasPresent(
|
||||
ResponseEntityProvider provider) {
|
||||
ResponseEntity<String> response = provider.get(this);
|
||||
|
||||
then(getHeader(response, Span.TRACE_ID_NAME)).isNotNull();
|
||||
@@ -94,9 +103,11 @@ public class WebClientTests {
|
||||
then(this.listener.getEvents()).isNotEmpty();
|
||||
}
|
||||
|
||||
private Object[] parametersForShouldCreateANewSpanWhenNoPreviousTracingWasPresent() {
|
||||
return $((ResponseEntityProvider) (tests) -> tests.testFeignInterface.getNoTrace(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template.getForEntity("http://fooservice/notrace", String.class));
|
||||
Object[] parametersForShouldCreateANewSpanWhenNoPreviousTracingWasPresent() {
|
||||
return $(
|
||||
(ResponseEntityProvider) (tests) -> tests.testFeignInterface.getNoTrace(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template
|
||||
.getForEntity("http://fooservice/notrace", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,15 +126,17 @@ public class WebClientTests {
|
||||
then(this.listener.getEvents()).isNotEmpty();
|
||||
}
|
||||
|
||||
private Object[] parametersForShouldPropagateNotSamplingHeader() {
|
||||
Object[] parametersForShouldPropagateNotSamplingHeader() {
|
||||
return $((ResponseEntityProvider) (tests) -> tests.testFeignInterface.headers(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template.getForEntity("http://fooservice/", Map.class));
|
||||
(ResponseEntityProvider) (tests) -> tests.template
|
||||
.getForEntity("http://fooservice/", Map.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Parameters
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldAttachTraceIdWhenCallingAnotherService(ResponseEntityProvider provider) {
|
||||
public void shouldAttachTraceIdWhenCallingAnotherService(
|
||||
ResponseEntityProvider provider) {
|
||||
Long currentTraceId = 1L;
|
||||
Long currentParentId = 2L;
|
||||
Long currentSpanId = 100L;
|
||||
@@ -139,29 +152,29 @@ public class WebClientTests {
|
||||
}
|
||||
|
||||
private Span spanWithClientEvents() {
|
||||
return this.listener.getEvents()
|
||||
.stream()
|
||||
.filter(span -> span.logs()
|
||||
.stream()
|
||||
.filter(log -> log.getEvent().contains(Span.CLIENT_RECV) || log.getEvent().contains(Span.CLIENT_SEND))
|
||||
return this.listener.getEvents().stream()
|
||||
.filter(span -> span.logs().stream()
|
||||
.filter(log -> log.getEvent().contains(Span.CLIENT_RECV)
|
||||
|| log.getEvent().contains(Span.CLIENT_SEND))
|
||||
.findFirst().isPresent())
|
||||
.findFirst().get();
|
||||
}
|
||||
|
||||
private Object[] parametersForShouldAttachTraceIdWhenCallingAnotherService() {
|
||||
Object[] parametersForShouldAttachTraceIdWhenCallingAnotherService() {
|
||||
return $((ResponseEntityProvider) (tests) -> tests.testFeignInterface.headers(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template.getForEntity("http://fooservice/traceid", String.class));
|
||||
(ResponseEntityProvider) (tests) -> tests.template
|
||||
.getForEntity("http://fooservice/traceid", String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Parameters
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldAttachTraceIdWhenUsingFeignClientWithoutResponseBody(ResponseEntityProvider provider) {
|
||||
public void shouldAttachTraceIdWhenUsingFeignClientWithoutResponseBody(
|
||||
ResponseEntityProvider provider) {
|
||||
Long currentTraceId = 1L;
|
||||
Long currentParentId = 2L;
|
||||
Long currentSpanId = generatedId();
|
||||
Span span = Span.builder().traceId(currentTraceId)
|
||||
.spanId(currentSpanId).parent(currentParentId).build();
|
||||
Span span = Span.builder().traceId(currentTraceId).spanId(currentSpanId)
|
||||
.parent(currentParentId).build();
|
||||
this.tracer.continueSpan(span);
|
||||
|
||||
provider.get(this);
|
||||
@@ -170,9 +183,12 @@ public class WebClientTests {
|
||||
thenRegisteredClientSentAndReceivedEvents(spanWithClientEvents());
|
||||
}
|
||||
|
||||
private Object[] parametersForShouldAttachTraceIdWhenUsingFeignClientWithoutResponseBody() {
|
||||
return $((ResponseEntityProvider) (tests) -> tests.testFeignInterface.noResponseBody(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template.getForEntity("http://fooservice/noresponse", String.class));
|
||||
Object[] parametersForShouldAttachTraceIdWhenUsingFeignClientWithoutResponseBody() {
|
||||
return $(
|
||||
(ResponseEntityProvider) (tests) -> tests.testFeignInterface
|
||||
.noResponseBody(),
|
||||
(ResponseEntityProvider) (tests) -> tests.template
|
||||
.getForEntity("http://fooservice/noresponse", String.class));
|
||||
}
|
||||
|
||||
private void thenRegisteredClientSentAndReceivedEvents(Span span) {
|
||||
@@ -223,7 +239,7 @@ public class WebClientTests {
|
||||
@LoadBalanced
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,7 +260,8 @@ public class WebClientTests {
|
||||
@RestController
|
||||
public static class FooController {
|
||||
|
||||
@Autowired Tracer tracer;
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@RequestMapping(value = "/notrace", method = RequestMethod.GET)
|
||||
public String notrace(
|
||||
@@ -299,6 +316,7 @@ public class WebClientTests {
|
||||
|
||||
@FunctionalInterface
|
||||
interface ResponseEntityProvider {
|
||||
@SuppressWarnings("rawtypes")
|
||||
ResponseEntity get(WebClientTests webClientTests);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.zuul;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -31,74 +36,65 @@ import org.springframework.cloud.sleuth.Tracer;
|
||||
import com.netflix.client.http.HttpRequest;
|
||||
import com.netflix.niws.client.http.RestClient;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class TraceRestClientRibbonCommandFactoryTest {
|
||||
|
||||
@Mock Tracer tracer;
|
||||
@Mock SpringClientFactory springClientFactory;
|
||||
@Mock
|
||||
Tracer tracer;
|
||||
@Mock
|
||||
SpringClientFactory springClientFactory;
|
||||
SpanInjector<HttpRequest.Builder> spanInjector = new RequestBuilderContextInjector();
|
||||
TraceRestClientRibbonCommandFactory traceRestClientRibbonCommandFactory;
|
||||
|
||||
@Before
|
||||
@SuppressWarnings({"deprecation", "unchecked"})
|
||||
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||
public void setup() {
|
||||
this.traceRestClientRibbonCommandFactory = new TraceRestClientRibbonCommandFactory(
|
||||
this.springClientFactory, this.tracer, this.spanInjector);
|
||||
given(this.springClientFactory.getClient(anyString(), any(Class.class))).willReturn(new RestClient());
|
||||
Span span = Span.builder()
|
||||
.name("name")
|
||||
.spanId(1L)
|
||||
.traceId(2L)
|
||||
.parent(3L)
|
||||
.processId("processId")
|
||||
.build();
|
||||
given(this.springClientFactory.getClient(anyString(), any(Class.class)))
|
||||
.willReturn(new RestClient());
|
||||
Span span = Span.builder().name("name").spanId(1L).traceId(2L).parent(3L)
|
||||
.processId("processId").build();
|
||||
given(this.tracer.getCurrentSpan()).willReturn(span);
|
||||
given(this.tracer.isTracing()).willReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_wrap_ribbon_command_in_a_sleuth_representation() throws Exception {
|
||||
RestClientRibbonCommand restClientRibbonCommand =
|
||||
this.traceRestClientRibbonCommandFactory.create(ribbonCommandContext());
|
||||
RestClientRibbonCommand restClientRibbonCommand = this.traceRestClientRibbonCommandFactory
|
||||
.create(ribbonCommandContext());
|
||||
|
||||
then(restClientRibbonCommand)
|
||||
.isInstanceOf(TraceRestClientRibbonCommandFactory.TraceRestClientRibbonCommand.class);
|
||||
then(restClientRibbonCommand).isInstanceOf(
|
||||
TraceRestClientRibbonCommandFactory.TraceRestClientRibbonCommand.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_attach_trace_headers_to_the_sent_request() throws Exception {
|
||||
RestClientRibbonCommand restClientRibbonCommand = this.traceRestClientRibbonCommandFactory.create(ribbonCommandContext());
|
||||
TraceRestClientRibbonCommandFactory.TraceRestClientRibbonCommand traceRestClientRibbonCommand =
|
||||
(TraceRestClientRibbonCommandFactory.TraceRestClientRibbonCommand) restClientRibbonCommand;
|
||||
RestClientRibbonCommand restClientRibbonCommand = this.traceRestClientRibbonCommandFactory
|
||||
.create(ribbonCommandContext());
|
||||
TraceRestClientRibbonCommandFactory.TraceRestClientRibbonCommand traceRestClientRibbonCommand = (TraceRestClientRibbonCommandFactory.TraceRestClientRibbonCommand) restClientRibbonCommand;
|
||||
HttpRequest.Builder builder = new HttpRequest.Builder();
|
||||
|
||||
traceRestClientRibbonCommand.customizeRequest(builder);
|
||||
|
||||
HttpRequest httpRequest = builder.build();
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.SPAN_ID_NAME)).isEqualTo("1");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.TRACE_ID_NAME)).isEqualTo("2");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.SPAN_NAME_NAME)).isEqualTo("name");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.PARENT_ID_NAME)).isEqualTo("3");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.PROCESS_ID_NAME)).isEqualTo("processId");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.SPAN_ID_NAME))
|
||||
.isEqualTo("1");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.TRACE_ID_NAME))
|
||||
.isEqualTo("2");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.SPAN_NAME_NAME))
|
||||
.isEqualTo("name");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.PARENT_ID_NAME))
|
||||
.isEqualTo("3");
|
||||
then(httpRequest.getHttpHeaders().getFirstValue(Span.PROCESS_ID_NAME))
|
||||
.isEqualTo("processId");
|
||||
}
|
||||
|
||||
private RibbonCommandContext ribbonCommandContext() {
|
||||
return new RibbonCommandContext(
|
||||
"serviceId",
|
||||
"GET",
|
||||
"http://localhost:1234/foo",
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
return new RibbonCommandContext("serviceId", "GET", "http://localhost:1234/foo",
|
||||
false, null, null, null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user