Made the Redis configuration more generic

This commit is contained in:
Marcin Grzejszczak
2021-11-22 15:41:33 +01:00
parent 1ca5e1aea2
commit a08f94cb21
16 changed files with 305 additions and 42 deletions

View File

@@ -68,6 +68,7 @@
|spring.sleuth.reactor.enabled | `true` | When true enables instrumentation for reactor.
|spring.sleuth.reactor.instrumentation-type | |
|spring.sleuth.redis.enabled | `true` | Enable span information propagation when using Redis.
|spring.sleuth.redis.legacy.enabled | `false` | Enable legacy tracing of Redis that works only via Brave.
|spring.sleuth.redis.remote-service-name | `redis` | Service name for the remote Redis endpoint.
|spring.sleuth.rpc.enabled | `true` | Enable tracing of RPC.
|spring.sleuth.rsocket.enabled | `true` | When true enables instrumentation for rsocket.

View File

@@ -459,7 +459,16 @@ To disable Reactor support, set the `spring.sleuth.reactor.enabled` property to
[[sleuth-redis-integration]]
== Redis
This feature is available for Brave tracer implementation.
This feature is available for all tracer implementations.
We're using the `Tracing` abstraction from Lettuce. If Brave is on the classpath we configure `Tracing` to be `BraveTracing`.
To disable Redis support, set the `spring.sleuth.redis.enabled` property to `false`.
[[sleuth-redis-legacy-integration]]
=== Redis With Legacy Brave Only Support
To use the Brave only supported feature you need to set the value of `spring.sleuth.redis.legacy.enabled` to `true`. This is the default mechanism available up till version 3.1.0 of Spring Cloud Sleuth.
We set `tracing` property to Lettuce `ClientResources` instance to enable Brave tracing built in Lettuce.
@@ -476,8 +485,6 @@ Spring Cloud Sleuth will provide a traced version of the `ClientResources` bean.
}
----
To disable Redis support, set the `spring.sleuth.redis.enabled` property to `false`.
[[sleuth-runnablecallable-integration]]
== Runnable and Callable

View File

