Merge branch '2.2.x'

This commit is contained in:
Adrian Cole
2020-04-04 14:39:36 +08:00
32 changed files with 209 additions and 304 deletions

View File

@@ -676,7 +676,7 @@ To that end, Sleuth:
** Includes a sampling policy to manage volume.
** Can report to a Zipkin system for query and visualization.
* Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, Zuul filters, and Feign client).
* Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, and Feign client).
* Sleuth includes default logic to join a trace across HTTP or messaging boundaries.
For example, HTTP propagation works over Zipkin-compatible request headers.
@@ -983,4 +983,4 @@ Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on t
- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL.
- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`.
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.

View File

@@ -40,7 +40,7 @@
|spring.sleuth.sampler.probability | | Probability of requests that should be sampled. E.g. 1.0 - 100% requests should be sampled. The precision is whole-numbers only (i.e. there's no support for 0.1% of the traces).
|spring.sleuth.sampler.rate | 10 | A rate per second can be a nice choice for low-traffic endpoints as it allows you surge protection. For example, you may never expect the endpoint to get more than 50 requests per second. If there was a sudden surge of traffic, to 5000 requests per second, you would still end up with 50 traces per second. Conversely, if you had a percentage, like 10%, the same surge would end up with 500 traces per second, possibly overloading your storage. Amazon X-Ray includes a rate-limited sampler (named Reservoir) for this purpose. Brave has taken the same approach via the {@link brave.sampler.RateLimitingSampler}.
|spring.sleuth.scheduled.enabled | true | Enable tracing for {@link org.springframework.scheduling.annotation.Scheduled}.
|spring.sleuth.scheduled.skip-pattern | org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask | Pattern for the fully qualified name of a class that should be skipped.
|spring.sleuth.scheduled.skip-pattern | | Pattern for the fully qualified name of a class that should be skipped.
|spring.sleuth.supports-join | true | True means the tracing system supports sharing a span ID between a client and server.
|spring.sleuth.trace-id128 | false | When true, generate 128-bit trace IDs instead of 64-bit ones.
|spring.sleuth.web.additional-skip-pattern | | Additional pattern for URLs that should be skipped in tracing. This will be appended to the {@link SleuthWebProperties#skipPattern}.
@@ -52,7 +52,6 @@
|spring.sleuth.web.filter-order | | Order in which the tracing filters should be registered. Defaults to {@link TraceHttpAutoConfiguration#TRACING_FILTER_ORDER}.
|spring.sleuth.web.ignore-auto-configured-skip-patterns | false | If set to true, auto-configured skip patterns will be ignored. @see TraceWebAutoConfiguration
|spring.sleuth.web.skip-pattern | /api-docs.*\|/swagger.*\|.*\.png\|.*\.css\|.*\.js\|.*\.html\|/favicon.ico\|/hystrix.stream | Pattern for URLs that should be skipped in tracing.
|spring.sleuth.zuul.enabled | true | Enable span information propagation when using Zuul.
|spring.zipkin.activemq.message-max-bytes | 100000 | Maximum number of bytes for a given message with spans sent to Zipkin over ActiveMQ.
|spring.zipkin.activemq.queue | zipkin | Name of the ActiveMQ queue where spans should be sent to Zipkin.
|spring.zipkin.base-url | http://localhost:9411/ | URL of the zipkin query server instance. You can also provide the service id of the Zipkin server if Zipkin's registered in service discovery (e.g. https://zipkinserver/).

View File

@@ -32,7 +32,7 @@ To that end, Sleuth:
** Includes a sampling policy to manage volume.
** Can report to a Zipkin system for query and visualization.
* Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, Zuul filters, and Feign client).
* Instruments common ingress and egress points from Spring applications (servlet filter, async endpoints, rest template, scheduled actions, message channels, and Feign client).
* Sleuth includes default logic to join a trace across HTTP or messaging boundaries.
For example, HTTP propagation works over Zipkin-compatible request headers.

View File

@@ -8,5 +8,5 @@ Spring Cloud Sleuth features:
* Adds trace and span ids to the Slf4J MDC, so you can extract all the logs from a given trace or span in a log aggregator.
* Provides an abstraction over common distributed tracing data models: traces, spans (forming a DAG), annotations, key-value annotations. Loosely based on HTrace, but Zipkin (Dapper) compatible.
* Instruments common ingress and egress points from Spring applications (servlet filter, rest template, scheduled actions, message channels, zuul filters, feign client).
* If `spring-cloud-sleuth-zipkin` is available then the app will generate and collect Zipkin-compatible traces via HTTP. By default it sends them to a Zipkin collector service on localhost (port 9411). Configure the location of the service using `spring.zipkin.baseUrl`.
* Instruments common ingress and egress points from Spring applications (servlet filter, rest template, scheduled actions, message channels, feign client).
* If `spring-cloud-sleuth-zipkin` is available then the app will generate and collect Zipkin-compatible traces via HTTP. By default it sends them to a Zipkin collector service on localhost (port 9411). Configure the location of the service using `spring.zipkin.baseUrl`.

View File

@@ -620,8 +620,6 @@ Sometimes, you do not want to create a new span but you want to continue one. An
situation might be as follows:
* *AOP*: If there was already a span created before an aspect was reached, you might not want to create a new span.
* *Hystrix*: Executing a Hystrix command is most likely a logical part of the current processing.
It is in fact merely a technical implementation detail that you would not necessarily want to reflect in tracing as a separate being.
To continue a span, you can use `brave.Tracer`, as shown in the following example:
@@ -1352,8 +1350,6 @@ If you annotate your method with `@Scheduled`, we automatically create a new spa
* The span is tagged with the method's class name and method name.
If you want to skip span creation for some `@Scheduled` annotated classes, you can set the `spring.sleuth.scheduled.skipPattern` with a regular expression that matches the fully qualified name of the `@Scheduled` annotated class.
If you use `spring-cloud-sleuth-stream` and `spring-cloud-netflix-hystrix-stream` together, a span is created for each Hystrix metrics and sent to Zipkin.
This behavior may be annoying. That's why, by default, `spring.sleuth.scheduled.skipPattern=org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask`.
==== Executor, ExecutorService, and ScheduledExecutorService
@@ -1450,11 +1446,6 @@ so that tracing headers get extracted from the message and a trace gets put into
To block this feature, set `spring.sleuth.messaging.sqs.enabled` to `false`.
=== Zuul
We instrument the Zuul Ribbon integration by enriching the Ribbon requests with tracing information.
To disable Zuul support, set the `spring.sleuth.zuul.enabled` property to `false`.
=== Redis
We set `tracing` property to Lettcue `ClientResources` instance to enable Brave tracing built in Lettuce .

View File

@@ -36,7 +36,7 @@ public class SleuthSchedulingProperties {
/**
* Pattern for the fully qualified name of a class that should be skipped.
*/
private String skipPattern = "org.springframework.cloud.netflix.hystrix.stream.HystrixStreamTask";
private String skipPattern;
public boolean isEnabled() {
return this.enabled;
@@ -51,7 +51,14 @@ public class SleuthSchedulingProperties {
}
public void setSkipPattern(String skipPattern) {
this.skipPattern = skipPattern;
this.skipPattern = emptyToNull(skipPattern);
}
static String emptyToNull(String skipPattern) {
if (skipPattern != null && skipPattern.isEmpty()) {
skipPattern = null; // otherwise this make an empty pattern!
}
return skipPattern;
}
}

View File

@@ -26,6 +26,7 @@ import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.cloud.sleuth.util.SpanNameUtil;
import org.springframework.lang.Nullable;
/**
* Aspect that creates a new Span for running threads executing methods annotated with
@@ -50,6 +51,7 @@ public class TraceSchedulingAspect {
private final Tracer tracer;
@Nullable
private final Pattern skipPattern;
public TraceSchedulingAspect(Tracer tracer, Pattern skipPattern) {
@@ -59,7 +61,8 @@ public class TraceSchedulingAspect {
@Around("execution (@org.springframework.scheduling.annotation.Scheduled * *.*(..))")
public Object traceBackgroundThread(final ProceedingJoinPoint pjp) throws Throwable {
if (this.skipPattern.matcher(pjp.getTarget().getClass().getName()).matches()) {
if (this.skipPattern != null && this.skipPattern
.matcher(pjp.getTarget().getClass().getName()).matches()) {
// we might have a span in context due to wrapping of runnables
// we want to clear that context
this.tracer.withSpanInScope(null);

View File

@@ -51,8 +51,10 @@ public class TraceSchedulingAutoConfiguration {
@ConditionalOnClass(name = "org.aspectj.lang.ProceedingJoinPoint")
public TraceSchedulingAspect traceSchedulingAspect(Tracer tracer,
SleuthSchedulingProperties sleuthSchedulingProperties) {
return new TraceSchedulingAspect(tracer,
Pattern.compile(sleuthSchedulingProperties.getSkipPattern()));
String skipPatternString = sleuthSchedulingProperties.getSkipPattern();
Pattern skipPattern = skipPatternString != null
? Pattern.compile(skipPatternString) : null;
return new TraceSchedulingAspect(tracer, skipPattern);
}
}

View File

@@ -27,18 +27,12 @@ import brave.sampler.SamplerFunction;
* @author Marcin Grzejszczak
* @since 2.0.0
*/
class SkipPatternHttpServerSampler implements SamplerFunction<HttpRequest> {
private final SkipPatternProvider provider;
abstract class SkipPatternSampler implements SamplerFunction<HttpRequest> {
private Pattern pattern;
SkipPatternHttpServerSampler(SkipPatternProvider provider) {
this.provider = provider;
}
@Override
public Boolean trySample(HttpRequest request) {
public final Boolean trySample(HttpRequest request) {
String url = request.path();
boolean shouldSkip = pattern().matcher(url).matches();
if (shouldSkip) {
@@ -47,9 +41,11 @@ class SkipPatternHttpServerSampler implements SamplerFunction<HttpRequest> {
return null;
}
abstract Pattern getPattern();
private Pattern pattern() {
if (this.pattern == null) {
this.pattern = this.provider.skipPattern();
this.pattern = getPattern();
}
return this.pattern;
}

View File

@@ -96,7 +96,7 @@ public class SleuthWebProperties {
}
public void setSkipPattern(String skipPattern) {
this.skipPattern = skipPattern;
this.skipPattern = emptyToNull(skipPattern);
}
public String getAdditionalSkipPattern() {
@@ -104,7 +104,7 @@ public class SleuthWebProperties {
}
public void setAdditionalSkipPattern(String additionalSkipPattern) {
this.additionalSkipPattern = additionalSkipPattern;
this.additionalSkipPattern = emptyToNull(additionalSkipPattern);
}
public int getFilterOrder() {
@@ -149,6 +149,13 @@ public class SleuthWebProperties {
this.client = client;
}
static String emptyToNull(String skipPattern) {
if (skipPattern != null && skipPattern.isEmpty()) {
skipPattern = null; // otherwise this would skip paths named ""!
}
return skipPattern;
}
/**
* Web client properties.
*
@@ -159,7 +166,7 @@ public class SleuthWebProperties {
/**
* Pattern for URLs that should be skipped in client side tracing.
*/
private String skipPattern = "";
private String skipPattern;
/**
* Enable interceptor injecting into
@@ -180,7 +187,7 @@ public class SleuthWebProperties {
}
public void setSkipPattern(String skipPattern) {
this.skipPattern = skipPattern;
this.skipPattern = emptyToNull(skipPattern);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.cloud.sleuth.instrument.web;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import brave.Tracing;
import brave.http.HttpRequest;
@@ -26,6 +27,7 @@ import brave.http.HttpResponseParser;
import brave.http.HttpTracing;
import brave.http.HttpTracingCustomizer;
import brave.sampler.SamplerFunction;
import brave.sampler.SamplerFunctions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
@@ -59,7 +61,7 @@ public class TraceHttpAutoConfiguration {
@Bean
@ConditionalOnMissingBean
// NOTE: stable bean name as might be used outside sleuth
HttpTracing httpTracing(Tracing tracing, SkipPatternProvider provider,
HttpTracing httpTracing(Tracing tracing, @Nullable SkipPatternProvider provider,
@Nullable @HttpClientRequestParser HttpRequestParser httpClientRequestParser,
@Nullable @HttpClientResponseParser HttpResponseParser httpClientResponseParser,
@Nullable brave.http.HttpClientParser clientParser,
@@ -106,12 +108,18 @@ public class TraceHttpAutoConfiguration {
private SamplerFunction<HttpRequest> combineUserProvidedSamplerWithSkipPatternSampler(
@Nullable SamplerFunction<HttpRequest> serverSampler,
SkipPatternProvider provider) {
SkipPatternHttpServerSampler skipPatternSampler = new SkipPatternHttpServerSampler(
provider);
if (serverSampler == null) {
@Nullable SkipPatternProvider provider) {
SamplerFunction<HttpRequest> skipPatternSampler = provider != null
? new SkipPatternHttpServerSampler(provider) : null;
if (serverSampler == null && skipPatternSampler == null) {
return SamplerFunctions.deferDecision();
}
else if (serverSampler == null) {
return skipPatternSampler;
}
else if (skipPatternSampler == null) {
return serverSampler;
}
return new CompositeHttpSampler(skipPatternSampler, serverSampler);
}
@@ -119,7 +127,12 @@ public class TraceHttpAutoConfiguration {
@ConditionalOnMissingBean(name = HttpClientSampler.NAME)
SamplerFunction<HttpRequest> sleuthHttpClientSampler(
SleuthWebProperties sleuthWebProperties) {
return new SkipPatternHttpClientSampler(sleuthWebProperties);
String skipPattern = sleuthWebProperties.getClient().getSkipPattern();
if (skipPattern == null) {
return SamplerFunctions.deferDecision();
}
return new SkipPatternHttpClientSampler(Pattern.compile(skipPattern));
}
}
@@ -129,7 +142,7 @@ public class TraceHttpAutoConfiguration {
*
* @author Adrian Cole
*/
class CompositeHttpSampler implements SamplerFunction<HttpRequest> {
final class CompositeHttpSampler implements SamplerFunction<HttpRequest> {
final SamplerFunction<HttpRequest> left;
@@ -170,21 +183,32 @@ class CompositeHttpSampler implements SamplerFunction<HttpRequest> {
*
* @author Marcin Grzejszczak
*/
class SkipPatternHttpClientSampler implements SamplerFunction<HttpRequest> {
final class SkipPatternHttpServerSampler extends SkipPatternSampler {
private final SleuthWebProperties properties;
private final SkipPatternProvider provider;
SkipPatternHttpClientSampler(SleuthWebProperties properties) {
this.properties = properties;
SkipPatternHttpServerSampler(SkipPatternProvider provider) {
this.provider = provider;
}
@Override
public Boolean trySample(HttpRequest request) {
String path = request.path();
if (path == null) {
return null;
}
return path.matches(this.properties.getClient().getSkipPattern()) ? false : null;
Pattern getPattern() {
return this.provider.skipPattern();
}
}
final class SkipPatternHttpClientSampler extends SkipPatternSampler {
private final Pattern skipPattern;
SkipPatternHttpClientSampler(Pattern skipPattern) {
this.skipPattern = skipPattern;
}
@Override
Pattern getPattern() {
return skipPattern;
}
}

View File

@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import brave.Tracing;
@@ -66,18 +67,26 @@ public class TraceWebAutoConfiguration {
@Bean
@ConditionalOnMissingBean
SkipPatternProvider sleuthSkipPatternProvider() {
return () -> {
StringJoiner joiner = new StringJoiner("|");
for (SingleSkipPattern pattern : this.patterns) {
Optional<Pattern> skipPattern = pattern.skipPattern();
if (skipPattern.isPresent()) {
Pattern pattern1 = skipPattern.get();
String s = pattern1.pattern();
joiner.add(s);
}
}
return Pattern.compile(joiner.toString());
};
if (this.patterns == null) {
return null;
}
List<Pattern> presentPatterns = this.patterns.stream()
.map(SingleSkipPattern::skipPattern).filter(Optional::isPresent)
.map(Optional::get).collect(Collectors.toList());
if (presentPatterns.isEmpty()) {
return null;
}
if (presentPatterns.size() == 1) {
Pattern pattern = presentPatterns.get(0);
return () -> pattern;
}
StringJoiner joiner = new StringJoiner("|");
for (Pattern pattern : presentPatterns) {
String s = pattern.pattern();
joiner.add(s);
}
Pattern pattern = Pattern.compile(joiner.toString());
return () -> pattern;
}
@Configuration(proxyBeanMethods = false)
@@ -200,24 +209,25 @@ public class TraceWebAutoConfiguration {
@Configuration(proxyBeanMethods = false)
static class DefaultSkipPatternConfig {
private static String combinedPattern(String skipPattern,
String additionalSkipPattern) {
String pattern = skipPattern;
if (!StringUtils.hasText(skipPattern)) {
pattern = SleuthWebProperties.DEFAULT_SKIP_PATTERN;
}
if (StringUtils.hasText(additionalSkipPattern)) {
return pattern + "|" + additionalSkipPattern;
}
return pattern;
}
@Bean
SingleSkipPattern defaultSkipPatternBean(
SleuthWebProperties sleuthWebProperties) {
return () -> Optional.of(
Pattern.compile(combinedPattern(sleuthWebProperties.getSkipPattern(),
sleuthWebProperties.getAdditionalSkipPattern())));
Pattern pattern = combinePatterns(sleuthWebProperties.getSkipPattern(),
sleuthWebProperties.getAdditionalSkipPattern());
return () -> Optional.ofNullable(pattern);
}
private static Pattern combinePatterns(String left, String right) {
if (left == null && right == null) {
return null;
}
else if (left == null) {
return Pattern.compile(right);
}
else if (right == null) {
return Pattern.compile(left);
}
return Pattern.compile(left + "|" + right);
}
}

View File

@@ -53,8 +53,6 @@ public class TraceFeignClientAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@Scope("prototype")
@ConditionalOnProperty(name = "feign.hystrix.enabled", havingValue = "false",
matchIfMissing = true)
Feign.Builder feignBuilder(BeanFactory beanFactory) {
return SleuthFeignBuilder.builder(beanFactory);
}

View File

@@ -44,7 +44,10 @@ class TraceFeignContext extends FeignContext {
@SuppressWarnings("unchecked")
public <T> T getInstance(String name, Class<T> type) {
T object = this.delegate.getInstance(name, type);
return (T) this.traceFeignObjectWrapper.wrap(object);
if (object != null) {
return (T) this.traceFeignObjectWrapper.wrap(object);
}
return null;
}
@Override

View File

@@ -36,12 +36,6 @@
"description": "Enable post processor that wraps Feign Context in its tracing representations.",
"defaultValue": true
},
{
"name": "spring.sleuth.zuul.enabled",
"type": "java.lang.Boolean",
"description": "Enable span information propagation when using Zuul.",
"defaultValue": true
},
{
"name": "spring.sleuth.grpc.enabled",
"type": "java.lang.Boolean",

View File

@@ -59,6 +59,13 @@ public class SkipPatternProviderConfigTest {
EndpointAutoConfiguration.class, WebEndpointAutoConfiguration.class,
TraceAutoConfiguration.class, TraceWebAutoConfiguration.class));
@Test
public void should_return_null_when_cleared() throws Exception {
contextRunner.withPropertyValues("spring.sleuth.web.skip-pattern")
.run(context -> then(context.getBean("sleuthSkipPatternProvider"))
.hasToString("null"));
}
@Test
public void should_pick_skip_pattern_from_sleuth_properties() throws Exception {
contextRunner.withPropertyValues("spring.sleuth.web.skip-pattern=foo.*|bar.*")

View File

@@ -31,27 +31,59 @@ import static org.assertj.core.api.BDDAssertions.then;
* @author Marcin Grzejszczak
*/
@ExtendWith(MockitoExtension.class)
public class SkipPatternHttpServerSamplerTests {
public class SkipPatternSamplerTests {
@Mock
HttpRequest request;
@Test
public void should_delegate_sampling_decision_if_pattern_is_not_matched() {
SkipPatternProvider provider = () -> Pattern.compile("foo");
BDDMockito.given(this.request.path()).willReturn("url");
SkipPatternHttpServerSampler sampler = new SkipPatternHttpServerSampler(provider);
SkipPatternSampler sampler = new SkipPatternSampler() {
@Override
Pattern getPattern() {
return Pattern.compile("foo");
}
};
then(sampler.trySample(this.request)).isNull();
}
@Test
public void should_not_sample_if_pattern_is_matched() {
SkipPatternProvider provider = () -> Pattern.compile(".*");
BDDMockito.given(this.request.path()).willReturn("url");
SkipPatternHttpServerSampler sampler = new SkipPatternHttpServerSampler(provider);
SkipPatternSampler sampler = new SkipPatternSampler() {
@Override
Pattern getPattern() {
return Pattern.compile(".*");
}
};
then(sampler.trySample(this.request)).isFalse();
}
@Test
public void should_not_get_pattern_twice() {
BDDMockito.given(this.request.path()).willReturn("url");
SkipPatternSampler sampler = new SkipPatternSampler() {
boolean provisioned;
@Override
Pattern getPattern() {
if (provisioned) {
throw new AssertionError("called twice!");
}
try {
return Pattern.compile(".*");
}
finally {
provisioned = true;
}
}
};
then(sampler.trySample(this.request)).isFalse();
then(sampler.trySample(this.request)).isFalse();
}
}

View File

@@ -21,6 +21,7 @@ import brave.http.HttpRequestParser;
import brave.http.HttpResponseParser;
import brave.http.HttpTracing;
import brave.sampler.SamplerFunction;
import brave.sampler.SamplerFunctions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
@@ -36,15 +37,27 @@ import static org.assertj.core.api.BDDAssertions.then;
public class TraceHttpAutoConfigurationTests {
@Test
public void defaultsToSkipPatternHttpClientSampler() {
public void defaultsClientSamplerToDefer() {
contextRunner().run((context) -> {
SamplerFunction<HttpRequest> clientSampler = context
.getBean(HttpTracing.class).clientRequestSampler();
then(clientSampler).isInstanceOf(SkipPatternHttpClientSampler.class);
then(clientSampler).isSameAs(SamplerFunctions.deferDecision());
});
}
@Test
public void configuresClientSkipPattern() throws Exception {
contextRunner()
.withPropertyValues("spring.sleuth.web.client.skip-pattern=foo.*|bar.*")
.run((context) -> {
SamplerFunction<HttpRequest> clientSampler = context
.getBean(HttpTracing.class).clientRequestSampler();
then(clientSampler).isInstanceOf(SkipPatternHttpClientSampler.class);
});
}
@Test
public void configuresUserProvidedHttpClientSampler() {
contextRunner().withUserConfiguration(HttpClientSamplerConfig.class)
@@ -57,7 +70,7 @@ public class TraceHttpAutoConfigurationTests {
}
@Test
public void defaultsToSkipPatternHttpServerSampler() {
public void defaultsServerSamplerToSkipPattern() {
contextRunner().run((context) -> {
SamplerFunction<HttpRequest> serverSampler = context
.getBean(HttpTracing.class).serverRequestSampler();
@@ -66,6 +79,17 @@ public class TraceHttpAutoConfigurationTests {
});
}
@Test
public void defaultsServerSamplerToDeferWhenSkipPatternCleared() {
contextRunner().withPropertyValues("spring.sleuth.web.skip-pattern")
.run((context) -> {
SamplerFunction<HttpRequest> clientSampler = context
.getBean(HttpTracing.class).serverRequestSampler();
then(clientSampler).isSameAs(SamplerFunctions.deferDecision());
});
}
@Test
public void wrapsUserProvidedHttpServerSampler() {
contextRunner().withUserConfiguration(HttpServerSamplerConfig.class)

View File

@@ -95,8 +95,6 @@ public class WebClientDiscoveryExceptionTests {
span.finish();
}
// hystrix commands should finish at this point
Thread.sleep(200);
List<zipkin2.Span> spans = this.reporter.getSpans();
then(spans.stream().filter(span1 -> span1.kind() == zipkin2.Span.Kind.CLIENT)
.findFirst().get().tags()).containsKey("error");

View File

@@ -52,8 +52,7 @@ import static org.assertj.core.api.Assertions.fail;
import static org.assertj.core.api.BDDAssertions.then;
@SpringBootTest(classes = { WebClientExceptionTests.TestConfiguration.class },
properties = { "ribbon.ConnectTimeout=30000",
"spring.application.name=exceptionservice" },
properties = { "spring.application.name=exceptionservice" },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class WebClientExceptionTests {
@@ -128,7 +127,7 @@ public class WebClientExceptionTests {
@EnableAutoConfiguration
@EnableFeignClients
@LoadBalancerClient(value = "exceptionservice",
configuration = ExceptionServiceRibbonClientConfiguration.class)
configuration = ExceptionServiceLoadBalancerClientConfiguration.class)
public static class TestConfiguration {
@LoadBalanced
@@ -153,7 +152,7 @@ public class WebClientExceptionTests {
}
@Configuration
public static class ExceptionServiceRibbonClientConfiguration {
public static class ExceptionServiceLoadBalancerClientConfiguration {
@Bean
public ServiceInstanceListSupplier serviceInstanceListSupplier(Environment env) {

View File

@@ -96,7 +96,7 @@ import static org.assertj.core.api.BDDAssertions.then;
@SpringBootTest(classes = WebClientTests.TestConfiguration.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(properties = { "spring.application.name=fooservice",
"feign.hystrix.enabled=false", "spring.sleuth.web.client.skip-pattern=/skip.*" })
"spring.sleuth.web.client.skip-pattern=/skip.*" })
@DirtiesContext
public class WebClientTests {

View File

@@ -10,10 +10,6 @@ There are a few samples with slightly different features. You can run all of the
* `spring-cloud-sleuth-sample-messaging`: a Spring Integration application with two HTTP endpoints ("/" and "/xform")
* `spring-cloud-sleuth-sample-ribbon`: two endpoints ("/" and "/call") that make calls to the "zipkin" sample via Ribbon. Also has `@EnableZUulProxy" so if the other samples are running they are proxied at "/messaging", "/zipkin", "/vanilla" (see "/routes" for a list).
The Ribbon sample makes an interesting demo or playground for learning about zipkin. In the screenshot below you can see a trace with 3 spans - it starts in the "testSleuthRibbon" app and crosses to "testSleuthMessaging" for the next 2 spans.
=== Running samples with Zipkin
1. Optionally run the https://github.com/openzipkin/zipkin[Zipkin] Server, e.g. via docker compose (there's a `docker-compose.yml` in https://github.com/spring-cloud/spring-cloud-sleuth-samples/spring-cloud-sleuth-sample-zipkin[Spring Cloud Sleuth], or in https://github.com/openzipkin/docker-zipkin[Docker Zipkin]
@@ -25,5 +21,5 @@ NOTE: You can see the zipkin spans without the UI (in logs) if you run the sampl
image::{github-raw}/docs/src/main/asciidoc/images/zipkin-trace-screenshot.png[Sample Zipkin Screenshot]
> The fact that the first trace in says "testSleuthMessaging" seems to be a bug in the UI (it has some annotations from that service, but it originates in the "testSleuthRibbon" service).
> The fact that the first trace in says "testSleuthMessaging" seems to be a bug in the UI (it has some annotations from that service, but it originates in the "testSleuthMessaging" service).

