31
pom.xml
31
pom.xml
@@ -30,7 +30,6 @@
|
||||
<module>spring-cloud-sleuth-core</module>
|
||||
<module>spring-cloud-sleuth-zipkin</module>
|
||||
<module>spring-cloud-sleuth-stream</module>
|
||||
<module>spring-cloud-sleuth-reactor</module>
|
||||
<module>spring-cloud-sleuth-zipkin-stream</module>
|
||||
<module>spring-cloud-starter-sleuth</module>
|
||||
<module>spring-cloud-starter-zipkin</module>
|
||||
@@ -172,6 +171,21 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- For Reactor -->
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-bom</artifactId>
|
||||
<version>${reactor.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<!-- Spock -->
|
||||
<dependency>
|
||||
<groupId>org.spockframework</groupId>
|
||||
@@ -201,16 +215,6 @@
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<version>${reactor.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reactivestreams</groupId>
|
||||
<artifactId>reactive-streams</artifactId>
|
||||
<version>${reactive-streams.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
<artifactId>hamcrest-core</artifactId>
|
||||
@@ -254,8 +258,9 @@
|
||||
<spring-cloud-commons.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-stream.version>Elmhurst.BUILD-SNAPSHOT</spring-cloud-stream.version>
|
||||
<spring-cloud-netflix.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-netflix.version>
|
||||
<reactor.version>3.1.0.BUILD-SNAPSHOT</reactor.version>
|
||||
<reactive-streams.version>1.0.0</reactive-streams.version>
|
||||
<reactor.version>Bismuth-BUILD-SNAPSHOT</reactor.version>
|
||||
<!-- To make Reactor work -->
|
||||
<spring-boot.version>2.0.0.BUILD-SNAPSHOT</spring-boot.version>
|
||||
</properties>
|
||||
|
||||
<profiles>
|
||||
|
||||
@@ -21,6 +21,21 @@
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reactivestreams</groupId>
|
||||
<artifactId>reactive-streams</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
|
||||
@@ -18,7 +18,8 @@ import reactor.util.context.Context;
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 1.3.0
|
||||
*/
|
||||
class SpanSubscriber extends AtomicBoolean implements Subscription, CoreSubscriber<Object> {
|
||||
class SpanSubscriber extends AtomicBoolean
|
||||
implements Subscription, CoreSubscriber<Object> {
|
||||
|
||||
private static final Logger log = Loggers.getLogger(SpanSubscriber.class);
|
||||
|
||||
@@ -61,29 +62,30 @@ class SpanSubscriber extends AtomicBoolean implements Subscription, CoreSubscrib
|
||||
}
|
||||
|
||||
@Override public void request(long n) {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Request");
|
||||
}
|
||||
this.tracer.continueSpan(this.span);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Request - continued");
|
||||
}
|
||||
this.s.request(n);
|
||||
Span localSpan = this.span;
|
||||
Span rootSpan = this.rootSpan;
|
||||
// We're in the main thread so we don't want to pollute it with wrong spans
|
||||
// that's why we need to detach the current one and continue with its parent
|
||||
Span localRootSpan = this.span;
|
||||
while (localRootSpan != null) {
|
||||
if (this.rootSpan != null) {
|
||||
if (localRootSpan.getSpanId() != this.rootSpan.getSpanId() &&
|
||||
!isRootParentSpan(localRootSpan)) {
|
||||
localRootSpan = continueDetachedSpan(localRootSpan);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Will detach spans. Root span is " + rootSpan + " and stored span is " + localSpan);
|
||||
}
|
||||
while (localSpan != null) {
|
||||
if (rootSpan != null) {
|
||||
if (localSpan.getSpanId() != rootSpan.getSpanId() &&
|
||||
!isRootParentSpan(localSpan)) {
|
||||
localSpan = continueDetachedSpan(localSpan);
|
||||
} else {
|
||||
localRootSpan = null;
|
||||
localSpan = null;
|
||||
}
|
||||
} else if (!isRootParentSpan(localRootSpan)) {
|
||||
localRootSpan = continueDetachedSpan(localRootSpan);
|
||||
} else if (!isRootParentSpan(localSpan)) {
|
||||
localSpan = continueDetachedSpan(localSpan);
|
||||
} else {
|
||||
localRootSpan = null;
|
||||
localSpan = null;
|
||||
}
|
||||
}
|
||||
if (log.isTraceEnabled()) {
|
||||
@@ -101,7 +103,12 @@ class SpanSubscriber extends AtomicBoolean implements Subscription, CoreSubscrib
|
||||
log.trace("Will detach span {}", localRootSpan);
|
||||
}
|
||||
Span detachedSpan = this.tracer.detach(localRootSpan);
|
||||
return this.tracer.continueSpan(detachedSpan);
|
||||
Span continuedSpan = this.tracer.continueSpan(detachedSpan);
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Now current span is " + continuedSpan + ". Root span is " + this.rootSpan +
|
||||
" and stored span for the subscriber is " + this.span);
|
||||
}
|
||||
return continuedSpan;
|
||||
}
|
||||
|
||||
@Override public void cancel() {
|
||||
@@ -8,12 +8,13 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.async.TraceableScheduledExecutorService;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebFluxAutoConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.publisher.Mono;
|
||||
@@ -30,11 +31,12 @@ import reactor.core.scheduler.Schedulers;
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value="spring.sleuth.reactor.enabled", matchIfMissing=true)
|
||||
@ConditionalOnClass(Mono.class)
|
||||
@AutoConfigureAfter(TraceAutoConfiguration.class)
|
||||
@AutoConfigureAfter(TraceWebFluxAutoConfiguration.class)
|
||||
public class TraceReactorAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@ConditionalOnNotWebApplication
|
||||
static class TraceReactorConfiguration {
|
||||
@Autowired Tracer tracer;
|
||||
@Autowired TraceKeys traceKeys;
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.cloud.sleuth.SpanTextMap;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
|
||||
/**
|
||||
* Created by mgrzejszczak.
|
||||
*/
|
||||
class ServerHttpRequestTextMap implements SpanTextMap {
|
||||
|
||||
private final ServerHttpRequest delegate;
|
||||
private final Map<String, String> additionalHeaders = new HashMap<>();
|
||||
|
||||
ServerHttpRequestTextMap(ServerHttpRequest delegate) {
|
||||
this.delegate = delegate;
|
||||
this.additionalHeaders.put(ZipkinHttpSpanExtractor.URI_HEADER,
|
||||
delegate.getPath().pathWithinApplication().value());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (Map.Entry<String, List<String>> entry : this.delegate.getHeaders()
|
||||
.entrySet()) {
|
||||
map.put(entry.getKey(), entry.getValue() != null ?
|
||||
entry.getValue().isEmpty() ? "" : entry.getValue().get(0) : "");
|
||||
}
|
||||
map.putAll(this.additionalHeaders);
|
||||
return map.entrySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, String value) {
|
||||
this.additionalHeaders.put(key, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Internal interface to describe patterns to skip tracing
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.0
|
||||
*/
|
||||
interface SkipPatternProvider {
|
||||
Pattern skipPattern();
|
||||
}
|
||||
@@ -65,7 +65,7 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
*
|
||||
* @see Tracer
|
||||
* @see TraceKeys
|
||||
* @see TraceWebAutoConfiguration#traceFilter
|
||||
* @see TraceWebServletAutoConfiguration#traceFilter
|
||||
*/
|
||||
@Order(TraceFilter.ORDER)
|
||||
public class TraceFilter extends GenericFilterBean {
|
||||
@@ -92,12 +92,12 @@ public class TraceFilter extends GenericFilterBean {
|
||||
|
||||
private Tracer tracer;
|
||||
private TraceKeys traceKeys;
|
||||
private Pattern skipPattern;
|
||||
private final Pattern skipPattern;
|
||||
private SpanReporter spanReporter;
|
||||
private HttpSpanExtractor spanExtractor;
|
||||
private HttpTraceKeysInjector httpTraceKeysInjector;
|
||||
private ErrorParser errorParser;
|
||||
private BeanFactory beanFactory;
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -27,79 +26,26 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClas
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.cloud.sleuth.ErrorParser;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import static javax.servlet.DispatcherType.ASYNC;
|
||||
import static javax.servlet.DispatcherType.ERROR;
|
||||
import static javax.servlet.DispatcherType.FORWARD;
|
||||
import static javax.servlet.DispatcherType.INCLUDE;
|
||||
import static javax.servlet.DispatcherType.REQUEST;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} enables tracing to HTTP requests.
|
||||
* Auto-configuration} that sets up common building blocks for both reactive
|
||||
* and servlet based web application.
|
||||
*
|
||||
* @author Tomasz Nurkewicz, 4financeIT
|
||||
* @author Michal Chmielarz, 4financeIT
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Spencer Gibb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.sleuth.web.enabled", matchIfMissing = true)
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.ANY)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter(TraceHttpAutoConfiguration.class)
|
||||
public class TraceWebAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Nested config that configures Web MVC if it's present (without adding a runtime
|
||||
* dependency to it)
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(WebMvcConfigurerAdapter.class)
|
||||
@Import(TraceWebMvcConfigurer.class)
|
||||
protected static class TraceWebMvcAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TraceWebAspect traceWebAspect(Tracer tracer, TraceKeys traceKeys,
|
||||
SpanNamer spanNamer, ErrorParser errorParser) {
|
||||
return new TraceWebAspect(tracer, spanNamer, traceKeys, errorParser);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping")
|
||||
public TraceSpringDataBeanPostProcessor traceSpringDataBeanPostProcessor(
|
||||
BeanFactory beanFactory) {
|
||||
return new TraceSpringDataBeanPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean traceWebFilter(TraceFilter traceFilter) {
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(
|
||||
traceFilter);
|
||||
filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE,
|
||||
REQUEST);
|
||||
filterRegistrationBean.setOrder(TraceFilter.ORDER);
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TraceFilter traceFilter(BeanFactory beanFactory,
|
||||
SkipPatternProvider skipPatternProvider) {
|
||||
return new TraceFilter(beanFactory, skipPatternProvider.skipPattern());
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ManagementServerProperties.class)
|
||||
@ConditionalOnMissingBean(SkipPatternProvider.class)
|
||||
@@ -157,12 +103,7 @@ public class TraceWebAutoConfiguration {
|
||||
|
||||
private static SkipPatternProvider defaultSkipPatternProvider(
|
||||
final String skipPattern) {
|
||||
return new SkipPatternProvider() {
|
||||
@Override
|
||||
public Pattern skipPattern() {
|
||||
return defaultSkipPattern(skipPattern);
|
||||
}
|
||||
};
|
||||
return () -> defaultSkipPattern(skipPattern);
|
||||
}
|
||||
|
||||
private static Pattern defaultSkipPattern(String skipPattern) {
|
||||
@@ -170,7 +111,5 @@ public class TraceWebAutoConfiguration {
|
||||
: Pattern.compile(SleuthWebProperties.DEFAULT_SKIP_PATTERN);
|
||||
}
|
||||
|
||||
interface SkipPatternProvider {
|
||||
Pattern skipPattern();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,262 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.cloud.sleuth.ErrorParser;
|
||||
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.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.sampler.NeverSampler;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* A {@link WebFilter} that creates / continues / closes and detaches spans
|
||||
* for a reactive web application.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class TraceWebFilter implements WebFilter {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceWebFilter.class);
|
||||
|
||||
protected static final String TRACE_REQUEST_ATTR = TraceWebFilter.class.getName()
|
||||
+ ".TRACE";
|
||||
private static final String HTTP_COMPONENT = "http";
|
||||
|
||||
private Tracer tracer;
|
||||
private TraceKeys traceKeys;
|
||||
private final Pattern skipPattern;
|
||||
private SpanReporter spanReporter;
|
||||
private HttpSpanExtractor spanExtractor;
|
||||
private HttpTraceKeysInjector httpTraceKeysInjector;
|
||||
private ErrorParser errorParser;
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
TraceWebFilter(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.skipPattern = Pattern.compile(SleuthWebProperties.DEFAULT_SKIP_PATTERN);
|
||||
}
|
||||
|
||||
TraceWebFilter(BeanFactory beanFactory, Pattern skipPattern) {
|
||||
this.beanFactory = beanFactory;
|
||||
this.skipPattern = skipPattern;
|
||||
}
|
||||
|
||||
@Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
String uri = request.getPath().pathWithinApplication().value();
|
||||
boolean skip = this.skipPattern.matcher(uri).matches()
|
||||
|| Span.SPAN_NOT_SAMPLED.equals(sampledHeader(request));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Received a request to uri [" + uri + "] that should not be sampled [" + skip + "]");
|
||||
}
|
||||
Optional<Span> spanFromAttribute = getSpanFromAttribute(exchange);
|
||||
spanFromAttribute.ifPresent(span -> continueSpan(exchange, span));
|
||||
String name = HTTP_COMPONENT + ":" + uri;
|
||||
Span span = createSpan(request, exchange, skip, spanFromAttribute, name);
|
||||
return chain.filter(exchange).compose(f -> f.doOnSuccess(t -> {
|
||||
addResponseTags(response, null);
|
||||
}).doOnError(t -> {
|
||||
errorParser().parseErrorTags(tracer().getCurrentSpan(), t);
|
||||
addResponseTags(response, t);
|
||||
}).doFinally(t -> detachOrCloseSpans(span)));
|
||||
}
|
||||
|
||||
private String sampledHeader(ServerHttpRequest request) {
|
||||
return getHeader(request, Span.SAMPLED_NAME);
|
||||
}
|
||||
|
||||
private void continueSpan(ServerWebExchange exchange, Span spanFromRequest) {
|
||||
tracer().continueSpan(spanFromRequest);
|
||||
exchange.getAttributes().put(TraceRequestAttributes.SPAN_CONTINUED_REQUEST_ATTR, "true");
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("There has already been a span in the request " + spanFromRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a span and appends it as the current request's attribute
|
||||
*/
|
||||
private Span createSpan(ServerHttpRequest request, ServerWebExchange exchange,
|
||||
boolean skip, Optional<Span> spanFromAttribute, String name) {
|
||||
Span spanFromRequest = null;
|
||||
if (spanFromAttribute.isPresent()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Span has already been created - continuing with the previous one");
|
||||
}
|
||||
return spanFromAttribute.get();
|
||||
}
|
||||
Span parent = spanExtractor().joinTrace(new ServerHttpRequestTextMap(request));
|
||||
if (parent != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Found a parent span " + parent + " in the request");
|
||||
}
|
||||
addRequestTagsForParentSpan(request, parent);
|
||||
spanFromRequest = parent;
|
||||
tracer().continueSpan(spanFromRequest);
|
||||
if (parent.isRemote()) {
|
||||
parent.logEvent(Span.SERVER_RECV);
|
||||
}
|
||||
exchange.getAttributes().put(TRACE_REQUEST_ATTR, spanFromRequest);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Parent span is " + parent + "");
|
||||
}
|
||||
} else {
|
||||
if (skip) {
|
||||
spanFromRequest = tracer().createSpan(name, NeverSampler.INSTANCE);
|
||||
}
|
||||
else {
|
||||
String header = getHeader(request, Span.SPAN_FLAGS);
|
||||
if (Span.SPAN_SAMPLED.equals(header)) {
|
||||
spanFromRequest = tracer().createSpan(name, new AlwaysSampler());
|
||||
} else {
|
||||
spanFromRequest = tracer().createSpan(name);
|
||||
}
|
||||
}
|
||||
spanFromRequest.logEvent(Span.SERVER_RECV);
|
||||
exchange.getAttributes().put(TRACE_REQUEST_ATTR, spanFromRequest);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No parent span present - creating a new span");
|
||||
}
|
||||
}
|
||||
return spanFromRequest;
|
||||
}
|
||||
|
||||
private String getHeader(ServerHttpRequest request, String headerName) {
|
||||
List<String> list = request.getHeaders().get(headerName);
|
||||
return list == null ? "" : list.isEmpty() ? "" : list.get(0);
|
||||
}
|
||||
|
||||
/** Override to add annotations not defined in {@link TraceKeys}. */
|
||||
protected void addRequestTags(Span span, ServerHttpRequest request) {
|
||||
keysInjector().addRequestTags(span, request.getURI(), request.getMethod().toString());
|
||||
for (String name : traceKeys().getHttp().getHeaders()) {
|
||||
List<String> values = request.getHeaders().get(name);
|
||||
if (values != null && !values.isEmpty()) {
|
||||
String key = traceKeys().getHttp().getPrefix() + name.toLowerCase();
|
||||
String value = values.size() == 1 ? values.get(0)
|
||||
: StringUtils.collectionToDelimitedString(values, ",", "'", "'");
|
||||
keysInjector().tagSpan(span, key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Override to add annotations not defined in {@link TraceKeys}. */
|
||||
protected void addResponseTags(ServerHttpResponse response, Throwable e) {
|
||||
HttpStatus httpStatus = response.getStatusCode();
|
||||
if (httpStatus != null && httpStatus == HttpStatus.OK && e != null) {
|
||||
// Filter chain threw exception but the response status may not have been set
|
||||
// yet, so we have to guess.
|
||||
tracer().addTag(traceKeys().getHttp().getStatusCode(),
|
||||
String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
||||
}
|
||||
// only tag valid http statuses
|
||||
else if (httpStatus != null &&
|
||||
(httpStatus.value() >= 100 && (httpStatus.value() < 200) || (httpStatus.value() > 399))) {
|
||||
tracer().addTag(traceKeys().getHttp().getStatusCode(),
|
||||
String.valueOf(response.getStatusCode().value()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* In order not to send unnecessary data we're not adding request tags to the server
|
||||
* side spans. All the tags are there on the client side.
|
||||
*/
|
||||
private void addRequestTagsForParentSpan(ServerHttpRequest request, Span spanFromRequest) {
|
||||
if (spanFromRequest.getName().contains("parent")) {
|
||||
addRequestTags(spanFromRequest, request);
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<Span> getSpanFromAttribute(ServerWebExchange exchange) {
|
||||
Optional<Span> attribute = exchange.getAttribute(TRACE_REQUEST_ATTR);
|
||||
return attribute == null ? Optional.ofNullable(null) : attribute;
|
||||
}
|
||||
|
||||
private void detachOrCloseSpans(Span spanFromRequest) {
|
||||
Span span = spanFromRequest;
|
||||
if (span != null) {
|
||||
if (span.hasSavedSpan()) {
|
||||
recordParentSpan(span.getSavedSpan());
|
||||
}
|
||||
recordParentSpan(span);
|
||||
tracer().close(span);
|
||||
}
|
||||
}
|
||||
|
||||
private void recordParentSpan(Span parent) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
if (parent.isRemote()) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Trying to send the parent span " + parent + " to Zipkin");
|
||||
}
|
||||
parent.stop();
|
||||
// should be already done by HttpServletResponse wrappers
|
||||
SsLogSetter.annotateWithServerSendIfLogIsNotAlreadyPresent(parent);
|
||||
spanReporter().report(parent);
|
||||
} else {
|
||||
// should be already done by HttpServletResponse wrappers
|
||||
SsLogSetter.annotateWithServerSendIfLogIsNotAlreadyPresent(parent);
|
||||
}
|
||||
}
|
||||
|
||||
Tracer tracer() {
|
||||
if (this.tracer == null) {
|
||||
this.tracer = this.beanFactory.getBean(Tracer.class);
|
||||
}
|
||||
return this.tracer;
|
||||
}
|
||||
|
||||
TraceKeys traceKeys() {
|
||||
if (this.traceKeys == null) {
|
||||
this.traceKeys = this.beanFactory.getBean(TraceKeys.class);
|
||||
}
|
||||
return this.traceKeys;
|
||||
}
|
||||
|
||||
SpanReporter spanReporter() {
|
||||
if (this.spanReporter == null) {
|
||||
this.spanReporter = this.beanFactory.getBean(SpanReporter.class);
|
||||
}
|
||||
return this.spanReporter;
|
||||
}
|
||||
|
||||
HttpSpanExtractor spanExtractor() {
|
||||
if (this.spanExtractor == null) {
|
||||
this.spanExtractor = this.beanFactory.getBean(HttpSpanExtractor.class);
|
||||
}
|
||||
return this.spanExtractor;
|
||||
}
|
||||
|
||||
HttpTraceKeysInjector keysInjector() {
|
||||
if (this.httpTraceKeysInjector == null) {
|
||||
this.httpTraceKeysInjector = this.beanFactory.getBean(HttpTraceKeysInjector.class);
|
||||
}
|
||||
return this.httpTraceKeysInjector;
|
||||
}
|
||||
|
||||
ErrorParser errorParser() {
|
||||
if (this.errorParser == null) {
|
||||
this.errorParser = this.beanFactory.getBean(ErrorParser.class);
|
||||
}
|
||||
return this.errorParser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} enables tracing to HTTP requests with Spring WebFlux.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.sleuth.web.enabled", matchIfMissing = true)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter(TraceWebAutoConfiguration.class)
|
||||
public class TraceWebFluxAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public TraceWebFilter traceFilter(BeanFactory beanFactory,
|
||||
SkipPatternProvider skipPatternProvider) {
|
||||
return new TraceWebFilter(beanFactory, skipPatternProvider.skipPattern());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
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.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.cloud.sleuth.ErrorParser;
|
||||
import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
|
||||
|
||||
import static javax.servlet.DispatcherType.ASYNC;
|
||||
import static javax.servlet.DispatcherType.ERROR;
|
||||
import static javax.servlet.DispatcherType.FORWARD;
|
||||
import static javax.servlet.DispatcherType.INCLUDE;
|
||||
import static javax.servlet.DispatcherType.REQUEST;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
* Auto-configuration} enables tracing to HTTP requests.
|
||||
*
|
||||
* @author Tomasz Nurkewicz, 4financeIT
|
||||
* @author Michal Chmielarz, 4financeIT
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Spencer Gibb
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "spring.sleuth.web.enabled", matchIfMissing = true)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter(TraceHttpAutoConfiguration.class)
|
||||
public class TraceWebServletAutoConfiguration {
|
||||
|
||||
/**
|
||||
* Nested config that configures Web MVC if it's present (without adding a runtime
|
||||
* dependency to it)
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnClass(WebMvcConfigurerAdapter.class)
|
||||
@Import(TraceWebMvcConfigurer.class)
|
||||
protected static class TraceWebMvcAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TraceWebAspect traceWebAspect(Tracer tracer, TraceKeys traceKeys,
|
||||
SpanNamer spanNamer, ErrorParser errorParser) {
|
||||
return new TraceWebAspect(tracer, spanNamer, traceKeys, errorParser);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping")
|
||||
public TraceSpringDataBeanPostProcessor traceSpringDataBeanPostProcessor(
|
||||
BeanFactory beanFactory) {
|
||||
return new TraceSpringDataBeanPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FilterRegistrationBean traceWebFilter(TraceFilter traceFilter) {
|
||||
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(
|
||||
traceFilter);
|
||||
filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE,
|
||||
REQUEST);
|
||||
filterRegistrationBean.setOrder(TraceFilter.ORDER);
|
||||
return filterRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TraceFilter traceFilter(BeanFactory beanFactory,
|
||||
SkipPatternProvider skipPatternProvider) {
|
||||
return new TraceFilter(beanFactory, skipPatternProvider.skipPattern());
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import org.springframework.cloud.sleuth.ErrorParser;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpSpanInjector;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
@@ -49,7 +49,7 @@ import org.springframework.web.client.AsyncRestTemplate;
|
||||
@ConditionalOnProperty(value = "spring.sleuth.web.async.client.enabled", matchIfMissing = true)
|
||||
@ConditionalOnClass(AsyncRestTemplate.class)
|
||||
@ConditionalOnBean(HttpTraceKeysInjector.class)
|
||||
@AutoConfigureAfter(TraceWebAutoConfiguration.class)
|
||||
@AutoConfigureAfter(TraceWebServletAutoConfiguration.class)
|
||||
public class TraceWebAsyncClientAutoConfiguration {
|
||||
|
||||
@Autowired Tracer tracer;
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Collection;
|
||||
import java.util.List;
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -30,11 +31,12 @@ import org.springframework.cloud.sleuth.ErrorParser;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpSpanInjector;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||
@@ -46,39 +48,50 @@ import org.springframework.web.client.RestTemplate;
|
||||
*/
|
||||
@Configuration
|
||||
@SleuthWebClientEnabled
|
||||
@ConditionalOnClass(RestTemplate.class)
|
||||
@ConditionalOnBean(HttpTraceKeysInjector.class)
|
||||
@AutoConfigureAfter(TraceWebAutoConfiguration.class)
|
||||
@AutoConfigureAfter(TraceWebServletAutoConfiguration.class)
|
||||
public class TraceWebClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceRestTemplateInterceptor traceRestTemplateInterceptor(Tracer tracer,
|
||||
HttpSpanInjector spanInjector, HttpTraceKeysInjector httpTraceKeysInjector,
|
||||
ErrorParser errorParser) {
|
||||
return new TraceRestTemplateInterceptor(tracer, spanInjector,
|
||||
httpTraceKeysInjector, errorParser);
|
||||
}
|
||||
@ConditionalOnClass(RestTemplate.class)
|
||||
static class RestTemplateConfig {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TraceRestTemplateInterceptor traceRestTemplateInterceptor(Tracer tracer,
|
||||
HttpSpanInjector spanInjector, HttpTraceKeysInjector httpTraceKeysInjector,
|
||||
ErrorParser errorParser) {
|
||||
return new TraceRestTemplateInterceptor(tracer, spanInjector,
|
||||
httpTraceKeysInjector, errorParser);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class TraceInterceptorConfiguration {
|
||||
@Configuration
|
||||
protected static class TraceInterceptorConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
private Collection<RestTemplate> restTemplates;
|
||||
@Autowired(required = false)
|
||||
private Collection<RestTemplate> restTemplates;
|
||||
|
||||
@Autowired
|
||||
private TraceRestTemplateInterceptor traceRestTemplateInterceptor;
|
||||
@Autowired
|
||||
private TraceRestTemplateInterceptor traceRestTemplateInterceptor;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (this.restTemplates != null) {
|
||||
for (RestTemplate restTemplate : this.restTemplates) {
|
||||
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>(
|
||||
restTemplate.getInterceptors());
|
||||
interceptors.add(this.traceRestTemplateInterceptor);
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
if (this.restTemplates != null) {
|
||||
for (RestTemplate restTemplate : this.restTemplates) {
|
||||
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>(
|
||||
restTemplate.getInterceptors());
|
||||
interceptors.add(this.traceRestTemplateInterceptor);
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
static class WebClientConfig {
|
||||
|
||||
@Bean
|
||||
TraceWebClientBeanPostProcessor traceWebClientBeanPostProcessor(BeanFactory beanFactory) {
|
||||
return new TraceWebClientBeanPostProcessor(beanFactory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.cloud.sleuth.ErrorParser;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanTextMap;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpSpanInjector;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
|
||||
import org.springframework.cloud.sleuth.util.SpanNameUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFunction;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} to wrap a {@link WebClient} instance into
|
||||
* its trace representation
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class TraceWebClientBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
TraceWebClientBeanPostProcessor(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof WebClient) {
|
||||
WebClient webClient = (WebClient) bean;
|
||||
return webClient
|
||||
.mutate()
|
||||
.filter(new TraceExchangeFilterFunction(this.beanFactory))
|
||||
.build();
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceExchangeFilterFunction.class);
|
||||
|
||||
private Tracer tracer;
|
||||
private HttpSpanInjector spanInjector;
|
||||
private HttpTraceKeysInjector keysInjector;
|
||||
private ErrorParser errorParser;
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
TraceExchangeFilterFunction(BeanFactory beanFactory) {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override public Mono<ClientResponse> filter(ClientRequest request,
|
||||
ExchangeFunction next) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Creating a client span for the RPC");
|
||||
}
|
||||
final Span clientSpan = createNewSpan(request);
|
||||
ClientRequest.Builder builder = ClientRequest.from(request);
|
||||
httpSpanInjector().inject(clientSpan, new ClientRequestTextMap(request, builder));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Headers got injected to the client span " + clientSpan);
|
||||
}
|
||||
Mono<ClientResponse> exchange = next.exchange(builder.build())
|
||||
.doOnError(throwable -> {
|
||||
tracer().continueSpan(clientSpan);
|
||||
errorParser().parseErrorTags(clientSpan, throwable);
|
||||
}).doOnSuccess(response -> {
|
||||
tracer().continueSpan(clientSpan);
|
||||
boolean error = response.statusCode().is4xxClientError() || response
|
||||
.statusCode().is5xxServerError();
|
||||
if (error) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(
|
||||
"Non positive status code was returned from the call. Will close the span ["
|
||||
+ clientSpan + "]");
|
||||
}
|
||||
errorParser().parseErrorTags(clientSpan, new RestClientException(
|
||||
"Status code of the response is [" + response.statusCode()
|
||||
.value() + "] and the reason is [" + response
|
||||
.statusCode().getReasonPhrase() + "]"));
|
||||
}
|
||||
}).doFinally(signalType -> finish(clientSpan));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will detach the client span " + clientSpan);
|
||||
}
|
||||
Span detachedSpan = tracer().detach(clientSpan);
|
||||
tracer().continueSpan(detachedSpan);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Client span detached");
|
||||
}
|
||||
return exchange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enriches the request with proper headers and publishes
|
||||
* the client sent event
|
||||
*/
|
||||
private Span createNewSpan(ClientRequest request) {
|
||||
URI uri = request.url();
|
||||
String spanName = getName(uri);
|
||||
Span newSpan = tracer().createSpan(spanName);
|
||||
addRequestTags(request);
|
||||
newSpan.logEvent(Span.CLIENT_SEND);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Starting new client span [" + newSpan + "]");
|
||||
}
|
||||
return newSpan;
|
||||
}
|
||||
|
||||
private String getName(URI uri) {
|
||||
return SpanNameUtil.shorten(uriScheme(uri) + ":" + uri.getPath());
|
||||
}
|
||||
|
||||
private String uriScheme(URI uri) {
|
||||
return uri.getScheme() == null ? "http" : uri.getScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds HTTP tags to the client side span
|
||||
*/
|
||||
private void addRequestTags(ClientRequest request) {
|
||||
keysInjector().addRequestTags(request.url().toString(),
|
||||
request.url().getHost(),
|
||||
request.url().getPath(),
|
||||
request.method().name(),
|
||||
request.headers());
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the current span and log the client received event
|
||||
*/
|
||||
private void finish(Span span) {
|
||||
tracer().continueSpan(span);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Will close span and mark it with Client Received" + span);
|
||||
}
|
||||
span.logEvent(Span.CLIENT_RECV);
|
||||
tracer().close(span);
|
||||
}
|
||||
|
||||
private Tracer tracer() {
|
||||
if (this.tracer == null) {
|
||||
this.tracer = this.beanFactory.getBean(Tracer.class);
|
||||
}
|
||||
return this.tracer;
|
||||
}
|
||||
|
||||
private HttpSpanInjector httpSpanInjector() {
|
||||
if (this.spanInjector == null) {
|
||||
this.spanInjector = this.beanFactory.getBean(HttpSpanInjector.class);
|
||||
}
|
||||
return this.spanInjector;
|
||||
}
|
||||
|
||||
private HttpTraceKeysInjector keysInjector() {
|
||||
if (this.keysInjector == null) {
|
||||
this.keysInjector = this.beanFactory.getBean(HttpTraceKeysInjector.class);
|
||||
}
|
||||
return this.keysInjector;
|
||||
}
|
||||
|
||||
private ErrorParser errorParser() {
|
||||
if (this.errorParser == null) {
|
||||
this.errorParser = this.beanFactory.getBean(ErrorParser.class);
|
||||
}
|
||||
return this.errorParser;
|
||||
}
|
||||
}
|
||||
|
||||
class ClientRequestTextMap implements SpanTextMap {
|
||||
|
||||
private final ClientRequest.Builder writeDelegate;
|
||||
private final ClientRequest readDelegate;
|
||||
|
||||
ClientRequestTextMap(ClientRequest readDelegate,
|
||||
ClientRequest.Builder writeDelegate) {
|
||||
this.readDelegate = readDelegate;
|
||||
this.writeDelegate = writeDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<String, String>> iterator() {
|
||||
final Iterator<Map.Entry<String, List<String>>> iterator = this.readDelegate.headers()
|
||||
.entrySet().iterator();
|
||||
return new Iterator<Map.Entry<String, String>>() {
|
||||
@Override public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override public Map.Entry<String, String> next() {
|
||||
Map.Entry<String, List<String>> next = iterator.next();
|
||||
List<String> value = next.getValue();
|
||||
return new AbstractMap.SimpleEntry<>(next.getKey(), value.isEmpty() ? "" : value.get(0));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, String value) {
|
||||
if (!StringUtils.hasText(value)) {
|
||||
return;
|
||||
}
|
||||
this.writeDelegate.header(key, value);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.netflix.feign.FeignAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
@@ -47,7 +47,7 @@ import feign.okhttp.OkHttpClient;
|
||||
@ConditionalOnClass(Client.class)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureBefore(FeignAutoConfiguration.class)
|
||||
@AutoConfigureAfter({SleuthHystrixAutoConfiguration.class, TraceWebAutoConfiguration.class})
|
||||
@AutoConfigureAfter({SleuthHystrixAutoConfiguration.class, TraceWebServletAutoConfiguration.class})
|
||||
public class TraceFeignClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.springframework.cloud.sleuth.instrument.web.HttpSpanInjector;
|
||||
import org.springframework.cloud.sleuth.TraceKeys;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.instrument.web.HttpTraceKeysInjector;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -50,7 +50,7 @@ import okhttp3.Request;
|
||||
@ConditionalOnWebApplication
|
||||
@ConditionalOnClass(ZuulFilter.class)
|
||||
@ConditionalOnBean(Tracer.class)
|
||||
@AutoConfigureAfter(TraceWebAutoConfiguration.class)
|
||||
@AutoConfigureAfter(TraceWebServletAutoConfiguration.class)
|
||||
public class TraceZuulAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -9,9 +9,12 @@ org.springframework.cloud.sleuth.instrument.messaging.websocket.TraceWebSocketAu
|
||||
org.springframework.cloud.sleuth.instrument.async.AsyncCustomAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.async.AsyncDefaultAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.scheduling.TraceSchedulingAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceHttpAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.TraceWebFluxAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.client.TraceWebClientAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.client.TraceWebAsyncClientAutoConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.web.client.feign.TraceFeignClientAutoConfiguration,\
|
||||
|
||||
@@ -272,7 +272,7 @@ public class ListOfSpansAssert extends AbstractAssert<ListOfSpansAssert, ListOfS
|
||||
return this;
|
||||
}
|
||||
|
||||
public ListOfSpansAssert hasRpcTagsInProperOrder() {
|
||||
public ListOfSpansAssert hasRpcLogsInProperOrder() {
|
||||
isNotNull();
|
||||
printSpans();
|
||||
RpcLogKeeper rpcLogKeeper = findRpcLogs();
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -21,6 +22,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
@@ -56,7 +58,7 @@ public class SpanSubscriberTests {
|
||||
.subscribe(System.out::println);
|
||||
|
||||
then(this.tracer.getCurrentSpan()).isNull();
|
||||
then(spanInOperation.get().getParents().get(0)).isEqualTo(span.getSpanId());
|
||||
then(spanInOperation.get().getTraceId()).isEqualTo(span.getTraceId());
|
||||
then(ExceptionUtils.getLastException()).isNull();
|
||||
}
|
||||
|
||||
@@ -105,10 +107,16 @@ public class SpanSubscriberTests {
|
||||
then(this.tracer.getCurrentSpan()).isEqualTo(foo2);
|
||||
then(ExceptionUtils.getLastException()).isNull();
|
||||
// parent cause there's an async span in the meantime
|
||||
then(spanInOperation.get().getSavedSpan().getParents().get(0)).isEqualTo(foo2.getSpanId());
|
||||
then(spanInOperation.get().getTraceId()).isEqualTo(foo2.getTraceId());
|
||||
tracer.close(foo2);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void cleanup() {
|
||||
Hooks.resetOnNewSubscriber();
|
||||
Schedulers.resetFactory();
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
static class Config {
|
||||
@@ -16,11 +16,10 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.autoconfigure.ManagementServerProperties;
|
||||
import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration.SkipPatternProviderConfig;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
@@ -33,7 +32,7 @@ public class SkipPatternProviderConfigTest {
|
||||
public void should_combine_skip_pattern_and_management_context_when_they_are_both_not_empty() throws Exception {
|
||||
SleuthWebProperties sleuthWebProperties = new SleuthWebProperties();
|
||||
sleuthWebProperties.setSkipPattern("foo.*|bar.*");
|
||||
Pattern pattern = SkipPatternProviderConfig.getPatternForManagementServerProperties(
|
||||
Pattern pattern = TraceWebAutoConfiguration.SkipPatternProviderConfig.getPatternForManagementServerProperties(
|
||||
managementServerPropertiesWithContextPath(), sleuthWebProperties);
|
||||
|
||||
then(pattern.pattern()).isEqualTo("foo.*|bar.*|/management/context.*");
|
||||
@@ -44,7 +43,7 @@ public class SkipPatternProviderConfigTest {
|
||||
SleuthWebProperties sleuthWebProperties = new SleuthWebProperties();
|
||||
sleuthWebProperties.setSkipPattern("foo.*|bar.*");
|
||||
|
||||
Pattern pattern = SkipPatternProviderConfig.getPatternForManagementServerProperties(new ManagementServerProperties(), sleuthWebProperties);
|
||||
Pattern pattern = TraceWebAutoConfiguration.SkipPatternProviderConfig.getPatternForManagementServerProperties(new ManagementServerProperties(), sleuthWebProperties);
|
||||
|
||||
then(pattern.pattern()).isEqualTo("foo.*|bar.*|/application.*");
|
||||
}
|
||||
@@ -54,7 +53,7 @@ public class SkipPatternProviderConfigTest {
|
||||
SleuthWebProperties sleuthWebProperties = new SleuthWebProperties();
|
||||
sleuthWebProperties.setSkipPattern("");
|
||||
|
||||
Pattern pattern = SkipPatternProviderConfig.getPatternForManagementServerProperties(
|
||||
Pattern pattern = TraceWebAutoConfiguration.SkipPatternProviderConfig.getPatternForManagementServerProperties(
|
||||
managementServerPropertiesWithContextPath(), sleuthWebProperties);
|
||||
|
||||
then(pattern.pattern()).isEqualTo("/management/context.*");
|
||||
@@ -65,7 +64,7 @@ public class SkipPatternProviderConfigTest {
|
||||
SleuthWebProperties sleuthWebProperties = new SleuthWebProperties();
|
||||
sleuthWebProperties.setSkipPattern("");
|
||||
|
||||
Pattern pattern = SkipPatternProviderConfig.getPatternForManagementServerProperties(
|
||||
Pattern pattern = TraceWebAutoConfiguration.SkipPatternProviderConfig.getPatternForManagementServerProperties(
|
||||
new ManagementServerProperties() {
|
||||
@Override
|
||||
public String getContextPath() {
|
||||
|
||||
@@ -47,7 +47,6 @@ import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
@@ -88,7 +87,7 @@ public class SpringDataInstrumentationTests {
|
||||
});
|
||||
then(this.tracer.getCurrentSpan()).isNull();
|
||||
then(ExceptionUtils.getLastException()).isNull();
|
||||
then(new ListOfSpans(this.arrayListSpanAccumulator.getSpans())).hasRpcTagsInProperOrder();
|
||||
then(new ListOfSpans(this.arrayListSpanAccumulator.getSpans())).hasRpcLogsInProperOrder();
|
||||
}
|
||||
|
||||
long namesCount() {
|
||||
|
||||
@@ -77,7 +77,7 @@ public class TraceFilterWebIntegrationTests {
|
||||
then(new ListOfSpans(this.accumulator.getSpans()))
|
||||
.hasASpanWithTagEqualTo(Span.SPAN_ERROR_TAG_NAME,
|
||||
"Request processing failed; nested exception is java.lang.RuntimeException: Throwing exception")
|
||||
.hasRpcTagsInProperOrder();
|
||||
.hasRpcLogsInProperOrder();
|
||||
}
|
||||
|
||||
private int port() {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package org.springframework.cloud.sleuth.instrument.web;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.sleuth.Sampler;
|
||||
import org.springframework.cloud.sleuth.Span;
|
||||
import org.springframework.cloud.sleuth.SpanReporter;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.assertions.ListOfSpans;
|
||||
import org.springframework.cloud.sleuth.assertions.SleuthAssertions;
|
||||
import org.springframework.cloud.sleuth.sampler.AlwaysSampler;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanAccumulator;
|
||||
import org.springframework.cloud.sleuth.util.ExceptionUtils;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Hooks;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
import rx.plugins.RxJavaHooks;
|
||||
|
||||
public class TraceWebFluxTests {
|
||||
|
||||
@BeforeClass
|
||||
public static void setup() {
|
||||
RxJavaHooks.reset();
|
||||
RxJavaHooks.clear();
|
||||
Hooks.resetOnNewSubscriber();
|
||||
Schedulers.resetFactory();
|
||||
}
|
||||
|
||||
@Test public void should_instrument_web_filter() throws Exception {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder(TraceWebFluxTests.Config.class)
|
||||
.web(WebApplicationType.REACTIVE).properties("server.port=0", "spring.jmx.enabled=false",
|
||||
"spring.application.name=TraceWebFluxTests").run();
|
||||
ExceptionUtils.setFail(true);
|
||||
Span span = null;
|
||||
try {
|
||||
span = context.getBean(Tracer.class).createSpan("foo");
|
||||
int port = context.getBean(Environment.class).getProperty("local.server.port", Integer.class);
|
||||
ArrayListSpanAccumulator accumulator = context.getBean(ArrayListSpanAccumulator.class);
|
||||
|
||||
Mono<ClientResponse> exchange = context.getBean(WebClient.class).get().uri("http://localhost:" + port + "/api/c2/10").exchange();
|
||||
|
||||
Awaitility.await().untilAsserted(() -> {
|
||||
ClientResponse response = exchange.block();
|
||||
SleuthAssertions.then(response.statusCode().value()).isEqualTo(200);
|
||||
SleuthAssertions.then(ExceptionUtils.getLastException()).isNull();
|
||||
SleuthAssertions.then(new ListOfSpans(accumulator.getSpans()))
|
||||
.hasASpanWithLogEqualTo(Span.CLIENT_SEND)
|
||||
.hasASpanWithLogEqualTo(Span.SERVER_RECV)
|
||||
.hasASpanWithLogEqualTo(Span.SERVER_SEND)
|
||||
.hasASpanWithLogEqualTo(Span.CLIENT_RECV);
|
||||
});
|
||||
} finally {
|
||||
context.getBean(Tracer.class).close(span);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
static class Config {
|
||||
|
||||
@Bean WebClient webClient() {
|
||||
return WebClient.create();
|
||||
}
|
||||
|
||||
@Bean Sampler sampler() {
|
||||
return new AlwaysSampler();
|
||||
}
|
||||
|
||||
@Bean SpanReporter spanReporter() {
|
||||
return new ArrayListSpanAccumulator();
|
||||
}
|
||||
|
||||
@Bean
|
||||
Controller2 controller2() {
|
||||
return new Controller2();
|
||||
}
|
||||
}
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/c2")
|
||||
static class Controller2 {
|
||||
@GetMapping("/{id}")
|
||||
public Flux<String> successful(@PathVariable Long id) {
|
||||
return Flux.just(id.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class WebClientTests {
|
||||
// TODO: matches cause there is an issue with Feign not providing the full URL at the interceptor level
|
||||
then(noTraceSpan.get()).matchesATag("http.url", ".*/notrace")
|
||||
.hasATag("http.path", "/notrace").hasATag("http.method", "GET");
|
||||
then(new ListOfSpans(spans)).hasRpcTagsInProperOrder();
|
||||
then(new ListOfSpans(spans)).hasRpcLogsInProperOrder();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<logger name="org.springframework.cloud.sleuth.log" level="DEBUG"/>
|
||||
<logger name="org.springframework.cloud.sleuth.trace" level="DEBUG"/>
|
||||
<logger name="org.springframework.cloud.sleuth.instrument.rxjava" level="DEBUG"/>
|
||||
<logger name="org.springframework.cloud.sleuth.instrument.reactor" level="TRACE"/>
|
||||
<root level="INFO">
|
||||
<appender-ref ref="CONSOLE"/>
|
||||
<appender-ref ref="FILE"/>
|
||||
|
||||
@@ -24,11 +24,6 @@
|
||||
<artifactId>spring-cloud-sleuth-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-reactor</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-sleuth-reactor</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Sleuth Reactor</name>
|
||||
<description>Spring Cloud Sleuth Reactor</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-compile</id>
|
||||
<configuration>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArguments>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>default-testCompile</id>
|
||||
<configuration>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
<showWarnings>true</showWarnings>
|
||||
<compilerArguments>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</compilerArguments>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.reactivestreams</groupId>
|
||||
<artifactId>reactive-streams</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,3 +0,0 @@
|
||||
# Auto Configuration
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration
|
||||
@@ -1 +0,0 @@
|
||||
logging.level.org.springframework.cloud.sleuth.instrument.reactor=TRACE
|
||||
@@ -61,6 +61,7 @@
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>animal-sniffer-maven-plugin</artifactId>
|
||||
<version>1.14</version>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
<signature>
|
||||
|
||||
Reference in New Issue
Block a user