0

What I am trying to do is the following: Modify the logback to write out the users id and request id on the log lines. e.g.

2017-11-24 [userid:abcd123 - requestId:12345679] [ClassA:MethodA1] message...
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassA:MethodA2] message...
2017-11-24 [userid:abcd123 - requestId:12345679] [ClassB:MethodB1] message...

Notice that the requestId remains the same as it is all part of one request made to the system by the end user.

I have created a Filter based off of several examples where it shows how to set values into the MDC. e.g.(https://logback.qos.ch/manual/mdc.html1)

...
@Component
public class RequestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            String mdcData = String.format("[userId:%s | requestId:%s] ", user(), requestId());
            MDC.put("mdcData", mdcData); //Referenced from logging configuration.
            chain.doFilter(request, response);
        } finally {
            MDC.clear();
        }
    }

    private String requestId() {
        return UUID.randomUUID().toString();
    }

    private String user() {
        return "tux";
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}
...

If I make a request to a rest service it executes one time without the system making any additional requests to itself for information. This is what I had expected and a I can see the log entries where they all contain the same requestId. If I make a browser page request to one of our Swagger pages then the web page makes multiple internal requests for additional information that will appear on the page. The logging captures about 20 requests made by the loading of the web page request due to all of the additional requests for information that the page needs to render. When this occurs then I end up with X number of log entries where each of the internal requests are generating a unique request and requestId gets logged for each of them. This was not my intention.

HOW do I determine with a request to the system the initiating portion over the internal request calls that are created?

I need to not set the MDC values for the requestId over and over. I only need it set once per call based on the first request that gets made from the external user.

Not even sure what you would call this other than lifecycle of a request but I'm not finding the answer.

Appreciate any guidance. Thanks.

EDIT: Link to another question I have out there that is only dealing with identifying the original user request.

edjm
  • 4,830
  • 7
  • 36
  • 65
  • 1
    What do you mean by "sub-call"? Do you mean that a given request is being forwarded many times, and that the filter is invoked at every forward? If so, you can just store an attribute in the request, and avoiding to filter if the attribute is already set. You can also set the dispatcher types of your filter (https://docs.oracle.com/javaee/7/api/javax/servlet/annotation/WebFilter.html#dispatcherTypes--). If that's not what you mean by "sub-call", then explain. – JB Nizet Nov 24 '17 at 19:26
  • By sub calls, yes the system is making many other calls to itself that are triggering the Filter. I checked on the dispatcher type which all show up as REQUEST. I'll look into the setting of the attribute and that sounds like it may be the simple fix I need. – edjm Nov 24 '17 at 19:29
  • It's still very unclear what you mean by "the system", and by "calls". If you have a frontend sending many requests to your server, then there is no such thing as a "sub-call". These are just requests, independant from each other. – JB Nizet Nov 24 '17 at 19:30
  • My apologies. Allow me to rewrite the problem. – edjm Nov 26 '17 at 00:38

1 Answers1

1

One way to address this is to map you RequestFilter to the URL pattern of your services that you want to log and not to "/*".

EDIT: Another idea would be to map the filter to "/*" but in your doFilter method, do not MDC any requests that contain "swagger" in the URL. You might have to experiment and possibly include all the URL's that get generated from the Swagger page, as some may not contain the word "swagger" in them.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    if (isRequestSwaggerUrl(request)) {
        chain.doFilter(request, response);
        return;
    }

    try {
        String mdcData = String.format("[userId:%s | requestId:%s] ", user(), requestId());
        MDC.put("mdcData", mdcData); //Referenced from logging configuration.
        chain.doFilter(request, response);
    } finally {
        MDC.clear();
    }
}
Jose Martinez
  • 11,452
  • 7
  • 53
  • 68
  • I was trying to avoid doing that as I don't know the system and all of the end points or pages that can load, but it looks like I'm going to have to do this if I am not able to be more generic. Thanks for the input. – edjm Nov 27 '17 at 12:19