3

I want to create a filter that would log the time spent for particular web request along with the operation name. However, some URLs have path parameters and I'm looking for something that would allow me to get a URL pattern that corresponds to the particular method instead of URL itself.

For example, for method that handles GET requests for URLs like /users/{id}/accounts/{type} I want to see operation name like GET /users/{}/accounts/{} instead of, say: GET /users/1/accounts/facebook or GET /users/2/accounts/twitter?someParam=3.

Right now I solve this by matching URL with predefined patterns in the tool that parses log records but to me it looks like a hack.

I didn’t find an easy way to access URL pattern associated with a method that handles incoming request, so one possible solution that I’m considering right now is setting a thread local variable in the controller method itself and access it in my HTTP filter but this also doesn’t seem like a clean way to solve this.

Is there any better solution to this problem?

To set up some context: I'm using Spring MVC 4.

3
  • 1
    If you have your filter extend GenericFilterBean it can be Spring manged. You can then inject an instance of the configured RequestMappingHandlerMapping which is what you would seem to need to find the mapping for a given request. I have not been able to work out how to proceed from here but see stackoverflow.com/questions/14025872/… which may give you some ideas as to how you would get the matching url pattern. Commented Nov 7, 2016 at 21:24
  • 1
    OK, looks like I see how to make it working. I'll update my question if I decide to stick with this approach with the working code - unless I decide to stick to something else. Commented Nov 11, 2016 at 20:22
  • @AlanHay I posted an answer, it turned out to be much simpler than I hoped it to be. Commented Nov 18, 2016 at 1:20

1 Answer 1

2

OK, it turned out to be super-simple. With spring, you can do it as follows:

public class HttpOperationLoggerFilter extends OncePerRequestFilter {
  private final Logger log = LoggerFactory.getLogger(getClass());

  @Override
  protected void doFilterInternal(HttpServletRequest request,
                                  HttpServletResponse response,
                                  FilterChain filterChain) throws ServletException, IOException {
      // do filter first
      filterChain.doFilter(request, response);

      // ... then you'll be able to access spring MVC's bestMatchingPattern!
      final Object urlPattern = request
        .getAttribute("org.springframework.web.servlet.HandlerMapping.bestMatchingPattern");
      log.info("urlPattern={}", urlPattern);
  }
}

So, if you have MVC controller's method that handles URL patterns like '/do/{something}/like/{that}' you'll see exactly that pattern!

Good thing is that this variable contains composite pattern, so if your controller is annotated with RequestMapping, its value will be prepended to the pattern.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.