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:
Adrian Cole
2019-10-03 18:21:56 +08:00
committed by Marcin Grzejszczak
parent dc82c5cafc
commit be5fa04118
26 changed files with 888 additions and 101 deletions

View File

@@ -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>

View File

@@ -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>
----

View File

@@ -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>

View File

@@ -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

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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();
}
}

View File

@@ -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 {
/**

View File

@@ -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";
}

View File

@@ -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";
}

View File

@@ -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 {
/**

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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,\

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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[]

View 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>

View File

@@ -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[]
}
}