@@ -32,8 +32,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
import org.springframework.cloud.sleuth.instrument.redis.ClientResourcesBuilderCustomizer;
import org.springframework.cloud.sleuth.instrument.redis.TraceLettuceClientResourcesBuilderCustomizer;
import org.springframework.cloud.sleuth.autoconfig.instrument.redis.TraceRedisAutoConfiguration;
import org.springframework.cloud.sleuth.brave.instrument.redis.ClientResourcesBuilderCustomizer;
import org.springframework.cloud.sleuth.brave.instrument.redis.TraceLettuceClientResourcesBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -47,38 +48,58 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.redis.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracing.class)
@AutoConfigureAfter({ BraveAutoConfiguration.class })
@AutoConfigureBefore({ RedisAutoConfiguration.class })
@AutoConfigureAfter(BraveAutoConfiguration.class)
@AutoConfigureBefore({ RedisAutoConfiguration.class, TraceRedisAutoConfiguration.class })
@EnableConfigurationProperties(TraceRedisProperties.class)
@ConditionalOnClass(BraveTracing.class)
public class BraveRedisAutoConfiguration {
// TODO: The customization auto configuration should come from Spring Boot
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(ClientResources.class)
DefaultClientResources traceLettuceClientResources(ObjectProvider<ClientResourcesBuilderCustomizer> customizer) {
DefaultClientResources.Builder builder = DefaultClientResources.builder();
customizer.stream().forEach(c -> c.customize(builder));
return builder.build();
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty("spring.sleuth.redis.legacy.enabled")
static class LegacyBraveOnlyLettuceConfiguration {
// TODO: The customization auto configuration should come from Spring Boot
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean({ ClientResources.class,
org.springframework.cloud.sleuth.instrument.redis.TraceLettuceClientResourcesBuilderCustomizer.class })
DefaultClientResources traceLettuceClientResources(
ObjectProvider<ClientResourcesBuilderCustomizer> customizer) {
DefaultClientResources.Builder builder = DefaultClientResources.builder();
customizer.stream().forEach(c -> c.customize(builder));
return builder.build();
}
@Bean
@ConditionalOnMissingBean(org.springframework.cloud.sleuth.instrument.redis.TraceLettuceClientResourcesBuilderCustomizer.class)
TraceLettuceClientResourcesBuilderCustomizer traceBraveOnlyLettuceClientResourcesBuilderCustomizer(
Tracing tracing, TraceRedisProperties traceRedisProperties, Sampler sampler) {
eagerlyInitializePotentiallyRefreshScopeSampler(sampler);
return new TraceLettuceClientResourcesBuilderCustomizer(tracing,
traceRedisProperties.getRemoteServiceName());
}
/**
* We need to do the eager method invocation. Since this might be @RefreshScope, a
* proxy is being created. Trying to resolve the proxy from a different thread
* than main can lead to cross thread locking.
* @param sampler potentially refresh scope sampler
*/
private void eagerlyInitializePotentiallyRefreshScopeSampler(Sampler sampler) {
sampler.isSampled(0L);
}
}
@Bean
TraceLettuceClientResourcesBuilderCustomizer traceLettuceClientResourcesBuilderCustomizer(Tracing tracing,
TraceRedisProperties traceRedisProperties, Sampler sampler) {
eagerlyInitializePotentiallyRefreshScopeSampler(sampler);
BraveTracing braveTracing = BraveTracing.builder().tracing(tracing).excludeCommandArgsFromSpanTags()
.serviceName(traceRedisProperties.getRemoteServiceName()).build();
return new TraceLettuceClientResourcesBuilderCustomizer(braveTracing);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.redis.legacy.enabled", havingValue = "false", matchIfMissing = true)
static class NewBraveLettuceConfiguration {
@Bean
BraveTracing lettuceBraveTracing(Tracing tracing, TraceRedisProperties traceRedisProperties) {
return BraveTracing.builder().tracing(tracing).excludeCommandArgsFromSpanTags()
.serviceName(traceRedisProperties.getRemoteServiceName()).build();
}
/**
* We need to do the eager method invocation. Since this might be @RefreshScope, a
* proxy is being created. Trying to resolve the proxy from a different thread than
* main can lead to cross thread locking.
* @param sampler potentially refresh scope sampler
*/
private void eagerlyInitializePotentiallyRefreshScopeSampler(Sampler sampler) {
sampler.isSampled(0L);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright 2013-2021 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.autoconfig.instrument.redis;
import io.lettuce.core.tracing.Tracing;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.cloud.sleuth.autoconfig.brave.instrument.redis.TraceRedisProperties;
import org.springframework.cloud.sleuth.instrument.redis.TraceLettuceClientResourcesBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} enables Redis span information propagation.
*
* @author Marcin Grzejszczak
* @since 3.1.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.redis.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracer.class)
@AutoConfigureBefore({ RedisAutoConfiguration.class })
@EnableConfigurationProperties(TraceRedisProperties.class)
public class TraceRedisAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.sleuth.redis.legacy.enabled", havingValue = "false", matchIfMissing = true)
static class LettuceConfiguration {
@Bean
@ConditionalOnBean(Tracing.class)
TraceLettuceClientResourcesBuilderCustomizer traceLettuceClientResourcesBuilderCustomizer(Tracing tracing) {
return new TraceLettuceClientResourcesBuilderCustomizer(tracing);
}
}
}

View File

@@ -119,6 +119,12 @@
"description": "Enable setting of SocketAddress information on the Mongo span.",
"defaultValue": false
},
{
"name": "spring.sleuth.redis.legacy.enabled",
"type": "java.lang.Boolean",
"description": "Enable legacy tracing of Redis that works only via Brave.",
"defaultValue": false
},
{
"name": "spring.sleuth.rpc.enabled",
"type": "java.lang.Boolean",

View File

@@ -26,6 +26,7 @@ org.springframework.cloud.sleuth.autoconfig.instrument.scheduling.TraceSchedulin
org.springframework.cloud.sleuth.autoconfig.instrument.session.TraceSessionAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.instrument.security.TraceSecurityAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.instrument.reactor.TraceReactorAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.instrument.redis.TraceRedisAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.instrument.messaging.TraceFunctionAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.instrument.messaging.TraceSpringIntegrationAutoConfiguration,\
org.springframework.cloud.sleuth.autoconfig.instrument.messaging.TraceSpringMessagingAutoConfiguration,\

View File

@@ -291,6 +291,12 @@
<artifactId>brave-instrumentation-grpc</artifactId>
<optional>true</optional>
</dependency>
<!-- Instrumentation of Lettuce -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-metrics-micrometer</artifactId>

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.cloud.sleuth.instrument.redis;
package org.springframework.cloud.sleuth.brave.instrument.redis;
import io.lettuce.core.resource.ClientResources;

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2013-2021 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.brave.instrument.redis;
import brave.Tracing;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.tracing.BraveTracing;
/**
* {@link ClientResourcesBuilderCustomizer} for wrapping Lettuce components in a tracing
* representation.
*
* @author Marcin Grzejszczak
* @author Thomas Vitale
* @since 3.0.4
*/
public class TraceLettuceClientResourcesBuilderCustomizer implements ClientResourcesBuilderCustomizer {
private final BraveTracing tracing;
public TraceLettuceClientResourcesBuilderCustomizer(Tracing tracing, String serviceName) {
this.tracing = BraveTracing.builder().tracing(tracing).excludeCommandArgsFromSpanTags().serviceName(serviceName)
.build();
}
@Override
public void customize(ClientResources.Builder builder) {
builder.tracing(this.tracing);
}
}

View File

@@ -190,13 +190,11 @@
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<!-- Instrumentation of Lettuce -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<!-- For Instrumentation of Quartz -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>

View File

@@ -19,13 +19,15 @@ package org.springframework.cloud.sleuth.instrument.redis;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.tracing.Tracing;
import org.springframework.boot.autoconfigure.data.redis.ClientResourcesBuilderCustomizer;
/**
* {@link ClientResourcesBuilderCustomizer} for wrapping Lettuce components in a tracing
* representation.
*
* @author Marcin Grzejszczak
* @author Thomas Vitale
* @since 3.0.4
* @since 3.1.0
*/
public class TraceLettuceClientResourcesBuilderCustomizer implements ClientResourcesBuilderCustomizer {

View File

@@ -52,12 +52,12 @@
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<groupId>${project.groupId}</groupId>
<artifactId>spring-cloud-sleuth-tests-common</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2013-2021 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.brave.instrument.redis;
import brave.sampler.Sampler;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.sleuth.brave.BraveTestSpanHandler;
import org.springframework.cloud.sleuth.test.TestSpanHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest
@ContextConfiguration(classes = BraveLettuceIntegrationTests.Config.class)
public class BraveLettuceIntegrationTests
extends org.springframework.cloud.sleuth.instrument.redis.LettuceIntegrationTests {
@Configuration(proxyBeanMethods = false)
static class Config {
@Bean
TestSpanHandler testSpanHandlerSupplier(brave.test.TestSpanHandler testSpanHandler) {
return new BraveTestSpanHandler(testSpanHandler);
}
@Bean
Sampler alwaysSampler() {
return Sampler.ALWAYS_SAMPLE;
}
@Bean
brave.test.TestSpanHandler braveTestSpanHandler() {
return new brave.test.TestSpanHandler();
}
}
}

View File

@@ -30,9 +30,9 @@ import static org.assertj.core.api.BDDAssertions.then;
* @author Chao Chang
*/
@SpringBootTest(classes = BraveRedisAutoConfigurationTests.Config.class,
webEnvironment = SpringBootTest.WebEnvironment.NONE,
properties = { "spring.sleuth.redis.enabled=true", "spring.sleuth.redis.remote-service-name=redis-foo" })
public class BraveRedisAutoConfigurationTests {
webEnvironment = SpringBootTest.WebEnvironment.NONE, properties = { "spring.sleuth.redis.enabled=true",
"spring.sleuth.redis.legacy.enabled=true", "spring.sleuth.redis.remote-service-name=redis-foo" })
class BraveRedisAutoConfigurationTests {
@Autowired
ClientResources clientResources;
@@ -41,7 +41,7 @@ public class BraveRedisAutoConfigurationTests {
TraceLettuceClientResourcesBuilderCustomizer customizer;
@Test
public void tracing_should_be_set() {
void tracing_should_be_set() {
then(this.clientResources.tracing().isEnabled()).isTrue();
then(this.customizer).isNotNull();
}

View File

@@ -189,6 +189,11 @@
<artifactId>r2dbc-proxy</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2013-2021 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.redis;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.tracing.BraveTracing;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource;
import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Chao Chang
*/
@ContextConfiguration(classes = LettuceIntegrationTests.TestConfig.class)
@TestPropertySource(properties = "spring.sleuth.redis.remote-service-name=redis-foo")
public abstract class LettuceIntegrationTests {
@Autowired(required = false)
ClientResources clientResources;
@Autowired
TraceLettuceClientResourcesBuilderCustomizer customizer;
@Autowired
BraveTracing braveTracing;
@Test
void tracing_should_be_set() {
then(this.clientResources).isNull();
then(this.customizer).isNotNull();
then(this.braveTracing.isEnabled()).isTrue();
}
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
protected static class TestConfig {
}
}