Merge branch '2.1.x'
This commit is contained in:
@@ -84,7 +84,7 @@ public class TraceWebClientAutoConfiguration {
|
||||
protected static class TraceInterceptorConfiguration {
|
||||
|
||||
@Autowired
|
||||
private TracingClientHttpRequestInterceptor clientInterceptor;
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
@Bean
|
||||
static TraceRestTemplateBeanPostProcessor traceRestTemplateBeanPostProcessor(
|
||||
@@ -95,7 +95,8 @@ public class TraceWebClientAutoConfiguration {
|
||||
@Bean
|
||||
@Order
|
||||
RestTemplateCustomizer traceRestTemplateCustomizer() {
|
||||
return new TraceRestTemplateCustomizer(this.clientInterceptor);
|
||||
return new TraceRestTemplateCustomizer(
|
||||
new LazyTracingClientHttpRequestInterceptor(this.beanFactory));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -247,9 +248,9 @@ class RestTemplateInterceptorInjector {
|
||||
|
||||
class TraceRestTemplateCustomizer implements RestTemplateCustomizer {
|
||||
|
||||
private final TracingClientHttpRequestInterceptor interceptor;
|
||||
private final ClientHttpRequestInterceptor interceptor;
|
||||
|
||||
TraceRestTemplateCustomizer(TracingClientHttpRequestInterceptor interceptor) {
|
||||
TraceRestTemplateCustomizer(ClientHttpRequestInterceptor interceptor) {
|
||||
this.interceptor = interceptor;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.reactivestreams.Subscription;
|
||||
import reactor.core.CoreSubscriber;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.util.annotation.Nullable;
|
||||
import reactor.util.context.Context;
|
||||
@@ -41,14 +42,22 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseCookie;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.reactive.ClientHttpResponse;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.reactive.function.BodyExtractor;
|
||||
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.ExchangeStrategies;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||
|
||||
/**
|
||||
* {@link BeanPostProcessor} to wrap a {@link WebClient} instance into its trace
|
||||
@@ -294,17 +303,107 @@ final class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
this.done = true;
|
||||
try {
|
||||
// decorate response body
|
||||
this.actual
|
||||
.onNext(ClientResponse.from(response)
|
||||
.body(response.bodyToFlux(DataBuffer.class)
|
||||
.transform(this.scopePassingTransformer))
|
||||
.build());
|
||||
this.actual.onNext(wrapped(response));
|
||||
}
|
||||
finally {
|
||||
terminateSpan(response, null);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove once fixed
|
||||
// https://github.com/spring-projects/spring-framework/issues/23366
|
||||
private ClientResponse wrapped(ClientResponse response) {
|
||||
return new ClientResponse() {
|
||||
@Override
|
||||
public HttpStatus statusCode() {
|
||||
try {
|
||||
return response.statusCode();
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int rawStatusCode() {
|
||||
return response.rawStatusCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Headers headers() {
|
||||
return response.headers();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiValueMap<String, ResponseCookie> cookies() {
|
||||
return response.cookies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExchangeStrategies strategies() {
|
||||
return response.strategies();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T body(
|
||||
BodyExtractor<T, ? super ClientHttpResponse> extractor) {
|
||||
return response.body(extractor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> bodyToMono(Class<? extends T> elementClass) {
|
||||
return response.bodyToMono(elementClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<T> bodyToMono(
|
||||
ParameterizedTypeReference<T> typeReference) {
|
||||
return response.bodyToMono(typeReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> bodyToFlux(Class<? extends T> elementClass) {
|
||||
return (Flux<T>) response.bodyToFlux(DataBuffer.class)
|
||||
.transform(scopePassingTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Flux<T> bodyToFlux(
|
||||
ParameterizedTypeReference<T> typeReference) {
|
||||
return (Flux<T>) response.bodyToFlux(DataBuffer.class)
|
||||
.transform(scopePassingTransformer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) {
|
||||
return response.toEntity(bodyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<T>> toEntity(
|
||||
ParameterizedTypeReference<T> typeReference) {
|
||||
return response.toEntity(typeReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<List<T>>> toEntityList(
|
||||
Class<T> elementType) {
|
||||
return response.toEntityList(elementType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ResponseEntity<List<T>>> toEntityList(
|
||||
ParameterizedTypeReference<T> typeReference) {
|
||||
return response.toEntityList(typeReference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<WebClientResponseException> createException() {
|
||||
return response.createException();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
try {
|
||||
@@ -350,7 +449,7 @@ final class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
|
||||
void terminateSpan(@Nullable ClientResponse clientResponse,
|
||||
@Nullable Throwable throwable) {
|
||||
if (clientResponse == null || tryStatusCode(clientResponse) == null) {
|
||||
if (clientResponse == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No response was returned. Will close the span ["
|
||||
+ this.span + "]");
|
||||
@@ -358,8 +457,8 @@ final class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
handleReceive(this.span, this.ws, clientResponse, throwable);
|
||||
return;
|
||||
}
|
||||
boolean error = clientResponse.statusCode().is4xxClientError()
|
||||
|| clientResponse.statusCode().is5xxServerError();
|
||||
int statusCode = statusCodeAsInt(clientResponse);
|
||||
boolean error = isError(statusCode);
|
||||
if (error) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(
|
||||
@@ -367,19 +466,31 @@ final class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
+ this.span + "]");
|
||||
}
|
||||
throwable = new RestClientException("Status code of the response is ["
|
||||
+ clientResponse.statusCode().value()
|
||||
+ "] and the reason is ["
|
||||
+ clientResponse.statusCode().getReasonPhrase() + "]");
|
||||
+ statusCode + "] and the reason is ["
|
||||
+ reasonPhrase(clientResponse) + "]");
|
||||
}
|
||||
handleReceive(this.span, this.ws, clientResponse, throwable);
|
||||
}
|
||||
|
||||
private HttpStatus tryStatusCode(ClientResponse clientResponse) {
|
||||
private String reasonPhrase(ClientResponse clientResponse) {
|
||||
try {
|
||||
return clientResponse.statusCode();
|
||||
return clientResponse.statusCode().getReasonPhrase();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return null;
|
||||
catch (IllegalArgumentException ex) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isError(int code) {
|
||||
return code >= 400;
|
||||
}
|
||||
|
||||
private int statusCodeAsInt(ClientResponse response) {
|
||||
try {
|
||||
return response.rawStatusCode();
|
||||
}
|
||||
catch (Exception dontCare) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client.feign;
|
||||
|
||||
import brave.http.HttpTracing;
|
||||
import feign.Client;
|
||||
import feign.Feign;
|
||||
import feign.Retryer;
|
||||
@@ -45,8 +44,7 @@ final class SleuthFeignBuilder {
|
||||
return new LazyClient(beanFactory);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
return TracingFeignClient.create(beanFactory.getBean(HttpTracing.class),
|
||||
new Client.Default(null, null));
|
||||
return new LazyClient(beanFactory, new Client.Default(null, null));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -378,6 +378,22 @@ public class WebClientTests {
|
||||
.contains("CLIENT");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void shouldNotBreakWhenCustomStatusCodeIsSetViaWebClient() {
|
||||
Span span = this.tracer.nextSpan().name("foo").start();
|
||||
|
||||
try (Tracer.SpanInScope ws = this.tracer.withSpanInScope(span)) {
|
||||
this.webClient.get()
|
||||
.uri("http://localhost:" + this.port + "/customstatuscode").exchange()
|
||||
.block();
|
||||
}
|
||||
finally {
|
||||
span.finish();
|
||||
}
|
||||
then(this.tracer.currentSpan()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("Flakey on CI")
|
||||
public void shouldReportTraceForCancelledRequestViaWebClient() {
|
||||
@@ -665,6 +681,12 @@ public class WebClientTests {
|
||||
return traceId;
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/customstatuscode", method = RequestMethod.GET)
|
||||
public ResponseEntity customStatusCode() {
|
||||
this.span = this.tracer.currentSpan();
|
||||
return ResponseEntity.status(499).build();
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
public Map<String, String> home(@RequestHeader HttpHeaders headers) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
||||
Reference in New Issue
Block a user