Spring application without web.xml log4j configuration

jerseylog4jlog4j2spring

I have a Spring + Jersey web application that I'm migrating from a web.xml to annotation base configuration. I'm implementing WebApplicationInitializer and everything works except log4j, because I have a custom file name.

In the web.xml I had

<context-param>
    <param-name>log4jConfiguration</param-name>
    <param-value>/WEB-INF/custom-name-log4j.xml</param-value>
</context-param>

This worked.

Now, I tried to do the same in Java:

container.setInitParameter("log4jConfiguration", "/WEB-INF/custom-name-log4j.xml");

This doesn't work… I get the following errors in Tomcat 7.0.62:

ERROR StatusLogger No Log4j context configuration provided. This is very unusual.
ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

My WAR file contains the xml in the WEB-INF/ folder.

Do I have to do more than specifying that log4jConfiguration parameter?

Later Edit:
WebApplicationInitializer

    @Override
    public void onStartup(ServletContext container) {
        AnnotationConfigWebApplicationContext rootContext =
                new AnnotationConfigWebApplicationContext();
        rootContext.register(MyApplicationConfiguration.class);

        container.setInitParameter("log4jConfiguration", "/WEB-INF/custom-name-log4j.xml");

        rootContext.setConfigLocation("my.package.spring");

        final FilterRegistration.Dynamic characterEncodingFilter = container.addFilter("characterEncodingFilter", new CharacterEncodingFilter());
        characterEncodingFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
        characterEncodingFilter.setInitParameter("encoding", "UTF-8");
        characterEncodingFilter.setInitParameter("forceEncoding", "true");

        container.setInitParameter("spring.profiles.default", "prod");

        rootContext.register(SecurityContextFilter.class);

        container.addListener(new ContextLoaderListener(rootContext));
        container.addListener(new RequestContextListener());

        container.setInitParameter("contextConfigLocation", "");

        final ServletContainer servlet = new ServletContainer();
        final ServletRegistration.Dynamic appServlet = container.addServlet("appServlet", servlet);
        appServlet.setInitParameter("jersey.config.server.provider.packages", "my.package");
        appServlet.setLoadOnStartup(1);

        final Set<String> mappingConflicts = appServlet.addMapping("/rest/*");

    }

Best Answer

You also need to register a Listener : Log4jConfigListener (you can find it in org.springframework.web.util)

servletContext.addListener(Log4jConfigListener.class);

By the way, you can note that it is deprecated since spring 4.2.1

EDIT

Sorry I didn't realized that you were using log4j2, everything stated above is false, and here is the solution for you :

log4j2 (thanks to log4j-web artifact) & spring are both relying on ServletContainerInitializer from servlet 3.0 API to setup the ServletContext. The problem is that the order they are executed depends on the order they are scanned on the classpath and you can't really rely on it (in your case the Log4jServletContainerInitializer startup methods is called before the one from SpringServletContainerInitializer).

To correct this you can declare your own ServletContainerInitializer implementation which we'll be taken into account before others (before scanning the classpath) and here is a sample :

public class Log4j2ConfigServletContainerInitializer implements ServletContainerInitializer {

    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        ctx.setInitParameter("log4jConfiguration", "/WEB-INF/custom-name-log4j.xml");
    }
}

Then you have to create a file : /META-INF/services/javax.servlet.ServletContainerInitializer

and put into it :

example.initializer.Log4j2ConfigServletContainerInitializer (change to suit your needs)

and the configuration you provided to set a custom log4j config file location will be set before triggering the Log4jServletContainerInitializer and everything is going to be fine.

see :

https://docs.oracle.com/javaee/6/api/javax/servlet/ServletContainerInitializer.html

http://www.eclipse.org/jetty/documentation/current/using-annotations.html#servlet-container-initializers

http://logging.apache.org/log4j/2.x/manual/webapp.html

EDIT

POC @ http://www.filedropper.com/32713596_1 just run mvn jetty:run

Related Topic