Skip to content

Commit b25408e

Browse files
csabakosgeoand
authored andcommitted
WebFlux tracing should trace all URLs by default. (#96)
* WebFlux tracing should trace all URLs by default. Improve documentation of urlPatterns field
1 parent f5b172a commit b25408e

File tree

5 files changed

+268
-3
lines changed

5 files changed

+268
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ class TracingConfiguration {
9999
tracer,
100100
Integer.MIN_VALUE, // Order
101101
Pattern.compile(""), // Skip pattern
102-
Collections.singletonList("/*"), // URL patterns
102+
Collections.emptyList(), // URL patterns, empty list means all
103103
Arrays.asList(new WebFluxSpanDecorator.StandardTags(), new WebFluxSpanDecorator.WebFluxTags())
104104
);
105105
}

opentracing-spring-web-starter/src/main/java/io/opentracing/contrib/spring/web/starter/WebTracingProperties.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,18 @@ public class WebTracingProperties {
3333
private boolean enabled = true;
3434
private Pattern skipPattern = DEFAULT_SKIP_PATTERN;
3535
private int order = Integer.MIN_VALUE;
36-
private List<String> urlPatterns = new ArrayList<>(Collections.singletonList("/*"));
36+
37+
/**
38+
* List of URL patterns that should be traced.
39+
*
40+
* For servlet web stack, the URL pattern syntax is defined in the Servlet spec, under "Specification of Mappings".
41+
* For reactive (WebFlux), see the documentation of {@link org.springframework.web.util.pattern.PathPattern} for
42+
* the syntax.
43+
*
44+
* By default, the list is empty, which means that all requests will be traced (unless {@link #skipPattern} says
45+
* otherwise.)
46+
*/
47+
private List<String> urlPatterns = Collections.emptyList();
3748

3849
public boolean isEnabled() {
3950
return enabled;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* Copyright 2016-2019 The OpenTracing Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package io.opentracing.contrib.spring.web.starter;
15+
16+
import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator;
17+
import io.opentracing.mock.MockTracer;
18+
import org.awaitility.Awaitility;
19+
import org.hamcrest.core.IsEqual;
20+
import org.junit.After;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.mockito.Mockito;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.beans.factory.annotation.Qualifier;
26+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.test.mock.mockito.MockBean;
29+
import org.springframework.boot.test.web.client.TestRestTemplate;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
33+
import org.springframework.web.bind.annotation.RequestMapping;
34+
import org.springframework.web.bind.annotation.RestController;
35+
36+
import java.util.concurrent.Callable;
37+
import java.util.concurrent.CountDownLatch;
38+
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
41+
/**
42+
* @author Pavol Loffay
43+
*
44+
* Test that the default settings in {@link WebTracingProperties} work as expected.
45+
*/
46+
@SpringBootTest(
47+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
48+
classes = {ServerTracingAutoConfigurationDefaultsTest.SpringConfiguration.class},
49+
properties = "opentracing.spring.web.client.enabled=false")
50+
@RunWith(SpringJUnit4ClassRunner.class)
51+
public class ServerTracingAutoConfigurationDefaultsTest extends AutoConfigurationBaseTest {
52+
53+
private static CountDownLatch infoCountDownLatch = new CountDownLatch(1);
54+
55+
@RestController
56+
@Configuration
57+
@EnableAutoConfiguration
58+
public static class SpringConfiguration {
59+
@Bean
60+
public MockTracer tracer() {
61+
return new MockTracer();
62+
}
63+
64+
@RequestMapping("/hello")
65+
public void hello() {
66+
}
67+
68+
@RequestMapping("/hello/nested")
69+
public void nestedHello() {
70+
}
71+
72+
@RequestMapping("/info")
73+
public void info() {
74+
infoCountDownLatch.countDown();
75+
}
76+
}
77+
78+
@Autowired
79+
private TestRestTemplate testRestTemplate;
80+
81+
@Autowired
82+
private MockTracer mockTracer;
83+
84+
@MockBean
85+
@Qualifier("mockDecorator1")
86+
private ServletFilterSpanDecorator mockDecorator1;
87+
@MockBean
88+
@Qualifier("mockDecorator2")
89+
private ServletFilterSpanDecorator mockDecorator2;
90+
91+
// Test that top level paths are traced by default
92+
@Test
93+
public void testRequestIsTraced() {
94+
testRestTemplate.getForEntity("/hello", String.class);
95+
Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1));
96+
assertThat(mockTracer.finishedSpans()).hasSize(1);
97+
}
98+
99+
// Test that lower level paths are traced by default as well
100+
@Test
101+
public void testNestedRequestIsTraced() {
102+
testRestTemplate.getForEntity("/hello/nested", String.class);
103+
Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1));
104+
assertThat(mockTracer.finishedSpans()).hasSize(1);
105+
}
106+
107+
// Test that /info is excluded due to the default skipPattern
108+
@Test
109+
public void testExcluded() throws InterruptedException {
110+
testRestTemplate.getForEntity("/info", String.class);
111+
infoCountDownLatch.await();
112+
113+
assertThat(mockTracer.finishedSpans()).hasSize(0);
114+
assertThat(Mockito.mockingDetails(mockDecorator1).getInvocations()).hasSize(0);
115+
assertThat(Mockito.mockingDetails(mockDecorator2).getInvocations()).hasSize(0);
116+
}
117+
118+
public Callable<Integer> reportedSpansSize() {
119+
return () -> mockTracer.finishedSpans().size();
120+
}
121+
122+
@After()
123+
public void reset() {
124+
mockTracer.reset();
125+
infoCountDownLatch = new CountDownLatch(1);
126+
}
127+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* Copyright 2016-2019 The OpenTracing Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5+
* in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License
10+
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11+
* or implied. See the License for the specific language governing permissions and limitations under
12+
* the License.
13+
*/
14+
package io.opentracing.contrib.spring.web.starter;
15+
16+
import io.opentracing.contrib.spring.web.webfilter.WebFluxSpanDecorator;
17+
import io.opentracing.mock.MockTracer;
18+
import org.awaitility.Awaitility;
19+
import org.hamcrest.core.IsEqual;
20+
import org.junit.After;
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
import org.mockito.Mockito;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.beans.factory.annotation.Qualifier;
26+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
27+
import org.springframework.boot.test.context.SpringBootTest;
28+
import org.springframework.boot.test.mock.mockito.MockBean;
29+
import org.springframework.boot.test.web.client.TestRestTemplate;
30+
import org.springframework.context.annotation.Bean;
31+
import org.springframework.context.annotation.Configuration;
32+
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
33+
import org.springframework.web.bind.annotation.RequestMapping;
34+
import org.springframework.web.bind.annotation.RestController;
35+
36+
import java.util.concurrent.Callable;
37+
import java.util.concurrent.CountDownLatch;
38+
39+
import static org.assertj.core.api.Assertions.assertThat;
40+
41+
/**
42+
* @author Csaba Kos
43+
*
44+
* Test that the default settings in {@link WebTracingProperties} work as expected.
45+
*/
46+
@SpringBootTest(
47+
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
48+
classes = {WebFluxTracingAutoConfigurationDefaultsTest.SpringConfiguration.class},
49+
properties = {"opentracing.spring.web.client.enabled=false", "spring.main.web-application-type=reactive"})
50+
@RunWith(SpringJUnit4ClassRunner.class)
51+
public class WebFluxTracingAutoConfigurationDefaultsTest extends AutoConfigurationBaseTest {
52+
53+
private static CountDownLatch infoCountDownLatch = new CountDownLatch(1);
54+
55+
@RestController
56+
@Configuration
57+
@EnableAutoConfiguration
58+
public static class SpringConfiguration {
59+
@Bean
60+
public MockTracer tracer() {
61+
return new MockTracer();
62+
}
63+
64+
@RequestMapping("/hello")
65+
public void hello() {
66+
}
67+
68+
@RequestMapping("/hello/nested")
69+
public void nestedHello() {
70+
}
71+
72+
@RequestMapping("/info")
73+
public void info() {
74+
infoCountDownLatch.countDown();
75+
}
76+
}
77+
78+
@Autowired
79+
private TestRestTemplate testRestTemplate;
80+
81+
@Autowired
82+
private MockTracer mockTracer;
83+
84+
@MockBean
85+
@Qualifier("mockDecorator1")
86+
private WebFluxSpanDecorator mockDecorator1;
87+
@MockBean
88+
@Qualifier("mockDecorator2")
89+
private WebFluxSpanDecorator mockDecorator2;
90+
91+
// Test that top level paths are traced by default
92+
@Test
93+
public void testRequestIsTraced() {
94+
testRestTemplate.getForEntity("/hello", String.class);
95+
Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1));
96+
assertThat(mockTracer.finishedSpans()).hasSize(1);
97+
}
98+
99+
// Test that lower level paths are traced by default as well
100+
@Test
101+
public void testNestedRequestIsTraced() {
102+
testRestTemplate.getForEntity("/hello/nested", String.class);
103+
Awaitility.await().until(reportedSpansSize(), IsEqual.equalTo(1));
104+
assertThat(mockTracer.finishedSpans()).hasSize(1);
105+
}
106+
107+
// Test that /info is excluded due to the default skipPattern
108+
@Test
109+
public void testExcluded() throws InterruptedException {
110+
testRestTemplate.getForEntity("/info", String.class);
111+
infoCountDownLatch.await();
112+
113+
assertThat(mockTracer.finishedSpans()).hasSize(0);
114+
assertThat(Mockito.mockingDetails(mockDecorator1).getInvocations()).hasSize(0);
115+
assertThat(Mockito.mockingDetails(mockDecorator2).getInvocations()).hasSize(0);
116+
}
117+
118+
public Callable<Integer> reportedSpansSize() {
119+
return () -> mockTracer.finishedSpans().size();
120+
}
121+
122+
@After()
123+
public void reset() {
124+
mockTracer.reset();
125+
infoCountDownLatch = new CountDownLatch(1);
126+
}
127+
}

opentracing-spring-web/src/main/java/io/opentracing/contrib/spring/web/webfilter/TracingWebFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ boolean shouldBeTraced(final ServerHttpRequest request) {
111111
return false;
112112
}
113113
}
114-
if (urlPatterns.stream().noneMatch(urlPattern -> urlPattern.matches(pathWithinApplication))) {
114+
if (!urlPatterns.isEmpty() && urlPatterns.stream().noneMatch(urlPattern -> urlPattern.matches(pathWithinApplication))) {
115115
if (LOG.isTraceEnabled()) {
116116
LOG.trace("Not tracing request " + request + " because it does not match any URL pattern: " + urlPatterns);
117117
}

0 commit comments

Comments
 (0)