diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java index 50faa46a6..cdf25664c 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceFilter.java @@ -65,13 +65,15 @@ import org.springframework.web.util.UrlPathHelper; * @see TraceKeys * @see TraceWebAutoConfiguration#traceFilter */ -@Order(Ordered.HIGHEST_PRECEDENCE + 5) +@Order(TraceFilter.ORDER) public class TraceFilter extends GenericFilterBean { private static final Log log = LogFactory.getLog(MethodHandles.lookup().lookupClass()); private static final String HTTP_COMPONENT = "http"; + protected static final int ORDER = Ordered.HIGHEST_PRECEDENCE + 5; + protected static final String TRACE_REQUEST_ATTR = TraceFilter.class.getName() + ".TRACE"; diff --git a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java index e2b00eeaf..39cd582f2 100644 --- a/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java +++ b/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/web/TraceWebAutoConfiguration.java @@ -15,8 +15,8 @@ */ package org.springframework.cloud.sleuth.instrument.web; -import javax.servlet.http.HttpServletRequest; import java.util.regex.Pattern; +import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.annotation.Value; @@ -90,6 +90,7 @@ public class TraceWebAutoConfiguration { HttpTraceKeysInjector httpTraceKeysInjector, TraceFilter traceFilter) { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(traceFilter); filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE, REQUEST); + filterRegistrationBean.setOrder(TraceFilter.ORDER); return filterRegistrationBean; } diff --git a/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationMultipleFiltersTests.java b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationMultipleFiltersTests.java new file mode 100644 index 000000000..e51800a45 --- /dev/null +++ b/spring-cloud-sleuth-core/src/test/java/org/springframework/cloud/sleuth/instrument/web/TraceFilterWebIntegrationMultipleFiltersTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2013-2016 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 + * + * http://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.io.IOException; +import java.util.concurrent.atomic.AtomicReference; +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import org.junit.After; +import org.junit.Before; +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.context.embedded.FilterRegistrationBean; +import org.springframework.boot.test.SpringApplicationConfiguration; +import org.springframework.boot.test.WebIntegrationTest; +import org.springframework.cloud.sleuth.Sampler; +import org.springframework.cloud.sleuth.Span; +import org.springframework.cloud.sleuth.Tracer; +import org.springframework.cloud.sleuth.sampler.AlwaysSampler; +import org.springframework.cloud.sleuth.trace.TestSpanContextHolder; +import org.springframework.cloud.sleuth.util.ExceptionUtils; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.filter.GenericFilterBean; + +import static org.springframework.cloud.sleuth.assertions.SleuthAssertions.then; + +/** + * @author Marcin Grzejszczak + */ +@RunWith(SpringJUnit4ClassRunner.class) +@WebIntegrationTest({ "server.port=0" }) +@SpringApplicationConfiguration(classes = { TraceFilterWebIntegrationMultipleFiltersTests.Config.class }) +public class TraceFilterWebIntegrationMultipleFiltersTests { + + @Autowired Tracer tracer; + @Autowired RestTemplate restTemplate; + @Autowired Environment environment; + @Autowired MyFilter myFilter; + + @Before + @After + public void cleanup() { + ExceptionUtils.setFail(true); + TestSpanContextHolder.removeCurrentSpan(); + } + + @Test + public void should_register_trace_filter_before_the_custom_filter() { + this.restTemplate.getForObject("http://localhost:" + port() + "/", String.class); + + then(this.tracer.getCurrentSpan()).isNull(); + then(this.myFilter.getSpan().get()).isNotNull(); + then(ExceptionUtils.getLastException()).isNull(); + } + + private int port() { + return this.environment.getProperty("local.server.port", Integer.class); + } + + @EnableAutoConfiguration + @Configuration + public static class Config { + + @Bean Sampler alwaysSampler() { + return new AlwaysSampler(); + } + + + @Bean RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override public void handleError(ClientHttpResponse response) + throws IOException { + } + }); + return restTemplate; + } + + @Bean MyFilter myFilter(Tracer tracer) { + return new MyFilter(tracer); + } + + @Bean FilterRegistrationBean registrationBean(MyFilter myFilter) { + FilterRegistrationBean bean = new FilterRegistrationBean(); + bean.setFilter(myFilter); + bean.setOrder(0); + return bean; + } + } + + static class MyFilter extends GenericFilterBean { + + AtomicReference span = new AtomicReference<>(); + + private final Tracer tracer; + + MyFilter(Tracer tracer) { + this.tracer = tracer; + } + + @Override public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + Span currentSpan = tracer.getCurrentSpan(); + this.span.set(currentSpan); + } + + public AtomicReference getSpan() { + return span; + } + } +}