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
This commit is contained in:
committed by
Marcin Grzejszczak
parent
ac7dd52544
commit
aa533bc4cb
@@ -34,7 +34,7 @@
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<spring-boot.version>2.1.7.RELEASE</spring-boot.version>
|
||||
<brave.version>5.7.0</brave.version>
|
||||
<brave.version>5.8.0</brave.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -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<HttpRequest>` 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<HttpRequest>`.
|
||||
|
||||
[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<RpcRequest>` 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]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-instrumentation-dubbo-rpc</artifactId>
|
||||
<artifactId>brave-instrumentation-dubbo</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -265,7 +265,7 @@
|
||||
<spring-cloud-netflix.version>2.1.4.BUILD-SNAPSHOT</spring-cloud-netflix.version>
|
||||
<spring-cloud-openfeign.version>2.1.4.BUILD-SNAPSHOT
|
||||
</spring-cloud-openfeign.version>
|
||||
<brave.version>5.7.0</brave.version>
|
||||
<brave.version>5.8.0</brave.version>
|
||||
<spring-security-boot-autoconfigure.version>2.1.2.RELEASE
|
||||
</spring-security-boot-autoconfigure.version>
|
||||
|
||||
|
||||
@@ -197,6 +197,10 @@
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-context-log4j2</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-instrumentation-rpc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.zipkin.brave</groupId>
|
||||
<artifactId>brave-instrumentation-spring-web</artifactId>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
@@ -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<RpcTracingCustomizer> rpcTracingCustomizers = new ArrayList<>();
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
// NOTE: stable bean name as might be used outside sleuth
|
||||
RpcTracing rpcTracing(Tracing tracing,
|
||||
@Nullable @RpcClientSampler SamplerFunction<RpcRequest> clientSampler,
|
||||
@Nullable @RpcServerSampler SamplerFunction<RpcRequest> 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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
@@ -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<HttpRequest> {
|
||||
|
||||
private final SkipPatternProvider provider;
|
||||
|
||||
private Pattern pattern;
|
||||
|
||||
SleuthHttpSampler(SkipPatternProvider provider) {
|
||||
SkipPatternHttpServerSampler(SkipPatternProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Req> Boolean trySample(HttpAdapter<Req, ?> 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;
|
||||
@@ -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<HttpRequest> httpClientSampler,
|
||||
@Nullable @ServerSampler HttpSampler serverSampler,
|
||||
@Nullable @HttpServerSampler SamplerFunction<HttpRequest> httpServerSampler) {
|
||||
if (httpServerSampler == null) {
|
||||
httpServerSampler = serverSampler;
|
||||
}
|
||||
SamplerFunction<HttpRequest> 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<HttpRequest> combineUserProvidedSamplerWithSkipPatternSampler(
|
||||
@Nullable SamplerFunction<HttpRequest> 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<HttpRequest> 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<HttpRequest> {
|
||||
|
||||
private final HttpSampler left;
|
||||
final SamplerFunction<HttpRequest> left;
|
||||
|
||||
private final HttpSampler right;
|
||||
final SamplerFunction<HttpRequest> right;
|
||||
|
||||
CompositeHttpSampler(HttpSampler left, HttpSampler right) {
|
||||
CompositeHttpSampler(SamplerFunction<HttpRequest> left,
|
||||
SamplerFunction<HttpRequest> right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Req> Boolean trySample(HttpAdapter<Req, ?> 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<HttpRequest> {
|
||||
|
||||
private final SleuthWebProperties properties;
|
||||
|
||||
PathMatchingHttpSampler(SleuthWebProperties properties) {
|
||||
SkipPatternHttpClientSampler(SleuthWebProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Req> Boolean trySample(HttpAdapter<Req, ?> adapter, Req request) {
|
||||
String path = adapter.path(request);
|
||||
public Boolean trySample(HttpRequest request) {
|
||||
String path = request.path();
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,\
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<RpcRequest> 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<RpcRequest> myRpcSampler() {
|
||||
Matcher<RpcRequest> 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[]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<RpcRequest> clientSampler = context.getBean(RpcTracing.class)
|
||||
.clientSampler();
|
||||
|
||||
then(clientSampler).isSameAs(SamplerFunctions.deferDecision());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuresUserProvidedRpcClientSampler() {
|
||||
contextRunner().withUserConfiguration(RpcClientSamplerConfig.class)
|
||||
.run((context) -> {
|
||||
SamplerFunction<RpcRequest> clientSampler = context
|
||||
.getBean(RpcTracing.class).clientSampler();
|
||||
|
||||
then(clientSampler).isSameAs(RpcClientSamplerConfig.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultsToBraveRpcServerSampler() {
|
||||
contextRunner().run((context) -> {
|
||||
SamplerFunction<RpcRequest> serverSampler = context.getBean(RpcTracing.class)
|
||||
.serverSampler();
|
||||
|
||||
then(serverSampler).isSameAs(SamplerFunctions.deferDecision());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuresUserProvidedRpcServerSampler() {
|
||||
contextRunner().withUserConfiguration(RpcServerSamplerConfig.class)
|
||||
.run((context) -> {
|
||||
SamplerFunction<RpcRequest> 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<RpcRequest> INSTANCE = request -> null;
|
||||
|
||||
@Bean(RpcClientSampler.NAME)
|
||||
SamplerFunction<RpcRequest> sleuthRpcClientSampler() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class RpcServerSamplerConfig {
|
||||
|
||||
static final SamplerFunction<RpcRequest> INSTANCE = request -> null;
|
||||
|
||||
@Bean(RpcServerSampler.NAME)
|
||||
SamplerFunction<RpcRequest> sleuthRpcServerSampler() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<HttpRequest> left;
|
||||
|
||||
@Mock
|
||||
HttpSampler left;
|
||||
SamplerFunction<HttpRequest> right;
|
||||
|
||||
@Mock
|
||||
HttpSampler right;
|
||||
HttpRequest request;
|
||||
|
||||
HttpSampler sampler;
|
||||
|
||||
Object request = new Object();
|
||||
SamplerFunction<HttpRequest> 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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<HttpRequest> 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<HttpRequest> myHttpSampler(SkipPatternProvider provider) {
|
||||
Pattern pattern = provider.skipPattern();
|
||||
return new HttpSampler() {
|
||||
|
||||
@Override
|
||||
public <Req> Boolean trySample(HttpAdapter<Req, ?> 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[]
|
||||
|
||||
@@ -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<HttpRequest> clientSampler = context
|
||||
.getBean(HttpTracing.class).clientRequestSampler();
|
||||
|
||||
then(clientSampler).isInstanceOf(SkipPatternHttpClientSampler.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuresUserProvidedDeprecatedClientSampler() {
|
||||
contextRunner().withUserConfiguration(DeprecatedClientSamplerConfig.class)
|
||||
.run((context) -> {
|
||||
SamplerFunction<HttpRequest> clientSampler = context
|
||||
.getBean(HttpTracing.class).clientRequestSampler();
|
||||
|
||||
then(clientSampler).isSameAs(DeprecatedClientSamplerConfig.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configuresUserProvidedHttpClientSampler() {
|
||||
contextRunner().withUserConfiguration(HttpClientSamplerConfig.class)
|
||||
.run((context) -> {
|
||||
SamplerFunction<HttpRequest> 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<HttpRequest> clientSampler = context
|
||||
.getBean(HttpTracing.class).clientRequestSampler();
|
||||
|
||||
then(clientSampler).isSameAs(HttpClientSamplerConfig.INSTANCE);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultsToSkipPatternHttpServerSampler() {
|
||||
contextRunner().run((context) -> {
|
||||
SamplerFunction<HttpRequest> 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<AssertableApplicationContext> thenCompositeHttpServerSamplerOf(
|
||||
SamplerFunction<HttpRequest> instance) {
|
||||
return (context) -> {
|
||||
|
||||
SamplerFunction<HttpRequest> 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<HttpRequest> INSTANCE = request -> null;
|
||||
|
||||
@Bean(HttpClientSampler.NAME)
|
||||
SamplerFunction<HttpRequest> sleuthHttpClientSampler() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class DeprecatedClientSamplerConfig {
|
||||
|
||||
static final HttpSampler INSTANCE = new HttpSampler() {
|
||||
@Override
|
||||
public <Req> Boolean trySample(HttpAdapter<Req, ?> httpAdapter, Req req) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Bean(ClientSampler.NAME)
|
||||
HttpSampler sleuthClientSampler() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class HttpServerSamplerConfig {
|
||||
|
||||
static final SamplerFunction<HttpRequest> INSTANCE = request -> null;
|
||||
|
||||
@Bean(HttpServerSampler.NAME)
|
||||
SamplerFunction<HttpRequest> sleuthHttpServerSampler() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
class DeprecatedServerSamplerConfig {
|
||||
|
||||
static final HttpSampler INSTANCE = new HttpSampler() {
|
||||
@Override
|
||||
public <Req> Boolean trySample(HttpAdapter<Req, ?> httpAdapter, Req req) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Bean(ServerSampler.NAME)
|
||||
HttpSampler sleuthServerSampler() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,7 +104,8 @@ public class TraceWebClientAutoConfigurationTests {
|
||||
.containsOnlyElementsOf(Collections.singletonList(1));
|
||||
}
|
||||
|
||||
private void incrementNumberOfInstances(Map<Class, Integer> numberOfInstances, ClientHttpRequestInterceptor interceptor) {
|
||||
private void incrementNumberOfInstances(Map<Class, Integer> numberOfInstances,
|
||||
ClientHttpRequestInterceptor interceptor) {
|
||||
Integer no = numberOfInstances.get(interceptor.getClass());
|
||||
if (no == null) {
|
||||
numberOfInstances.put(interceptor.getClass(), 1);
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
<dependency>
|
||||
<groupId>io.zipkin.zipkin2</groupId>
|
||||
<artifactId>zipkin</artifactId>
|
||||
<version>2.16.0</version>
|
||||
<version>2.17.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
Reference in New Issue
Block a user