From aa533bc4cb0e13d879d135f562cf81b1dfea047e Mon Sep 17 00:00:00 2001 From: Adrian Cole Date: Tue, 8 Oct 2019 16:47:25 -0700 Subject: [PATCH] Updates to latest Sampling infrastructure (2.1.x) (#1461) * Updates to latest Sampling infrastructure (2.1.x) This adapts #1456 for the 2.1.x branch --- benchmarks/pom.xml | 2 +- .../main/asciidoc/spring-cloud-sleuth.adoc | 50 ++++- pom.xml | 2 +- spring-cloud-sleuth-core/pom.xml | 4 + .../grpc/TraceGrpcAutoConfiguration.java | 11 +- .../instrument/rpc/RpcClientSampler.java | 50 +++++ .../instrument/rpc/RpcServerSampler.java | 50 +++++ .../rpc/TraceRpcAutoConfiguration.java | 73 +++++++ .../sleuth/instrument/web/ClientSampler.java | 2 + .../instrument/web/HttpClientSampler.java | 50 +++++ .../instrument/web/HttpServerSampler.java | 50 +++++ .../sleuth/instrument/web/ServerSampler.java | 2 + ...java => SkipPatternHttpServerSampler.java} | 12 +- .../web/TraceHttpAutoConfiguration.java | 61 +++--- .../TraceWebClientAutoConfiguration.java | 3 +- .../main/resources/META-INF/spring.factories | 1 + ...raceAutoConfigurationCustomizersTests.java | 13 +- ...eRpcAutoConfigurationIntegrationTests.java | 76 +++++++ .../rpc/TraceRpcAutoConfigurationTests.java | 108 ++++++++++ .../web/CompositeHttpSamplerTests.java | 50 +++-- ...=> SkipPatternHttpServerSamplerTests.java} | 18 +- .../instrument/web/TraceFilterTests.java | 7 +- .../web/TraceFilterWebIntegrationTests.java | 28 ++- .../web/TraceHttpAutoConfigurationTests.java | 190 ++++++++++++++++++ .../TraceWebClientAutoConfigurationTests.java | 3 +- spring-cloud-sleuth-samples/pom.xml | 2 +- 26 files changed, 815 insertions(+), 103 deletions(-) create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcClientSampler.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcServerSampler.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfiguration.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpClientSampler.java create mode 100644 spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpServerSampler.java rename spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/{SleuthHttpSampler.java => SkipPatternHttpServerSampler.java} (80%) create mode 100644 spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationIntegrationTests.java create mode 100644 spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationTests.java rename spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/{SleuthHttpSamplerTests.java => SkipPatternHttpServerSamplerTests.java} (72%) create mode 100644 spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfigurationTests.java diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 7fcba0caa..daa5f2101 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -34,7 +34,7 @@ 1.8 1.8 2.1.7.RELEASE - 5.7.0 + 5.8.0 diff --git a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc index 322e98dc1..64c226409 100644 --- a/docs/src/main/asciidoc/spring-cloud-sleuth.adoc +++ b/docs/src/main/asciidoc/spring-cloud-sleuth.adoc @@ -845,21 +845,23 @@ Sleuth will search for beans of those types and automatically apply customizatio === HTTP -If a customization of client / server parsing of the HTTP related spans is required, -just register a bean of type `brave.http.HttpClientParser` or +If a customization of client / server parsing of the HTTP related spans is +required, just register a bean of type `brave.http.HttpClientParser` or `brave.http.HttpServerParser`. If client /server sampling is required, just -register a bean of type `brave.http.HttpSampler` and name the bean - `sleuthClientSampler` for client sampler and `sleuthServerSampler` for server sampler. - For your convenience the `@ClientSampler` and `@ServerSampler` - annotations can be used to inject the proper beans or to - reference the bean names via their static String `NAME` fields. +register a bean of type `brave.sampler.SamplerFunction` and name +the bean `sleuthHttpClientSampler` for client sampler and +`sleuthHttpServerSampler` for server sampler. + +For your convenience the `@HttpClientSampler` and `@HttpServerSampler` +annotations can be used to inject the proper beans or to reference the bean +names via their static String `NAME` fields. Check out Brave's code to see an example of how to make a path-based sampler https://github.com/openzipkin/brave/tree/master/instrumentation/http#sampling-policy If you want to completely rewrite the `HttpTracing` bean you can use the `SkipPatternProvider` interface to retrieve the URL `Pattern` for spans that should be not sampled. Below you can see -an example of usage of `SkipPatternProvider` inside a server side, `HttpSampler`. +an example of usage of `SkipPatternProvider` inside a server side, `Sampler`. [source,java] ---- @@ -881,6 +883,34 @@ In the following example, we register the `TracingFilter` bean, add the `ZIPKIN- include::../../../..//spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterIntegrationTests.java[tags=response_headers,indent=0] ---- +=== RPC + +Sleuth automatically configures the `RpcTracing` bean which serves as a +foundation for RPC instrumentation such as gRPC or Dubbo. + +If a customization of client / server sampling of the RPC traces is required, +just register a bean of type `brave.sampler.SamplerFunction` and +name the bean `sleuthRpcClientSampler` for client sampler and +`sleuthRpcServerSampler` for server sampler. + +For your convenience the `@RpcClientSampler` and `@RpcServerSampler` +annotations can be used to inject the proper beans or to reference the bean +names via their static String `NAME` fields. + +Ex. Here's a sampler that traces 100 "GetUserToken" server requests per second. +This doesn't start new traces for requests to the health check service. Other +requests will use the global sampling configuration. + +[source,java] +---- +@Configuration +class Config { +include::../../../../spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationIntegrationTests.java[tags=custom_rpc_server_sampler,indent=2] +} +---- + +For more, see https://github.com/openzipkin/brave/tree/master/instrumentation/rpc#sampling-policy + === Custom service name By default, Sleuth assumes that, when you send a span to Zipkin, you want the span's service name to be equal to the value of the `spring.application.name` property. @@ -1119,13 +1149,13 @@ To change the order of tracing filter registration, please set the ==== Dubbo RPC support Via the integration with Brave, Spring Cloud Sleuth supports https://dubbo.apache.org/[Dubbo]. -It's enough to add the `brave-instrumentation-dubbo-rpc` dependency: +It's enough to add the `brave-instrumentation-dubbo` dependency: [source,xml,indent=0] ---- io.zipkin.brave - brave-instrumentation-dubbo-rpc + brave-instrumentation-dubbo ---- diff --git a/pom.xml b/pom.xml index 29a90743b..12c897c6c 100644 --- a/pom.xml +++ b/pom.xml @@ -265,7 +265,7 @@ 2.1.4.BUILD-SNAPSHOT 2.1.4.BUILD-SNAPSHOT - 5.7.0 + 5.8.0 2.1.2.RELEASE diff --git a/spring-cloud-sleuth-core/pom.xml b/spring-cloud-sleuth-core/pom.xml index 5ca597e02..b101ad3ef 100644 --- a/spring-cloud-sleuth-core/pom.xml +++ b/spring-cloud-sleuth-core/pom.xml @@ -197,6 +197,10 @@ io.zipkin.brave brave-context-log4j2 + + io.zipkin.brave + brave-instrumentation-rpc + io.zipkin.brave brave-instrumentation-spring-web diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java index 9cf02eb5d..4b333dee1 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/grpc/TraceGrpcAutoConfiguration.java @@ -19,15 +19,17 @@ package org.springframework.cloud.sleuth.instrument.grpc; import java.util.List; import java.util.Optional; -import brave.Tracing; import brave.grpc.GrpcTracing; +import brave.rpc.RpcTracing; import io.grpc.ServerInterceptor; import org.lognet.springboot.grpc.GRpcGlobalInterceptor; +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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.sleuth.instrument.rpc.TraceRpcAutoConfiguration; import org.springframework.context.annotation.Bean; /** @@ -41,12 +43,13 @@ import org.springframework.context.annotation.Bean; */ @ConditionalOnClass({ GrpcTracing.class, GRpcGlobalInterceptor.class }) @ConditionalOnProperty(value = "spring.sleuth.grpc.enabled", matchIfMissing = true) -@ConditionalOnBean(Tracing.class) +@ConditionalOnBean(RpcTracing.class) +@AutoConfigureAfter(TraceRpcAutoConfiguration.class) public class TraceGrpcAutoConfiguration { @Bean - public GrpcTracing grpcTracing(Tracing tracing) { - return GrpcTracing.create(tracing); + public GrpcTracing grpcTracing(RpcTracing rpcTracing) { + return GrpcTracing.create(rpcTracing); } // Register a global interceptor for both the server diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcClientSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcClientSampler.java new file mode 100644 index 000000000..689eef752 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcClientSampler.java @@ -0,0 +1,50 @@ +/* + * 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.rpc; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import brave.sampler.SamplerFunction; + +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * Annotate a client {@link brave.sampler.SamplerFunction} that should be injected to + * {@link brave.rpc.RpcTracing.Builder#clientSampler(SamplerFunction)}. + * + * @since 2.2.0 + * @see Qualifier + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, + ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Qualifier(RpcClientSampler.NAME) +public @interface RpcClientSampler { + + /** + * Default name for RPC client sampler. + */ + String NAME = "sleuthRpcClientSampler"; + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcServerSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcServerSampler.java new file mode 100644 index 000000000..195116410 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/RpcServerSampler.java @@ -0,0 +1,50 @@ +/* + * 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.rpc; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import brave.sampler.SamplerFunction; + +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * Annotate a server {@link brave.sampler.SamplerFunction} that should be injected to + * {@link brave.rpc.RpcTracing.Builder#serverSampler(SamplerFunction)}. + * + * @since 2.2.0 + * @see Qualifier + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, + ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Qualifier(RpcServerSampler.NAME) +public @interface RpcServerSampler { + + /** + * Default name for RPC server sampler. + */ + String NAME = "sleuthRpcServerSampler"; + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfiguration.java new file mode 100644 index 000000000..77e775219 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfiguration.java @@ -0,0 +1,73 @@ +/* + * 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.rpc; + +import java.util.ArrayList; +import java.util.List; + +import brave.Tracing; +import brave.rpc.RpcRequest; +import brave.rpc.RpcTracing; +import brave.rpc.RpcTracingCustomizer; +import brave.sampler.SamplerFunction; + +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.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; + +/** + * {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration + * Auto-configuration} related to RPC based communication. + * + * @since 2.2.0 + */ +@Configuration +@ConditionalOnProperty(name = "spring.sleuth.rpc.enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnBean(Tracing.class) +@AutoConfigureAfter(TraceAutoConfiguration.class) +public class TraceRpcAutoConfiguration { + + @Autowired(required = false) + List rpcTracingCustomizers = new ArrayList<>(); + + @Bean + @ConditionalOnMissingBean + // NOTE: stable bean name as might be used outside sleuth + RpcTracing rpcTracing(Tracing tracing, + @Nullable @RpcClientSampler SamplerFunction clientSampler, + @Nullable @RpcServerSampler SamplerFunction serverSampler) { + + RpcTracing.Builder builder = RpcTracing.newBuilder(tracing); + if (clientSampler != null) { + builder.clientSampler(clientSampler); + } + if (serverSampler != null) { + builder.serverSampler(serverSampler); + } + for (RpcTracingCustomizer customizer : this.rpcTracingCustomizers) { + customizer.customize(builder); + } + return builder.build(); + } + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ClientSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ClientSampler.java index 7b58cc5df..21bb50cd5 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ClientSampler.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ClientSampler.java @@ -32,6 +32,7 @@ import org.springframework.beans.factory.annotation.Qualifier; * @author Marcin Grzejszczak * @since 2.0.0 * @see Qualifier + * @deprecated Since 2.2.0, please use {@link HttpClientSampler} */ @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @@ -39,6 +40,7 @@ import org.springframework.beans.factory.annotation.Qualifier; @Inherited @Documented @Qualifier(ClientSampler.NAME) +@Deprecated public @interface ClientSampler { /** diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpClientSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpClientSampler.java new file mode 100644 index 000000000..fbf748196 --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpClientSampler.java @@ -0,0 +1,50 @@ +/* + * 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.web; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import brave.sampler.SamplerFunction; + +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * Annotate a client {@link brave.sampler.SamplerFunction} that should be injected to + * {@link brave.http.HttpTracing.Builder#clientSampler(SamplerFunction)}. + * + * @since 2.2.0 + * @see Qualifier + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, + ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Qualifier(HttpClientSampler.NAME) +public @interface HttpClientSampler { + + /** + * Default name for Sleuth HTTP client sampler. + */ + String NAME = "sleuthHttpClientSampler"; + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpServerSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpServerSampler.java new file mode 100644 index 000000000..a725de02d --- /dev/null +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/HttpServerSampler.java @@ -0,0 +1,50 @@ +/* + * 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.web; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import brave.sampler.SamplerFunction; + +import org.springframework.beans.factory.annotation.Qualifier; + +/** + * Annotate a client {@link brave.sampler.SamplerFunction} that should be injected to + * {@link brave.http.HttpTracing.Builder#serverSampler(SamplerFunction)}. + * + * @since 2.2.0 + * @see Qualifier + */ +@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, + ElementType.ANNOTATION_TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@Documented +@Qualifier(HttpServerSampler.NAME) +public @interface HttpServerSampler { + + /** + * Default name for the Sleuth HTTP server sampler. + */ + String NAME = "sleuthHttpServerSampler"; + +} diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ServerSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ServerSampler.java index f0a807f4f..fccf26a3b 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ServerSampler.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/ServerSampler.java @@ -32,6 +32,7 @@ import org.springframework.beans.factory.annotation.Qualifier; * @author Marcin Grzejszczak * @since 2.0.0 * @see Qualifier + * @deprecated Since 2.2.0, please use {@link HttpServerSampler} */ @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE }) @@ -39,6 +40,7 @@ import org.springframework.beans.factory.annotation.Qualifier; @Inherited @Documented @Qualifier(ServerSampler.NAME) +@Deprecated public @interface ServerSampler { /** diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SleuthHttpSampler.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SkipPatternHttpServerSampler.java similarity index 80% rename from spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SleuthHttpSampler.java rename to spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SkipPatternHttpServerSampler.java index 35e5f736c..4e00022f0 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SleuthHttpSampler.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/SkipPatternHttpServerSampler.java @@ -18,8 +18,8 @@ package org.springframework.cloud.sleuth.instrument.web; import java.util.regex.Pattern; -import brave.http.HttpAdapter; -import brave.http.HttpSampler; +import brave.http.HttpRequest; +import brave.sampler.SamplerFunction; /** * Doesn't sample a span if skip pattern is matched. @@ -27,19 +27,19 @@ import brave.http.HttpSampler; * @author Marcin Grzejszczak * @since 2.0.0 */ -class SleuthHttpSampler extends HttpSampler { +class SkipPatternHttpServerSampler implements SamplerFunction { private final SkipPatternProvider provider; private Pattern pattern; - SleuthHttpSampler(SkipPatternProvider provider) { + SkipPatternHttpServerSampler(SkipPatternProvider provider) { this.provider = provider; } @Override - public Boolean trySample(HttpAdapter adapter, Req request) { - String url = adapter.path(request); + public Boolean trySample(HttpRequest request) { + String url = request.path(); boolean shouldSkip = pattern().matcher(url).matches(); if (shouldSkip) { return false; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfiguration.java index 7a9166c8f..6075139d5 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfiguration.java @@ -21,12 +21,13 @@ import java.util.List; import brave.ErrorParser; import brave.Tracing; -import brave.http.HttpAdapter; import brave.http.HttpClientParser; +import brave.http.HttpRequest; import brave.http.HttpSampler; import brave.http.HttpServerParser; import brave.http.HttpTracing; import brave.http.HttpTracingCustomizer; +import brave.sampler.SamplerFunction; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -63,22 +64,28 @@ public class TraceHttpAutoConfiguration { // NOTE: stable bean name as might be used outside sleuth HttpTracing httpTracing(Tracing tracing, SkipPatternProvider provider, HttpClientParser clientParser, HttpServerParser serverParser, - @ClientSampler HttpSampler clientSampler, - @Nullable @ServerSampler HttpSampler serverSampler) { - HttpSampler combinedSampler = combineUserProvidedSamplerWithSkipPatternSampler( - serverSampler, provider); + @HttpClientSampler SamplerFunction httpClientSampler, + @Nullable @ServerSampler HttpSampler serverSampler, + @Nullable @HttpServerSampler SamplerFunction httpServerSampler) { + if (httpServerSampler == null) { + httpServerSampler = serverSampler; + } + SamplerFunction combinedSampler = combineUserProvidedSamplerWithSkipPatternSampler( + httpServerSampler, provider); HttpTracing.Builder builder = HttpTracing.newBuilder(tracing) .clientParser(clientParser).serverParser(serverParser) - .clientSampler(clientSampler).serverSampler(combinedSampler); + .clientSampler(httpClientSampler).serverSampler(combinedSampler); for (HttpTracingCustomizer customizer : this.httpTracingCustomizers) { customizer.customize(builder); } return builder.build(); } - private HttpSampler combineUserProvidedSamplerWithSkipPatternSampler( - HttpSampler serverSampler, SkipPatternProvider provider) { - SleuthHttpSampler skipPatternSampler = new SleuthHttpSampler(provider); + private SamplerFunction combineUserProvidedSamplerWithSkipPatternSampler( + @Nullable SamplerFunction serverSampler, + SkipPatternProvider provider) { + SkipPatternHttpServerSampler skipPatternSampler = new SkipPatternHttpServerSampler( + provider); if (serverSampler == null) { return skipPatternSampler; } @@ -118,9 +125,14 @@ public class TraceHttpAutoConfiguration { } @Bean - @ConditionalOnMissingBean(name = ClientSampler.NAME) - HttpSampler sleuthClientSampler(SleuthWebProperties sleuthWebProperties) { - return new PathMatchingHttpSampler(sleuthWebProperties); + @ConditionalOnMissingBean(name = HttpClientSampler.NAME) + SamplerFunction sleuthHttpClientSampler( + @Nullable @ClientSampler HttpSampler sleuthClientSampler, + SleuthWebProperties sleuthWebProperties) { + if (sleuthClientSampler != null) { + return sleuthClientSampler; + } + return new SkipPatternHttpClientSampler(sleuthWebProperties); } } @@ -130,25 +142,26 @@ public class TraceHttpAutoConfiguration { * * @author Adrian Cole */ -class CompositeHttpSampler extends HttpSampler { +class CompositeHttpSampler implements SamplerFunction { - private final HttpSampler left; + final SamplerFunction left; - private final HttpSampler right; + final SamplerFunction right; - CompositeHttpSampler(HttpSampler left, HttpSampler right) { + CompositeHttpSampler(SamplerFunction left, + SamplerFunction right) { this.left = left; this.right = right; } @Override - public Boolean trySample(HttpAdapter adapter, Req request) { + public Boolean trySample(HttpRequest request) { // If either decision is false, return false - Boolean leftDecision = this.left.trySample(adapter, request); + Boolean leftDecision = this.left.trySample(request); if (Boolean.FALSE.equals(leftDecision)) { return false; } - Boolean rightDecision = this.right.trySample(adapter, request); + Boolean rightDecision = this.right.trySample(request); if (Boolean.FALSE.equals(rightDecision)) { return false; } @@ -160,7 +173,7 @@ class CompositeHttpSampler extends HttpSampler { return leftDecision; } // Neither are null and at least one is true - return leftDecision && rightDecision; + return rightDecision; } } @@ -170,17 +183,17 @@ class CompositeHttpSampler extends HttpSampler { * * @author Marcin Grzejszczak */ -class PathMatchingHttpSampler extends HttpSampler { +class SkipPatternHttpClientSampler implements SamplerFunction { private final SleuthWebProperties properties; - PathMatchingHttpSampler(SleuthWebProperties properties) { + SkipPatternHttpClientSampler(SleuthWebProperties properties) { this.properties = properties; } @Override - public Boolean trySample(HttpAdapter adapter, Req request) { - String path = adapter.path(request); + public Boolean trySample(HttpRequest request) { + String path = request.path(); if (path == null) { return null; } diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java index 916b589b4..3028c6f90 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfiguration.java @@ -237,7 +237,8 @@ class RestTemplateInterceptorInjector { private boolean hasTraceInterceptor(RestTemplate restTemplate) { for (ClientHttpRequestInterceptor interceptor : restTemplate.getInterceptors()) { - if (interceptor instanceof TracingClientHttpRequestInterceptor || interceptor instanceof LazyTracingClientHttpRequestInterceptor) { + if (interceptor instanceof TracingClientHttpRequestInterceptor + || interceptor instanceof LazyTracingClientHttpRequestInterceptor) { return true; } } diff --git a/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories b/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories index db0e76446..4544463d5 100644 --- a/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-sleuth-core/src/main/resources/META-INF/spring.factories @@ -20,6 +20,7 @@ org.springframework.cloud.sleuth.instrument.rxjava.RxJavaAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.reactor.TraceReactorAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.web.TraceWebFluxAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.zuul.TraceZuulAutoConfiguration,\ +org.springframework.cloud.sleuth.instrument.rpc.TraceRpcAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.grpc.TraceGrpcAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.messaging.TraceMessagingAutoConfiguration,\ org.springframework.cloud.sleuth.instrument.messaging.TraceSpringIntegrationAutoConfiguration,\ diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfigurationCustomizersTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfigurationCustomizersTests.java index dd767eb52..ee357b0c8 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfigurationCustomizersTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/autoconfig/TraceAutoConfigurationCustomizersTests.java @@ -20,12 +20,14 @@ import brave.TracingCustomizer; import brave.http.HttpTracingCustomizer; import brave.propagation.CurrentTraceContextCustomizer; import brave.propagation.ExtraFieldCustomizer; +import brave.rpc.RpcTracingCustomizer; import brave.sampler.Sampler; import org.junit.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.instrument.rpc.TraceRpcAutoConfiguration; import org.springframework.cloud.sleuth.instrument.web.TraceHttpAutoConfiguration; import org.springframework.cloud.sleuth.instrument.web.TraceWebAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -38,7 +40,8 @@ public class TraceAutoConfigurationCustomizersTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues("spring.sleuth.baggage-keys=my-baggage") .withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class, - TraceWebAutoConfiguration.class, TraceHttpAutoConfiguration.class)) + TraceWebAutoConfiguration.class, TraceHttpAutoConfiguration.class, + TraceRpcAutoConfiguration.class)) .withUserConfiguration(Customizers.class); @Test @@ -60,6 +63,7 @@ public class TraceAutoConfigurationCustomizersTests { then(bean.contextCustomizerApplied).isTrue(); then(bean.extraFieldCustomizerApplied).isTrue(); then(bean.httpCustomizerApplied).isTrue(); + then(bean.rpcCustomizerApplied).isTrue(); } @Configuration @@ -73,6 +77,8 @@ public class TraceAutoConfigurationCustomizersTests { boolean httpCustomizerApplied; + boolean rpcCustomizerApplied; + @Bean TracingCustomizer sleuthTracingCustomizer() { return builder -> tracingCustomizerApplied = true; @@ -93,6 +99,11 @@ public class TraceAutoConfigurationCustomizersTests { return builder -> httpCustomizerApplied = true; } + @Bean + RpcTracingCustomizer sleuthRpcTracingCustomizer() { + return builder -> rpcCustomizerApplied = true; + } + @Bean Sampler sampler() { return Sampler.ALWAYS_SAMPLE; diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationIntegrationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationIntegrationTests.java new file mode 100644 index 000000000..d5d9dbbe7 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationIntegrationTests.java @@ -0,0 +1,76 @@ +/* + * 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.rpc; + +import brave.rpc.RpcRequest; +import brave.rpc.RpcRuleSampler; +import brave.sampler.Matcher; +import brave.sampler.RateLimitingSampler; +import brave.sampler.Sampler; +import brave.sampler.SamplerFunction; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +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 static brave.rpc.RpcRequestMatchers.methodEquals; +import static brave.rpc.RpcRequestMatchers.serviceEquals; +import static brave.sampler.Matchers.and; +import static org.assertj.core.api.BDDAssertions.then; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TraceRpcAutoConfigurationIntegrationTests.Config.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) +public class TraceRpcAutoConfigurationIntegrationTests { + + @Autowired + @RpcServerSampler + SamplerFunction sampler; + + @Test + public void should_inject_rpc_sampler() { + then(this.sampler).isNotNull(); + } + + @EnableAutoConfiguration + @Configuration + public static class Config { + + @Bean + ArrayListSpanReporter reporter() { + return new ArrayListSpanReporter(); + } + + // tag::custom_rpc_server_sampler[] + @Bean(name = RpcServerSampler.NAME) + SamplerFunction myRpcSampler() { + Matcher userAuth = and(serviceEquals("users.UserService"), + methodEquals("GetUserToken")); + return RpcRuleSampler.newBuilder() + .putRule(serviceEquals("grpc.health.v1.Health"), Sampler.NEVER_SAMPLE) + .putRule(userAuth, RateLimitingSampler.create(100)).build(); + } + // end::custom_rpc_server_sampler[] + + } + +} diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationTests.java new file mode 100644 index 000000000..ba71b65ae --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/rpc/TraceRpcAutoConfigurationTests.java @@ -0,0 +1,108 @@ +/* + * 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.rpc; + +import brave.rpc.RpcRequest; +import brave.rpc.RpcTracing; +import brave.sampler.SamplerFunction; +import brave.sampler.SamplerFunctions; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.BDDAssertions.then; + +public class TraceRpcAutoConfigurationTests { + + @Test + public void defaultsToBraveRpcClientSampler() { + contextRunner().run((context) -> { + SamplerFunction clientSampler = context.getBean(RpcTracing.class) + .clientSampler(); + + then(clientSampler).isSameAs(SamplerFunctions.deferDecision()); + }); + } + + @Test + public void configuresUserProvidedRpcClientSampler() { + contextRunner().withUserConfiguration(RpcClientSamplerConfig.class) + .run((context) -> { + SamplerFunction clientSampler = context + .getBean(RpcTracing.class).clientSampler(); + + then(clientSampler).isSameAs(RpcClientSamplerConfig.INSTANCE); + }); + } + + @Test + public void defaultsToBraveRpcServerSampler() { + contextRunner().run((context) -> { + SamplerFunction serverSampler = context.getBean(RpcTracing.class) + .serverSampler(); + + then(serverSampler).isSameAs(SamplerFunctions.deferDecision()); + }); + } + + @Test + public void configuresUserProvidedRpcServerSampler() { + contextRunner().withUserConfiguration(RpcServerSamplerConfig.class) + .run((context) -> { + SamplerFunction serverSampler = context + .getBean(RpcTracing.class).serverSampler(); + + then(serverSampler).isSameAs(RpcServerSamplerConfig.INSTANCE); + }); + } + + private ApplicationContextRunner contextRunner(String... propertyValues) { + return new ApplicationContextRunner().withPropertyValues(propertyValues) + .withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class, + TraceRpcAutoConfiguration.class, + TraceRpcAutoConfiguration.class)); + } + +} + +@Configuration +class RpcClientSamplerConfig { + + static final SamplerFunction INSTANCE = request -> null; + + @Bean(RpcClientSampler.NAME) + SamplerFunction sleuthRpcClientSampler() { + return INSTANCE; + } + +} + +@Configuration +class RpcServerSamplerConfig { + + static final SamplerFunction INSTANCE = request -> null; + + @Bean(RpcServerSampler.NAME) + SamplerFunction sleuthRpcServerSampler() { + return INSTANCE; + } + +} diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/CompositeHttpSamplerTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/CompositeHttpSamplerTests.java index 66bf56f65..51ce2c4cf 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/CompositeHttpSamplerTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/CompositeHttpSamplerTests.java @@ -16,8 +16,8 @@ package org.springframework.cloud.sleuth.instrument.web; -import brave.http.HttpAdapter; -import brave.http.HttpSampler; +import brave.http.HttpRequest; +import brave.sampler.SamplerFunction; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,17 +31,15 @@ import static org.mockito.BDDMockito.given; public class CompositeHttpSamplerTests { @Mock - HttpAdapter adapter; + SamplerFunction left; @Mock - HttpSampler left; + SamplerFunction right; @Mock - HttpSampler right; + HttpRequest request; - HttpSampler sampler; - - Object request = new Object(); + SamplerFunction sampler; @Before public void init() { @@ -50,41 +48,41 @@ public class CompositeHttpSamplerTests { @Test public void should_return_null_on_both_null() { - given(this.left.trySample(this.adapter, this.request)).willReturn(null); - given(this.right.trySample(this.adapter, this.request)).willReturn(null); + given(this.left.trySample(this.request)).willReturn(null); + given(this.right.trySample(this.request)).willReturn(null); - then(this.sampler.trySample(this.adapter, this.request)).isNull(); + then(this.sampler.trySample(this.request)).isNull(); } @Test public void should_return_false_on_any_false() { - given(this.left.trySample(this.adapter, this.request)).willReturn(false); - given(this.right.trySample(this.adapter, this.request)).willReturn(null); + given(this.left.trySample(this.request)).willReturn(false); + given(this.right.trySample(this.request)).willReturn(null); - then(this.sampler.trySample(this.adapter, this.request)).isFalse(); + then(this.sampler.trySample(this.request)).isFalse(); - given(this.left.trySample(this.adapter, this.request)).willReturn(null); - given(this.right.trySample(this.adapter, this.request)).willReturn(false); + given(this.left.trySample(this.request)).willReturn(null); + given(this.right.trySample(this.request)).willReturn(false); - then(this.sampler.trySample(this.adapter, this.request)).isFalse(); + then(this.sampler.trySample(this.request)).isFalse(); - given(this.left.trySample(this.adapter, this.request)).willReturn(false); - given(this.right.trySample(this.adapter, this.request)).willReturn(true); + given(this.left.trySample(this.request)).willReturn(false); + given(this.right.trySample(this.request)).willReturn(true); - then(this.sampler.trySample(this.adapter, this.request)).isFalse(); + then(this.sampler.trySample(this.request)).isFalse(); - given(this.left.trySample(this.adapter, this.request)).willReturn(true); - given(this.right.trySample(this.adapter, this.request)).willReturn(false); + given(this.left.trySample(this.request)).willReturn(true); + given(this.right.trySample(this.request)).willReturn(false); - then(this.sampler.trySample(this.adapter, this.request)).isFalse(); + then(this.sampler.trySample(this.request)).isFalse(); } @Test public void should_return_true_on_both_true() { - given(this.left.trySample(this.adapter, this.request)).willReturn(true); - given(this.right.trySample(this.adapter, this.request)).willReturn(true); + given(this.left.trySample(this.request)).willReturn(true); + given(this.right.trySample(this.request)).willReturn(true); - then(this.sampler.trySample(this.adapter, this.request)).isTrue(); + then(this.sampler.trySample(this.request)).isTrue(); } } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SleuthHttpSamplerTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SkipPatternHttpServerSamplerTests.java similarity index 72% rename from spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SleuthHttpSamplerTests.java rename to spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SkipPatternHttpServerSamplerTests.java index decbded42..49389a872 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SleuthHttpSamplerTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/SkipPatternHttpServerSamplerTests.java @@ -18,7 +18,7 @@ package org.springframework.cloud.sleuth.instrument.web; import java.util.regex.Pattern; -import brave.http.HttpAdapter; +import brave.http.HttpRequest; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.BDDMockito; @@ -31,27 +31,27 @@ import static org.assertj.core.api.BDDAssertions.then; * @author Marcin Grzejszczak */ @RunWith(MockitoJUnitRunner.class) -public class SleuthHttpSamplerTests { +public class SkipPatternHttpServerSamplerTests { @Mock - HttpAdapter adapter; + HttpRequest request; @Test public void should_delegate_sampling_decision_if_pattern_is_not_matched() { SkipPatternProvider provider = () -> Pattern.compile("foo"); - BDDMockito.given(this.adapter.path(BDDMockito.any())).willReturn("url"); - SleuthHttpSampler sampler = new SleuthHttpSampler(provider); + BDDMockito.given(this.request.path()).willReturn("url"); + SkipPatternHttpServerSampler sampler = new SkipPatternHttpServerSampler(provider); - then(sampler.trySample(this.adapter, new Object())).isNull(); + then(sampler.trySample(this.request)).isNull(); } @Test public void should_not_sample_if_pattern_is_matched() { SkipPatternProvider provider = () -> Pattern.compile(".*"); - BDDMockito.given(this.adapter.path(BDDMockito.any())).willReturn("url"); - SleuthHttpSampler sampler = new SleuthHttpSampler(provider); + BDDMockito.given(this.request.path()).willReturn("url"); + SkipPatternHttpServerSampler sampler = new SkipPatternHttpServerSampler(provider); - then(sampler.trySample(this.adapter, new Object())).isFalse(); + then(sampler.trySample(this.request)).isFalse(); } } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java index 5447472a6..09498b586 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterTests.java @@ -75,7 +75,8 @@ public class TraceFilterTests { HttpTracing httpTracing = HttpTracing.newBuilder(this.tracing) .clientParser(new SleuthHttpClientParser(this.traceKeys)) .serverParser(new SleuthHttpServerParser(this.traceKeys, new ErrorParser())) - .serverSampler(new SleuthHttpSampler(() -> Pattern.compile(""))).build(); + .serverSampler(new SkipPatternHttpServerSampler(() -> Pattern.compile(""))) + .build(); Filter filter = TracingFilter.create(this.httpTracing); @@ -124,7 +125,9 @@ public class TraceFilterTests { .clientParser(new SleuthHttpClientParser(this.traceKeys)) .serverParser( new SleuthHttpServerParser(this.traceKeys, new ErrorParser())) - .serverSampler(new SleuthHttpSampler(() -> Pattern.compile(""))).build(); + .serverSampler( + new SkipPatternHttpServerSampler(() -> Pattern.compile(""))) + .build(); return TracingFilter.create(httpTracing); } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java index 78e13db15..0e480a9e1 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationTests.java @@ -23,9 +23,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import brave.Tracing; -import brave.http.HttpAdapter; -import brave.http.HttpSampler; +import brave.http.HttpRequest; import brave.sampler.Sampler; +import brave.sampler.SamplerFunction; import org.assertj.core.api.BDDAssertions; import org.junit.After; import org.junit.Before; @@ -72,8 +72,8 @@ public class TraceFilterWebIntegrationTests { ArrayListSpanReporter accumulator; @Autowired - @ServerSampler - HttpSampler sampler; + @HttpServerSampler + SamplerFunction sampler; @Autowired Environment environment; @@ -161,20 +161,16 @@ public class TraceFilterWebIntegrationTests { } // tag::custom_server_sampler[] - @Bean(name = ServerSampler.NAME) - HttpSampler myHttpSampler(SkipPatternProvider provider) { + @Bean(name = HttpServerSampler.NAME) + SamplerFunction myHttpSampler(SkipPatternProvider provider) { Pattern pattern = provider.skipPattern(); - return new HttpSampler() { - - @Override - public Boolean trySample(HttpAdapter adapter, Req request) { - String url = adapter.path(request); - boolean shouldSkip = pattern.matcher(url).matches(); - if (shouldSkip) { - return false; - } - return null; + return request -> { + String url = request.path(); + boolean shouldSkip = pattern.matcher(url).matches(); + if (shouldSkip) { + return false; } + return null; }; } // end::custom_server_sampler[] diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfigurationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfigurationTests.java new file mode 100644 index 000000000..a5206db89 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceHttpAutoConfigurationTests.java @@ -0,0 +1,190 @@ +/* + * 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.web; + +import brave.http.HttpAdapter; +import brave.http.HttpRequest; +import brave.http.HttpSampler; +import brave.http.HttpTracing; +import brave.sampler.SamplerFunction; +import org.junit.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.context.runner.ContextConsumer; +import org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.BDDAssertions.then; + +public class TraceHttpAutoConfigurationTests { + + @Test + public void defaultsToSkipPatternHttpClientSampler() { + contextRunner().run((context) -> { + SamplerFunction clientSampler = context + .getBean(HttpTracing.class).clientRequestSampler(); + + then(clientSampler).isInstanceOf(SkipPatternHttpClientSampler.class); + }); + } + + @Test + public void configuresUserProvidedDeprecatedClientSampler() { + contextRunner().withUserConfiguration(DeprecatedClientSamplerConfig.class) + .run((context) -> { + SamplerFunction clientSampler = context + .getBean(HttpTracing.class).clientRequestSampler(); + + then(clientSampler).isSameAs(DeprecatedClientSamplerConfig.INSTANCE); + }); + } + + @Test + public void configuresUserProvidedHttpClientSampler() { + contextRunner().withUserConfiguration(HttpClientSamplerConfig.class) + .run((context) -> { + SamplerFunction clientSampler = context + .getBean(HttpTracing.class).clientRequestSampler(); + + then(clientSampler).isSameAs(HttpClientSamplerConfig.INSTANCE); + }); + } + + @Test + public void prefersUserProvidedHttpClientSampler() { + contextRunner().withUserConfiguration(DeprecatedClientSamplerConfig.class) + .withUserConfiguration(HttpClientSamplerConfig.class).run((context) -> { + SamplerFunction clientSampler = context + .getBean(HttpTracing.class).clientRequestSampler(); + + then(clientSampler).isSameAs(HttpClientSamplerConfig.INSTANCE); + }); + } + + @Test + public void defaultsToSkipPatternHttpServerSampler() { + contextRunner().run((context) -> { + SamplerFunction serverSampler = context + .getBean(HttpTracing.class).serverRequestSampler(); + + then(serverSampler).isInstanceOf(SkipPatternHttpServerSampler.class); + }); + } + + @Test + public void wrapsUserProvidedDeprecatedServerSampler() { + contextRunner().withUserConfiguration(DeprecatedServerSamplerConfig.class).run( + thenCompositeHttpServerSamplerOf(DeprecatedServerSamplerConfig.INSTANCE)); + } + + @Test + public void wrapsUserProvidedHttpServerSampler() { + contextRunner().withUserConfiguration(HttpServerSamplerConfig.class) + .run(thenCompositeHttpServerSamplerOf(HttpServerSamplerConfig.INSTANCE)); + } + + @Test + public void prefersUserProvidedUserProvidedHttpServerSampler() { + contextRunner().withUserConfiguration(HttpServerSamplerConfig.class) + .withUserConfiguration(DeprecatedServerSamplerConfig.class) + .run(thenCompositeHttpServerSamplerOf(HttpServerSamplerConfig.INSTANCE)); + } + + private ContextConsumer thenCompositeHttpServerSamplerOf( + SamplerFunction instance) { + return (context) -> { + + SamplerFunction serverSampler = context + .getBean(HttpTracing.class).serverRequestSampler(); + + then(serverSampler).isInstanceOf(CompositeHttpSampler.class); + + then(((CompositeHttpSampler) serverSampler).left) + .isInstanceOf(SkipPatternHttpServerSampler.class); + then(((CompositeHttpSampler) serverSampler).right).isSameAs(instance); + }; + } + + private ApplicationContextRunner contextRunner(String... propertyValues) { + return new ApplicationContextRunner().withPropertyValues(propertyValues) + .withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class, + TraceHttpAutoConfiguration.class, + TraceWebAutoConfiguration.class)); + } + +} + +@Configuration +class HttpClientSamplerConfig { + + static final SamplerFunction INSTANCE = request -> null; + + @Bean(HttpClientSampler.NAME) + SamplerFunction sleuthHttpClientSampler() { + return INSTANCE; + } + +} + +@Configuration +class DeprecatedClientSamplerConfig { + + static final HttpSampler INSTANCE = new HttpSampler() { + @Override + public Boolean trySample(HttpAdapter httpAdapter, Req req) { + return null; + } + }; + + @Bean(ClientSampler.NAME) + HttpSampler sleuthClientSampler() { + return INSTANCE; + } + +} + +@Configuration +class HttpServerSamplerConfig { + + static final SamplerFunction INSTANCE = request -> null; + + @Bean(HttpServerSampler.NAME) + SamplerFunction sleuthHttpServerSampler() { + return INSTANCE; + } + +} + +@Configuration +class DeprecatedServerSamplerConfig { + + static final HttpSampler INSTANCE = new HttpSampler() { + @Override + public Boolean trySample(HttpAdapter httpAdapter, Req req) { + return null; + } + }; + + @Bean(ServerSampler.NAME) + HttpSampler sleuthServerSampler() { + return INSTANCE; + } + +} diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java index 3bf6ba104..a8f81a8ed 100644 --- a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/client/TraceWebClientAutoConfigurationTests.java @@ -104,7 +104,8 @@ public class TraceWebClientAutoConfigurationTests { .containsOnlyElementsOf(Collections.singletonList(1)); } - private void incrementNumberOfInstances(Map numberOfInstances, ClientHttpRequestInterceptor interceptor) { + private void incrementNumberOfInstances(Map numberOfInstances, + ClientHttpRequestInterceptor interceptor) { Integer no = numberOfInstances.get(interceptor.getClass()); if (no == null) { numberOfInstances.put(interceptor.getClass(), 1); diff --git a/spring-cloud-sleuth-samples/pom.xml b/spring-cloud-sleuth-samples/pom.xml index 6b2427694..2f144c023 100644 --- a/spring-cloud-sleuth-samples/pom.xml +++ b/spring-cloud-sleuth-samples/pom.xml @@ -73,7 +73,7 @@ io.zipkin.zipkin2 zipkin - 2.16.0 + 2.17.0