Merge branch '2.0.x'
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -27,6 +28,8 @@ import brave.propagation.Propagation;
|
||||
import brave.propagation.TraceContext;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
@@ -36,7 +39,6 @@ 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
|
||||
@@ -87,10 +89,20 @@ class TraceWebClientBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceExchangeFilterFunction.class);
|
||||
|
||||
private static final String CLIENT_SPAN_KEY = "sleuth.webclient.clientSpan";
|
||||
|
||||
static final Propagation.Setter<ClientRequest.Builder, String> SETTER = new Propagation.Setter<ClientRequest.Builder, String>() {
|
||||
@Override
|
||||
public void put(ClientRequest.Builder carrier, String key, String value) {
|
||||
carrier.header(key, value);
|
||||
carrier.headers(httpHeaders -> {
|
||||
if (log.isTraceEnabled()) {
|
||||
log.trace("Replacing [" + key + "] with value [" + value + "]");
|
||||
}
|
||||
httpHeaders.merge(key, Collections.singletonList(value),
|
||||
(oldValue, newValue) -> newValue);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,21 +110,10 @@ class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
return "ClientRequest.Builder::header";
|
||||
}
|
||||
};
|
||||
static final Propagation.Getter<ClientRequest, String> GETTER = new Propagation.Getter<ClientRequest, String>() {
|
||||
@Override
|
||||
public String get(ClientRequest carrier, String key) {
|
||||
return carrier.headers().getFirst(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HttpHeaders::getFirst";
|
||||
}
|
||||
};
|
||||
|
||||
private static final Log log = LogFactory.getLog(TraceExchangeFilterFunction.class);
|
||||
|
||||
private static final String CLIENT_SPAN_KEY = "sleuth.webclient.clientSpan";
|
||||
public static ExchangeFilterFunction create(BeanFactory beanFactory) {
|
||||
return new TraceExchangeFilterFunction(beanFactory);
|
||||
}
|
||||
|
||||
final BeanFactory beanFactory;
|
||||
|
||||
@@ -128,16 +129,15 @@ class TraceExchangeFilterFunction implements ExchangeFilterFunction {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
public static ExchangeFilterFunction create(BeanFactory beanFactory) {
|
||||
return new TraceExchangeFilterFunction(beanFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
|
||||
final ClientRequest.Builder builder = ClientRequest.from(request);
|
||||
Mono<ClientResponse> exchange = Mono.defer(() -> next.exchange(builder.build()))
|
||||
.cast(Object.class).onErrorResume(Mono::just)
|
||||
.zipWith(Mono.subscriberContext()).flatMap(anyAndContext -> {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Wrapping the context [" + anyAndContext + "]");
|
||||
}
|
||||
Object any = anyAndContext.getT1();
|
||||
Span clientSpan = anyAndContext.getT2().get(CLIENT_SPAN_KEY);
|
||||
Mono<ClientResponse> continuation;
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright 2013-2018 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.client;
|
||||
|
||||
import brave.ScopedSpan;
|
||||
import brave.Tracer;
|
||||
import brave.sampler.Sampler;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClientResponseException;
|
||||
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
@RunWith(SpringRunner.class)
|
||||
public class GH1102Tests {
|
||||
|
||||
@Autowired
|
||||
Tracer tracer;
|
||||
|
||||
@Autowired
|
||||
WebClient webClient;
|
||||
|
||||
@Autowired
|
||||
TestRetry testRetry;
|
||||
|
||||
@Autowired
|
||||
ArrayListSpanReporter reporter;
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
@Test
|
||||
public void should_store_retries_as_separate_spans() throws Exception {
|
||||
ScopedSpan foo = this.tracer.startScopedSpan("foo");
|
||||
try {
|
||||
this.webClient.get().uri("http://localhost:" + this.port + "/test").retrieve()
|
||||
.bodyToMono(String.class).retry(1).block();
|
||||
BDDAssertions.fail("should throw exception");
|
||||
}
|
||||
catch (WebClientResponseException ex) {
|
||||
|
||||
}
|
||||
finally {
|
||||
foo.finish();
|
||||
}
|
||||
|
||||
BDDAssertions.then(this.testRetry.getHttpHeaders().get("x-b3-traceid"))
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
static class WebConfig {
|
||||
|
||||
@Bean
|
||||
Sampler sampler() {
|
||||
return Sampler.ALWAYS_SAMPLE;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ArrayListSpanReporter reporter() {
|
||||
return new ArrayListSpanReporter();
|
||||
}
|
||||
|
||||
@Bean
|
||||
WebClient webClient() {
|
||||
return WebClient.builder().build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
TestRetry testRetry() {
|
||||
return new TestRetry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RestController
|
||||
static class TestRetry {
|
||||
|
||||
private static final Log log = LogFactory.getLog(TestRetry.class);
|
||||
|
||||
private MultiValueMap<String, String> httpHeaders;
|
||||
|
||||
@GetMapping("test")
|
||||
Mono<String> test(@RequestHeader MultiValueMap<String, String> map) {
|
||||
this.httpHeaders = map;
|
||||
log.info("Processing test. Headers [" + this.httpHeaders + "]");
|
||||
return Mono.error(new RuntimeException("BOOM!"));
|
||||
}
|
||||
|
||||
MultiValueMap<String, String> getHttpHeaders() {
|
||||
return this.httpHeaders;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,9 +31,9 @@ import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@SpringBootTest(classes = GH846Test.App.class, webEnvironment = WebEnvironment.NONE)
|
||||
@SpringBootTest(classes = GH846Tests.App.class, webEnvironment = WebEnvironment.NONE)
|
||||
@RunWith(SpringRunner.class)
|
||||
public class GH846Test {
|
||||
public class GH846Tests {
|
||||
|
||||
@Autowired
|
||||
private MyBean myBean;
|
||||
@@ -16,12 +16,18 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.web.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import brave.propagation.Propagation;
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user