Last Updated: February 25, 2016
· mfornos

JAX-RS Mapped Diagnostic Context Filter

Are you running REST APIs? Using a JAX-RS 2.0 implementation?
Have you ever felt the need of knowing in which client request a log entry was originated?

If you answered «yes» to the above questions, then the following filter will make your day (hopefully).


import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;

import org.slf4j.MDC;

import com.google.common.base.Optional;

 * JAX-RS filter that sets a 'client-id', obtained from 
 * 'X-Forwarded-For' HTTP header or remote IP address 
 * if not present, as mapped diagnostic context attribute
 * for resource methods and classes annotated with @Diagnostic.
public class MDCFilter implements ContainerRequestFilter, ContainerResponseFilter
    private static final String CLIENT_ID = "client-id";

    protected HttpServletRequest r;

    public void filter(ContainerRequestContext req) throws IOException
        Optional<String> clientId = Optional.fromNullable(r.getHeader("X-Forwarded-For"));
        MDC.put(CLIENT_ID, clientId.or(defaultClientId()));

    public void filter(ContainerRequestContext req, ContainerResponseContext resp) throws IOException

    private String defaultClientId()
        return "Direct:" + r.getRemoteAddr();

And here the name binding annotation:


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.ws.rs.NameBinding;

@Target({ ElementType.METHOD, ElementType.TYPE })
public @interface Diagnostic

Configure your logging facility layout pattern to include the %X{client-id} attribute that will be available from MDC. For the sake of example, a log4j conversion pattern:

%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %X{client-id} %m%n

Lastly, register the MDCFilter in your JAX-RS runtime and that's all, folks.

Now you can annotate your resource methods with @Diagnostic to enable a Mapped Diagnostic Context per client request.

A trivial example to close this tip:

public class LogResource
    private static final Logger log = LoggerFactory.getLogger(LogResource.class);

    public void info()
        log.info("Hi ho!");

Don't forget to play nice!