Skip to content

Commit 507e918

Browse files
Added TX support
fixes gh-1941
1 parent 4fef057 commit 507e918

File tree

22 files changed

+939
-43
lines changed

22 files changed

+939
-43
lines changed

docs/src/main/asciidoc/integrations.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,3 +599,11 @@ This feature is available for all tracer implementations.
599599

600600
If you have Spring Batch running on the classpath, we wrap the `StepBuilderFactory` and the `JobBuilderFactory` to propagate the tracing context.
601601
In order to disable this instrumentation set `spring.sleuth.batch.enabled` to `false`.
602+
603+
[[sleuth-tx-integration]]
604+
== Spring Tx
605+
606+
This feature is available for all tracer implementations.
607+
608+
If you have Spring Tx on the classpath we will instrument the `PlatformTransactionManager` and the `ReactiveTransactionManager` to create a span whenever a new transaction is created.
609+
In order to disable this instrumentation set `spring.sleuth.tx.enabled` to `false`.

spring-cloud-sleuth-autoconfigure/src/main/java/org/springframework/cloud/sleuth/autoconfig/instrument/task/TraceTaskAutoConfiguration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
import org.springframework.context.annotation.Configuration;
3131

3232
/**
33-
* Registers beans related to Spring Cloud Task scheduling.
33+
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
34+
* Auto-configuration} that registers instrumentation for Spring Cloud Task.
3435
*
3536
* @author Marcin Grzejszczak
3637
* @since 3.1.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2013-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.sleuth.autoconfig.instrument.tx;
18+
19+
import org.springframework.beans.BeansException;
20+
import org.springframework.beans.factory.BeanFactory;
21+
import org.springframework.beans.factory.config.BeanPostProcessor;
22+
import org.springframework.cloud.sleuth.instrument.tx.TracePlatformTransactionManager;
23+
import org.springframework.transaction.PlatformTransactionManager;
24+
25+
/**
26+
* Post processor that wraps a {@link PlatformTransactionManager}.
27+
*
28+
* @author Marcin Grzejszczak
29+
* @since 3.1.0
30+
*/
31+
public class TracePlatformTransactionManagerBeanPostProcessor implements BeanPostProcessor {
32+
33+
private final BeanFactory beanFactory;
34+
35+
public TracePlatformTransactionManagerBeanPostProcessor(BeanFactory beanFactory) {
36+
this.beanFactory = beanFactory;
37+
}
38+
39+
@Override
40+
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
41+
if (bean instanceof PlatformTransactionManager && !(bean instanceof TracePlatformTransactionManager)) {
42+
return new TracePlatformTransactionManager((PlatformTransactionManager) bean, this.beanFactory);
43+
}
44+
return bean;
45+
}
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2013-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.sleuth.autoconfig.instrument.tx;
18+
19+
import org.springframework.beans.BeansException;
20+
import org.springframework.beans.factory.BeanFactory;
21+
import org.springframework.beans.factory.config.BeanPostProcessor;
22+
import org.springframework.cloud.sleuth.instrument.tx.TraceReactiveTransactionManager;
23+
import org.springframework.transaction.ReactiveTransactionManager;
24+
25+
/**
26+
* Post processor that wraps a {@link ReactiveTransactionManager}.
27+
*
28+
* @author Marcin Grzejszczak
29+
* @since 3.1.0
30+
*/
31+
public class TraceReactiveTransactionManagerBeanPostProcessor implements BeanPostProcessor {
32+
33+
private final BeanFactory beanFactory;
34+
35+
public TraceReactiveTransactionManagerBeanPostProcessor(BeanFactory beanFactory) {
36+
this.beanFactory = beanFactory;
37+
}
38+
39+
@Override
40+
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
41+
if (bean instanceof ReactiveTransactionManager && !(bean instanceof TraceReactiveTransactionManager)) {
42+
return new TraceReactiveTransactionManager((ReactiveTransactionManager) bean, this.beanFactory);
43+
}
44+
return bean;
45+
}
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2013-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.sleuth.autoconfig.instrument.tx;
18+
19+
import org.springframework.beans.factory.BeanFactory;
20+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
21+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
22+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
24+
import org.springframework.cloud.sleuth.Tracer;
25+
import org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration;
26+
import org.springframework.context.annotation.Bean;
27+
import org.springframework.context.annotation.Configuration;
28+
29+
/**
30+
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
31+
* Auto-configuration} that registers instrumentation for Spring TX.
32+
*
33+
* @author Marcin Grzejszczak
34+
* @since 3.1.0
35+
*/
36+
@Configuration(proxyBeanMethods = false)
37+
@ConditionalOnProperty(value = "spring.sleuth.tx.enabled", matchIfMissing = true)
38+
@ConditionalOnBean(Tracer.class)
39+
@AutoConfigureAfter(BraveAutoConfiguration.class)
40+
public class TraceTxAutoConfiguration {
41+
42+
@Bean
43+
@ConditionalOnClass(name = "org.springframework.transaction.PlatformTransactionManager")
44+
static TracePlatformTransactionManagerBeanPostProcessor tracePlatformTransactionManagerBeanPostProcessor(
45+
BeanFactory beanFactory) {
46+
return new TracePlatformTransactionManagerBeanPostProcessor(beanFactory);
47+
}
48+
49+
@Bean
50+
@ConditionalOnClass(
51+
name = { "org.springframework.transaction.ReactiveTransactionManager", "reactor.core.publisher.Mono" })
52+
static TraceReactiveTransactionManagerBeanPostProcessor traceReactiveTransactionManagerBeanPostProcessor(
53+
BeanFactory beanFactory) {
54+
return new TraceReactiveTransactionManagerBeanPostProcessor(beanFactory);
55+
}
56+
57+
}

