Skip to content

Commit 3c28622

Browse files
committed
Add support for reactor-tools debug agent
The `reactor-tools` dependency now brings a new Reactor Debug Agent which instruments loaded classes for better Reactor stacktraces. This commit removes the `spring.reactor.stacktrace-mode.enabled` configuration property since the related Reactor Hook is about to be removed. As a replacement, we're introducing `spring.reactor.debug-agent.enabled` which tells whether the Reactor Debug Agent should be loaded, given that the `reactor-tools` dependency is available. This option is enabled by default, since adding the dependency on classpath is a strong signal already. Fixes gh-17128
1 parent b1a3849 commit 3c28622

File tree

11 files changed

+145
-187
lines changed

11 files changed

+145
-187
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/core/ReactorCoreAutoConfiguration.java

Lines changed: 0 additions & 48 deletions
This file was deleted.

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/reactor/core/ReactorCoreProperties.java

Lines changed: 0 additions & 65 deletions
This file was deleted.

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,14 @@
775775
"name": "spring.rabbitmq.listener.type",
776776
"defaultValue": "simple"
777777
},
778+
{
779+
"name": "spring.reactor.stacktrace-mode.enabled",
780+
"description": "Whether Reactor should collect stacktrace information at runtime.",
781+
"defaultValue": false,
782+
"deprecation": {
783+
"replacement": "spring.reactor.debug-agent.enabled"
784+
}
785+
},
778786
{
779787
"name": "spring.security.filter.dispatcher-types",
780788
"defaultValue": [

spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\
100100
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
101101
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
102102
org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\
103-
org.springframework.boot.autoconfigure.reactor.core.ReactorCoreAutoConfiguration,\
104103
org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\
105104
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\
106105
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/reactor/core/ReactorCoreAutoConfigurationTests.java

Lines changed: 0 additions & 69 deletions
This file was deleted.

spring-boot-project/spring-boot/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@
7676
<artifactId>reactor-netty</artifactId>
7777
<optional>true</optional>
7878
</dependency>
79+
<dependency>
80+
<groupId>io.projectreactor</groupId>
81+
<artifactId>reactor-tools</artifactId>
82+
<optional>true</optional>
83+
</dependency>
7984
<dependency>
8085
<groupId>io.netty</groupId>
8186
<artifactId>netty-tcnative-boringssl-static</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright 2012-2019 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.boot.reactor;
18+
19+
import reactor.tools.agent.ReactorDebugAgent;
20+
21+
import org.springframework.boot.SpringApplication;
22+
import org.springframework.boot.env.EnvironmentPostProcessor;
23+
import org.springframework.core.Ordered;
24+
import org.springframework.core.env.ConfigurableEnvironment;
25+
import org.springframework.util.ClassUtils;
26+
27+
/**
28+
* {@link EnvironmentPostProcessor} to enable the Reactor Debug Agent if available.
29+
* <p>
30+
* The debug agent is enabled by default, unless the
31+
* {@code "spring.reactor.debug-agent.enabled"} configuration property is set to false. We
32+
* are using here an {@link EnvironmentPostProcessor} instead of an auto-configuration
33+
* class to enable the agent as soon as possible during the startup process.
34+
*
35+
* @author Brian Clozel
36+
* @since 2.2.0
37+
*/
38+
public class DebugAgentEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
39+
40+
private static final String REACTOR_DEBUGAGENT_CLASS = "reactor.tools.agent.ReactorDebugAgent";
41+
42+
private static final String DEBUGAGENT_ENABLED_CONFIG_KEY = "spring.reactor.debug-agent.enabled";
43+
44+
@Override
45+
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
46+
if (ClassUtils.isPresent(REACTOR_DEBUGAGENT_CLASS, null)) {
47+
Boolean agentEnabled = environment.getProperty(DEBUGAGENT_ENABLED_CONFIG_KEY, Boolean.class);
48+
if (agentEnabled != Boolean.FALSE) {
49+
ReactorDebugAgent.init();
50+
}
51+
}
52+
}
53+
54+
@Override
55+
public int getOrder() {
56+
return Ordered.LOWEST_PRECEDENCE;
57+
}
58+
59+
}

spring-boot-project/spring-boot/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,13 @@
719719
"sourceType": "org.springframework.boot.context.config.ConfigFileApplicationListener",
720720
"description": "Unconditionally activate the specified comma-separated list of profiles (or list of profiles if using YAML)."
721721
},
722+
{
723+
"name": "spring.reactor.debug-agent.enabled",
724+
"type": "java.lang.Boolean",
725+
"sourceType": "org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor",
726+
"description": "Whether the Reactor Debug Agent should be enabled when reactor-tools is present.",
727+
"defaultValue": true
728+
},
722729
{
723730
"name": "trace",
724731
"type": "java.lang.Boolean",

spring-boot-project/spring-boot/src/main/resources/META-INF/spring.factories

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
3434
org.springframework.boot.env.EnvironmentPostProcessor=\
3535
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
3636
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
37-
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor
37+
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
38+
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor
3839

3940
# Failure Analyzers
4041
org.springframework.boot.diagnostics.FailureAnalyzer=\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2012-2019 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.boot.reactor;
18+
19+
import org.junit.jupiter.api.Test;
20+
import reactor.core.Scannable;
21+
import reactor.core.publisher.Flux;
22+
23+
import org.springframework.mock.env.MockEnvironment;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Tests for {@link DebugAgentEnvironmentPostProcessor}.
29+
*
30+
* @author Brian Clozel
31+
*/
32+
class DebugAgentEnvironmentPostProcessorTests {
33+
34+
static {
35+
MockEnvironment environment = new MockEnvironment();
36+
DebugAgentEnvironmentPostProcessor postProcessor = new DebugAgentEnvironmentPostProcessor();
37+
postProcessor.postProcessEnvironment(environment, null);
38+
}
39+
40+
@Test
41+
void enablesReactorDebugAgent() {
42+
InstrumentedFluxProvider fluxProvider = new InstrumentedFluxProvider();
43+
Flux<Integer> flux = fluxProvider.newFluxJust();
44+
assertThat(Scannable.from(flux).stepName())
45+
.startsWith("Flux.just ⇢ at org.springframework.boot.reactor.InstrumentedFluxProvider.newFluxJust");
46+
}
47+
48+
}
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,7 +14,20 @@
1414
* limitations under the License.
1515
*/
1616

17+
package org.springframework.boot.reactor;
18+
19+
import reactor.core.publisher.Flux;
20+
1721
/**
18-
* Auto-configuration for Reactor Core.
22+
* Utility class that should be instrumented by the reactor debug agent.
23+
*
24+
* @author Brian Clozel
25+
* @see DebugAgentEnvironmentPostProcessorTests
1926
*/
20-
package org.springframework.boot.autoconfigure.reactor.core;
27+
class InstrumentedFluxProvider {
28+
29+
Flux<Integer> newFluxJust() {
30+
return Flux.just(1);
31+
}
32+
33+
}

0 commit comments

Comments
 (0)