View File

@@ -69,10 +69,8 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<!-- Including Eureka is a good test, even if there is no service to connect
with because it exercises slightly different code paths in Ribbon -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>

View File

@@ -59,8 +59,7 @@ import static org.assertj.core.api.BDDAssertions.then;
* @author Marcin Grzejszczak
*/
@SpringBootTest(classes = { AppConfig.class, Application.class },
webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "ribbon.eureka.enabled=false", "feign.hystrix.enabled=false" })
webEnvironment = WebEnvironment.RANDOM_PORT)
public class Issue410Tests {
private static final Log log = LogFactory

View File

@@ -40,9 +40,7 @@ import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Marcin Grzejszczak
*/
@SpringBootTest(classes = Issue546TestsApp.class,
properties = { "ribbon.eureka.enabled=false", "feign.hystrix.enabled=false",
"server.port=0" },
@SpringBootTest(classes = Issue546TestsApp.class, properties = { "server.port=0" },
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class Issue546Tests {

View File

@@ -166,7 +166,7 @@ class MyDelegateClient implements Client {
}
@FeignClient(name = "foo", url = "https://non.existing.url")
@FeignClient(name = "foo", url = "http://foo")
interface MyNameRemote {
@RequestMapping(value = "/", method = RequestMethod.GET)

View File

@@ -20,7 +20,6 @@ import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import brave.Tracing;
import brave.http.HttpRequest;
import brave.sampler.Sampler;
import brave.sampler.SamplerFunction;
@@ -72,9 +71,6 @@ public class ManuallyCreatedDelegateLoadBalancerFeignClientTests {
@Autowired
MyDelegateClient myClient;
@Autowired
Tracing tracer;
@BeforeEach
public void open() {
this.reporter.clear();
@@ -87,7 +83,6 @@ public class ManuallyCreatedDelegateLoadBalancerFeignClientTests {
// then(this.myClient.wasCalled()).isTrue();
then(this.myDelegateClient.wasCalled()).isTrue();
then(response).isEqualTo("foo");
// System.out.println("this.myclient.wascalled: " + this.myClient.wasCalled());
List<Span> spans = this.reporter.getSpans();
// retries
then(spans).hasSize(1);
@@ -126,8 +121,8 @@ class Application {
public MyNameRemote myNameRemote(Client client, Decoder decoder, Encoder encoder,
Contract contract) {
return Feign.builder().client(client).encoder(encoder).decoder(decoder)
.contract(contract).target(new HardCodedTarget<>(MyNameRemote.class,
"foo", "https://non.existing.url"));
.contract(contract)
.target(new HardCodedTarget<>(MyNameRemote.class, "foo", "http://foo"));
}
@Bean
@@ -167,7 +162,7 @@ class MyDelegateClient implements Client {
}
@FeignClient(name = "foo", url = "https://non.existing.url")
@FeignClient(name = "foo", url = "http://foo")
interface MyNameRemote {
@RequestMapping(value = "/", method = RequestMethod.GET)

View File

@@ -1,160 +0,0 @@
/*
* Copyright 2013-2019 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
*
* https://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.feign.issues.issue350;
import java.util.List;
import java.util.concurrent.ExecutionException;
import brave.Tracing;
import brave.sampler.Sampler;
import feign.Logger;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import zipkin2.Span;
import zipkin2.reporter.Reporter;
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.web.client.TestRestTemplate;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.sleuth.instrument.web.TraceWebServletAutoConfiguration;
import org.springframework.cloud.sleuth.util.ArrayListSpanReporter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.TestPropertySource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.BDDAssertions.then;
@FeignClient(name = "myFeignClient", url = "localhost:9988")
interface MyFeignClient {
@RequestMapping("/service/ok")
String ok();
@RequestMapping("/service/not-ok")
String exp();
}
/**
* @author Marcin Grzejszczak
*/
@SpringBootTest(classes = Application.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource(properties = { "ribbon.eureka.enabled=false",
"feign.hystrix.enabled=false", "server.port=9988" })
public class Issue350Tests {
TestRestTemplate template = new TestRestTemplate();
@Autowired
Tracing tracer;
@Autowired
ArrayListSpanReporter reporter;
@BeforeEach
public void setup() {
this.reporter.clear();
}
@Test
public void should_successfully_work_without_hystrix() {
this.template.getForEntity("http://localhost:9988/sleuth/test-not-ok",
String.class);
List<Span> spans = this.reporter.getSpans();
then(spans).hasSize(1);
then(spans.get(0).tags()).containsEntry("http.status_code", "406");
}
}
@Configuration
@EnableAutoConfiguration(exclude = TraceWebServletAutoConfiguration.class)
@EnableFeignClients(basePackageClasses = { SleuthTestController.class })
class Application {
@Bean
public ServiceTestController serviceTestController() {
return new ServiceTestController();
}
@Bean
public SleuthTestController sleuthTestController() {
return new SleuthTestController();
}
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
@Bean
public Sampler defaultSampler() {
return Sampler.ALWAYS_SAMPLE;
}
@Bean
public Reporter<Span> spanReporter() {
return new ArrayListSpanReporter();
}
}
@RestController
@RequestMapping(path = "/service")
class ServiceTestController {
@RequestMapping("/ok")
public String ok() throws InterruptedException, ExecutionException {
return "I'm OK";
}
@RequestMapping("/not-ok")
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
public String notOk() throws InterruptedException, ExecutionException {
return "Not OK";
}
}
@RestController
@RequestMapping(path = "/sleuth")
class SleuthTestController {
@Autowired
private MyFeignClient myFeignClient;
@RequestMapping("/test-ok")
public String ok() throws InterruptedException, ExecutionException {
return this.myFeignClient.ok();
}
@RequestMapping("/test-not-ok")
public String notOk() throws InterruptedException, ExecutionException {
return this.myFeignClient.exp();
}
}

View File

@@ -76,8 +76,7 @@ interface MyFeignClient {
@SpringBootTest(classes = Application.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource(properties = { "ribbon.eureka.enabled=false",
"feign.hystrix.enabled=false", "server.port=9998" })
@TestPropertySource(properties = { "server.port=9998" })
public class Issue362Tests {
RestTemplate template = new RestTemplate();

View File

@@ -61,8 +61,8 @@ interface MyNameRemote {
@SpringBootTest(classes = Application.class,
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@TestPropertySource(properties = { "spring.application.name=demo-feign-uri",
"server.port=9978", "eureka.client.enabled=true", "ribbon.eureka.enabled=true" })
@TestPropertySource(
properties = { "spring.application.name=demo-feign-uri", "server.port=9978" })
public class Issue393Tests {
RestTemplate template = new RestTemplate();

View File

@@ -46,7 +46,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import static org.assertj.core.api.BDDAssertions.then;
@FeignClient(name = "foo", url = "https://non.existing.url")
@FeignClient(name = "foo", url = "http://foo")
interface MyNameRemote {
@RequestMapping(value = "/", method = RequestMethod.GET)

View File

@@ -1,17 +1,3 @@
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 5000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 5000
exceptionService.ribbon:
MaxAutoRetries: 3
OkToRetryOnAllOperations: true
ConnectTimeout: 1
ReadTimeout: 1
eureka.client.enabled: false
ribbon.eureka.enabled: false
logging.level.org.springframework.cloud: DEBUG
logging.level.com.netflix.discovery.InstanceInfoReplicator: ERROR
logging.level.org.springframework.cloud.sleuth.instrument.web.client.feign: TRACE
logging.level.org.springframework.cloud.sleuth.instrument.web.client.feign: TRACE