Search code examples
web-applicationslog4j2mdc

Log4j2: unable to set MDC keys using Servlet Context Listener


I'm trying to set the hostname as a MDC variable using a Servlet Context Listener. The MDC variable gets available only in the listener itself, but it disappears if i try to log from other servlets.

Here my listener code:

public class MdcServletListener implements ServletContextListener {

    /** logger. */
    private static Logger logger = LoggerFactory
            .getLogger(MdcServletListener.class);

    /*
     * (non-Javadoc)
     * 
     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.
     * ServletContextEvent)
     */
    @Override
    public void contextDestroyed(ServletContextEvent sContext) {

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * javax.servlet.ServletContextListener#contextInitialized(javax.servlet
     * .ServletContextEvent)
     */
    @Override
    public void contextInitialized(ServletContextEvent sContext) {
        try {
            ThreadContext.put("LISTENER", "TEST");
            logger.info("Inizializzazione variabili mdc completata");
        } catch (Exception e) {
            logger.error("Inizializzazione variabili mdc fallita", e);
        }

    }

}

Here my web.xml:

<listener>
        <listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
    </listener>
    <listener>
        <listener-class>MdcServletListener</listener-class>
    </listener>
    <filter>
        <filter-name>log4jServletFilter</filter-name>
        <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>log4jServletFilter</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>INCLUDE</dispatcher>
        <dispatcher>ERROR</dispatcher>
    </filter-mapping>

Any suggestion? Thanks.


Solution

  • MDC configuration holds client specific or request specific data and is basically done per thread/client. In other words since each client request for a servlet is handled by a separate thread by the container; the configuration should rather go in a filter for that servlet rather than in the ServletContextListener(Your MdcServletListener class). The ServletContextListener that you extend is per webapp and does not hold individual request data MDC is intended for.

    Would suggest putting this line ThreadContext.put("LISTENER", "TEST"); in your own servlet filter.

    And then in your log4j.properties; you can access the above variable that you set using:- %X{LISTENER}%n.

    For example your appender configuration in your log4j.properties will change as below:- log4j.appender.yourAppender.layout.ConversionPattern = %-4r [%t] %5p %c %x - %m - %X{LISTENER}%n

    In the above example config notice the %X{LISTENER}%n added in the end to access the MDC specific data that you set.