Updates to latest Sampling infrastructure (#1456)
* Updates to latest Sampling infrastructure
Brave recently switched to an interface model for higher level sampling
like HTTP. So, `HttpSampler` -> `SamplingFunction<HttpRequest>`. Don't
worry because `HttpSampler` was retrofitted as a `SamplingFunction`.
This change moves to the higher interface, avoiding deprecated methods
and such. More interestingly, this weaves in support for `RpcTracing`,
which *finally* introduces RPC sampling the same way. Specifically, this
adds `SamplingFunction<RpcRequest>` under the same conventions as HTTP.
Most immediately, this can be used here in gRPC and Dubbo, as
autoconfiguration exists. It also works with any autoconfiguration that
isn't here, such as Armeria.
Ex. Here's a sampler that traces 100 "GetUserToken" requests per second. This
doesn't start new traces for requests to the health check service. Other
requests will use a global rate provided by the tracing component.
```java
import static brave.rpc.RpcRequestMatchers.methodEquals;
import static brave.rpc.RpcRequestMatchers.serviceEquals;
import static brave.sampler.Matchers.and;
--snip--
@Bean(name = ServerSampler.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();
}
```
This commit is contained in:
committed by
Marcin Grzejszczak
parent
dc82c5cafc
commit
be5fa04118
@@ -34,7 +34,7 @@
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<spring-boot.version>2.2.0.BUILD-SNAPSHOT</spring-boot.version>
|
||||
<brave.version>5.7.0</brave.version>
|
||||
<brave.version>5.8.0</brave.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@@ -838,21 +838,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]
|
||||
----
|
||||
@@ -874,6 +876,34 @@ In the following example, we register the `TracingFilter` bean, add the `ZIPKIN-
|
||||
include::{project-root}/tests/spring-cloud-sleuth-instrumentation-mvc-tests/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::{project-root}/tests/spring-cloud-sleuth-instrumentation-rpc-tests/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.
|
||||
@@ -1113,13 +1143,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>
|
||||
----
|
||||
|
||||
|
||||
@@ -208,6 +208,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,74 @@
|
||||
/*
|
||||
* 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;
|
||||
@@ -64,22 +65,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;
|
||||
}
|
||||
@@ -123,9 +130,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -135,25 +147,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;
|
||||
}
|
||||
@@ -165,7 +178,7 @@ class CompositeHttpSampler extends HttpSampler {
|
||||
return leftDecision;
|
||||
}
|
||||
// Neither are null and at least one is true
|
||||
return leftDecision && rightDecision;
|
||||
return rightDecision;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -175,17 +188,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;
|
||||
}
|
||||
|
||||
@@ -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.SleuthKafkaStreamsConfiguration,\
|
||||
org.springframework.cloud.sleuth.instrument.messaging.TraceMessagingAutoConfiguration,\
|
||||
|
||||
@@ -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;
|
||||
@@ -37,7 +39,8 @@ public class TraceAutoConfigurationCustomizersTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(TraceAutoConfiguration.class,
|
||||
TraceWebAutoConfiguration.class, TraceHttpAutoConfiguration.class))
|
||||
TraceWebAutoConfiguration.class, TraceHttpAutoConfiguration.class,
|
||||
TraceRpcAutoConfiguration.class))
|
||||
.withUserConfiguration(Customizers.class);
|
||||
|
||||
@Test
|
||||
@@ -69,6 +72,7 @@ public class TraceAutoConfigurationCustomizersTests {
|
||||
then(bean.contextCustomizerApplied).isTrue();
|
||||
then(bean.extraFieldCustomizerApplied).isTrue();
|
||||
then(bean.httpCustomizerApplied).isTrue();
|
||||
then(bean.rpcCustomizerApplied).isTrue();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -82,6 +86,8 @@ public class TraceAutoConfigurationCustomizersTests {
|
||||
|
||||
boolean httpCustomizerApplied;
|
||||
|
||||
boolean rpcCustomizerApplied;
|
||||
|
||||
@Bean
|
||||
TracingCustomizer sleuthTracingCustomizer() {
|
||||
return builder -> tracingCustomizerApplied = true;
|
||||
@@ -102,6 +108,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,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,7 +31,7 @@
|
||||
<name>spring-cloud-sleuth-dependencies</name>
|
||||
<description>Spring Cloud Sleuth Dependencies</description>
|
||||
<properties>
|
||||
<brave.version>5.7.0</brave.version>
|
||||
<brave.version>5.8.0</brave.version>
|
||||
<brave.opentracing.version>0.34.1</brave.opentracing.version>
|
||||
<grpc.spring.boot.version>3.4.1</grpc.spring.boot.version>
|
||||
</properties>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
<module>spring-cloud-sleuth-instrumentation-lettuce-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-rxjava-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-scheduling-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-rpc-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-mvc-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-webflux-tests</module>
|
||||
<module>spring-cloud-sleuth-instrumentation-feign-tests</module>
|
||||
|
||||
@@ -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;
|
||||
@@ -74,8 +74,8 @@ public class TraceFilterWebIntegrationTests {
|
||||
ArrayListSpanReporter accumulator;
|
||||
|
||||
@Autowired
|
||||
@ServerSampler
|
||||
HttpSampler sampler;
|
||||
@HttpServerSampler
|
||||
SamplerFunction<HttpRequest> sampler;
|
||||
|
||||
@Autowired
|
||||
Environment environment;
|
||||
@@ -163,20 +163,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[]
|
||||
|
||||
74
tests/spring-cloud-sleuth-instrumentation-rpc-tests/pom.xml
Normal file
74
tests/spring-cloud-sleuth-instrumentation-rpc-tests/pom.xml
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
~
|
||||
~
|
||||
-->
|
||||
|
||||
<project xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-sleuth-instrumentation-rpc-tests</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Sleuth RPC Instrumentation Tests</name>
|
||||
<description>Spring Cloud Sleuth RPC Instrumentation Tests</description>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-sleuth-tests</artifactId>
|
||||
<version>2.2.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<sonar.skip>true</sonar.skip>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<!--skip deploy -->
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-sleuth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.awaitility</groupId>
|
||||
<artifactId>awaitility</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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[]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user