Fixing TraceFilter order (#382)

after making TraceFilter process different dispatch types we've introduced a bug related to filter ordering. TraceFilter was registered with a default ordering which is of lowest precedence.

With this change we ensure that the ordering of TraceFilter is fixed.

Fixes #380
This commit is contained in:
Marcin Grzejszczak
2016-08-22 12:22:26 +02:00
parent 2f93bd955a
commit b24013075a
3 changed files with 141 additions and 2 deletions

View File

@@ -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";

View File

@@ -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;
}

View File

@@ -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> 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<Span> getSpan() {
return span;
}
}
}