spring-cloud-sleuth-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@
155155
"description": "Enable Spring Cloud Config Server instrumentation.",
156156
"defaultValue": true
157157
},
158+
{
159+
"name": "spring.sleuth.tx.enabled",
160+
"type": "java.lang.Boolean",
161+
"description": "Enable Spring TX instrumentation.",
162+
"defaultValue": true
163+
},
158164
{
159165
"name": "spring.sleuth.batch.enabled",
160166
"type": "java.lang.Boolean",

spring-cloud-sleuth-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ org.springframework.cloud.sleuth.autoconfig.instrument.messaging.TraceSpringInte
2121
org.springframework.cloud.sleuth.autoconfig.instrument.messaging.TraceSpringMessagingAutoConfiguration,\
2222
org.springframework.cloud.sleuth.autoconfig.instrument.messaging.TraceWebSocketAutoConfiguration,\
2323
org.springframework.cloud.sleuth.autoconfig.instrument.rsocket.TraceRSocketAutoConfiguration, \
24+
org.springframework.cloud.sleuth.autoconfig.instrument.tx.TraceTxAutoConfiguration, \
2425
org.springframework.cloud.sleuth.autoconfig.brave.BraveAutoConfiguration,\
2526
org.springframework.cloud.sleuth.autoconfig.brave.instrument.web.client.BraveWebClientAutoConfiguration,\
2627
org.springframework.cloud.sleuth.autoconfig.brave.instrument.rpc.BraveRpcAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2013-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.sleuth.autoconfig.instrument.tx;
18+
19+
import org.assertj.core.api.Assertions;
20+
import org.junit.jupiter.api.Test;
21+
import reactor.core.publisher.Mono;
22+
23+
import org.springframework.boot.autoconfigure.AutoConfigurations;
24+
import org.springframework.boot.test.context.FilteredClassLoader;
25+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
26+
import org.springframework.cloud.sleuth.autoconfig.TraceNoOpAutoConfiguration;
27+
import org.springframework.transaction.PlatformTransactionManager;
28+
import org.springframework.transaction.ReactiveTransactionManager;
29+
30+
class TraceTxAutoConfigurationTests {
31+
32+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
33+
.withPropertyValues("spring.sleuth.noop.enabled=true")
34+
.withConfiguration(AutoConfigurations.of(TraceNoOpAutoConfiguration.class, TraceTxAutoConfiguration.class));
35+
36+
@Test
37+
void should_register_bean_post_processors() {
38+
this.contextRunner.run(context -> Assertions.assertThat(context)
39+
.hasSingleBean(TracePlatformTransactionManagerBeanPostProcessor.class)
40+
.hasSingleBean(TraceReactiveTransactionManagerBeanPostProcessor.class));
41+
}
42+
43+
@Test
44+
void should_not_register_bean_post_processor_when_tx_not_on_classpath() {
45+
this.contextRunner.withClassLoader(new FilteredClassLoader(PlatformTransactionManager.class))
46+
.run(context -> Assertions.assertThat(context)
47+
.doesNotHaveBean(TracePlatformTransactionManagerBeanPostProcessor.class));
48+
}
49+
50+
@Test
51+
void should_not_register_reactive_bean_post_processor_when_reactive_tx_not_on_classpath() {
52+
this.contextRunner.withClassLoader(new FilteredClassLoader(ReactiveTransactionManager.class))
53+
.run(context -> Assertions.assertThat(context)
54+
.doesNotHaveBean(TraceReactiveTransactionManagerBeanPostProcessor.class));
55+
}
56+
57+
@Test
58+
void should_not_register_reactive_bean_post_processor_when_reactor_not_on_classpath() {
59+
this.contextRunner.withClassLoader(new FilteredClassLoader(Mono.class)).run(context -> Assertions
60+
.assertThat(context).doesNotHaveBean(TraceReactiveTransactionManagerBeanPostProcessor.class));
61+
}
62+
63+
}

spring-cloud-sleuth-instrumentation/src/main/java/org/springframework/cloud/sleuth/instrument/deployer/TraceAppDeployer.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,14 @@ public AppStatus status(String id) {
129129
@Override
130130
public Mono<AppStatus> statusReactive(String id) {
131131
return ReactorSleuth.tracedMono(tracer(), currentTraceContext(), "status",
132-
() -> this.delegate.statusReactive(id), span -> span.tag("deployer.app.id", id));
132+
() -> this.delegate.statusReactive(id), (o, span) -> span.tag("deployer.app.id", id));
133133
}
134134

135135
@Override
136136
public Flux<AppStatus> statusesReactive(String... ids) {
137137
return ReactorSleuth.tracedFlux(tracer(), currentTraceContext(), "statuses",
138-
() -> this.delegate.statusesReactive(ids), span -> span.tag("deployer.app.ids", Arrays.toString(ids)));
138+
() -> this.delegate.statusesReactive(ids),
139+
(o, span) -> span.tag("deployer.app.ids", Arrays.toString(ids)));
139140
}
140141

141142
@Override

0 commit comments

Comments
 (0)