Search code examples
javafiltertracespring-boot-actuator

Configuring TraceFilter in Actuator (Springboot) does not work


I am trying to create filters in a separate jar from my main spring boot project. One of them is the Trace filter in Actuator (the one which is executed when calling /trace), and I am configuring it to not tracing the calls to /trace itself. If I define the filter inside the project, it works perfectly and it does not trace the calls to /trace.

However, when I extract the class to another library and reference it from the main project, it is tracing those calls. I have checked that all references are correct, and the filter is being executed. However, I suspect that when initializing dependencies, both my filter and WebRequestTraceFilter (the class from my filter is inheriting) are being instantiated. This is the Filter class:

package common.api.filters.trace;


import org.springframework.boot.actuate.trace.TraceProperties;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.actuate.trace.WebRequestTraceFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * Class to exclude some some endpoints to be traced such as /admin/**, * /trace and
 * endpoints provide static files like /css/** and /js/**.
 */
@Component
public class RequestTraceFilter extends WebRequestTraceFilter {

    private static final String[] excludedEndpoints = new String[]{"/css/**", "/js/**", "/trace"};

    public RequestTraceFilter(TraceRepository repository, TraceProperties properties) {
        super(repository, properties);
    }

    /*
        The default implementation was always returning false.
        With this implementation, it returns true for the endpoints we don’t want to trace.
     */
    @Override
    protected boolean shouldNotFilter(final HttpServletRequest request) throws ServletException {
        return Arrays
                .stream(excludedEndpoints)
                .anyMatch(e -> new AntPathMatcher().match(e, request.getServletPath()));
    }
}

I also have tried to remove the tag @Component and initialize the Filter this way in a class tagged with @Configuration:

@Bean
public FilterRegistrationBean createTraceFilter(){
    FilterRegistrationBean frb = new FilterRegistrationBean();
    frb.setFilter(new RequestTraceFilter(new InMemoryTraceRepository(), new TraceProperties()));
    return frb;
}

But the result is the same: filter is being executed but the calls to /trace are being traced.

How can I initialize my Filter in main project to be the only one that is executed when tracing?


Solution

  • I have found out what was happening: as I thought, there were being instantiated two classes: RequestTraceFilter and WebRequestTraceFilter. So, mine was being executed correctly, but WebRequestTraceFilter was also being executed and returning false in shouldNotFilter method, tracing the call to /trace itself. I have solved it changing the way I initialize dependencies this way:

    @Bean
    public WebRequestTraceFilter createTraceFilter(){
        return new RequestTraceFilter(new InMemoryTraceRepository(), new TraceProperties());
    }
    

    So now, when Spring boot is asking an instance of WebRequestTraceFilter, it is returning only mine.