Log4j 2
  1. Log4j 2
  2. LOG4J2-270

Improve logging initialization in Servlet containers; reduce amount of extra configuration needed in these contexts

    Details

    • Type: Improvement Improvement
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0-beta6, 2.0-beta7
    • Fix Version/s: 2.0-beta8
    • Component/s: Core

      Description

      [Note: This has been pulled from discussions surrounding LOG4J2-223. Specifically, the description below comes from this comment.]

      Okay, based on all of this, here are my suggestions on how I would improve this (sorry for my scarcity lately ... trying to catch up on chapters for the book). These suggestions are based on the following goals:

      1. Design web application support so that users of simple Log4j configurations (not using JNDI lookups for logging configuration) don't have to do any additional configuration to get Log4j to "just work" in a Servlet container. This goal is made with the understanding that this is only possible for users of Servlet 3.0, 3.1, or higher. Users of Servlet 2.5 will have to manually configure listeners and filters. It's the only way.
      2. Eliminate the need for web applications to have an additional JAR just to support proper configuration.
      3. Improve the documentation considerably so that it is abundantly clear how Log4j works in web applications.

      With these goals in mind, here are my recommendations:

      • Get rid of the log4j-web module and move this stuff into log4j-core. We'll need Timothy Ward's input on how this could impact OSGi support. In theory, I don't think we should have a problem. No other Log4j classes will refer to the listener or filter. These classes will only ever get loaded BY the Servlet container, in which case the Servlet API will already be loaded, so I don't think it would be possible to get NoClassDefFoundError s.
      • Create a /META-INF/web-fragment.xml file with the contents noted below. This will ensure that the Log4j fragment is loaded before any other fragments.
      • Create a Log4jWebInitializer class (doesn't implement any interfaces, package-private) to properly initialize and de-initialize Log4j in a Servlet container. It works like this: If the context parameters currently required by the JNDIContextFilter exist, it initializes Log4j the way JNDIContextFilter currently does. If they don't exist, it initializes Log4j the way Log4jContextListener currently does.
      • Create a Log4jServletContainerInitializer implements ServletContainerInitializer and a /META-INF/services/javax.servlet.ServletContainerInitializer file to go along with it. This initializer:
        • Initializes Log4j properly using the Log4jWebInitializer.
        • Installs a private listener to de-initialize Log4j when the container shuts down the application using the Log4jWebInitializer.
        • Installs the NamedContextFilter (renamed from JNDIContextFilter), which doesn't do any initialization/deinitialization, it just does what it currently does for doFilter.
      • Change the existing Log4jContextListener to use the Log4jWebInitializer.
      • Create a new manual page directly under the "MANUAL" menu heading on the homepage that explains how to use Log4j in a Servlet container:
        • If you're using Servlet 3.0 or higher, it "just works," but if you're also using JNDI you need to create the proper context parameters.
        • If you're using Servlet 2.5, you MUST add the Log4jContextListener (and the NamedContextFilter and context parameters if you're using JNDI) to your deployment descriptor.

      Now, to address some questions:

      1. "What to do about JBoss 5, which doesn't support web-fragment.xml?" JBoss 5 doesn't support web-fragment.xml because it's a Servlet 2.5 container, not a Servlet 3.0 container. Users of JBoss 5 would follow the Servlet 2.5 instructions just like all other users. Users of JBoss 6, 7, 8, etc., would follow the Servlet 3.0 instructions ("don't do anything").
      2. "A container with multiple web applications. The Log4j jars are in the Tomcat classpath and they all share the same configuration file." versus "A container with multiple web applications. Each has their own copy of the log4j jars and each has their own configuration file." Easy! The Log4jServletContainerInitializer will get executed for every application, whether the Log4j JARs are in the Tomcat classpath or in /WEB-INF/lib (this is per the Servlet specification). Each application will get its own context. Regardless of where the JARs are, that context will load the application's configuration file if it has its own, and will load the shared configuration if it doesn't have its own.

      Thoughts?

      web-fragment.xml
      <web-fragment ... metadata-complete="true">
          <name>log4j</name>
          <distributable/>
          <ordering>
              <before>
                  <others/>
              </before>
          </ordering>
      </web-fragment>

        Issue Links

          Activity

          Hide
          Remko Popma added a comment -

          Nick, while reading the commit email, I noticed that in the new webapp.xml manual page, in the section on Context Parameters,
          You give a few examples of using log4jConfiguration to point to a log4j config file.
          In these examples the config files are all named log4j.xml, not log4j2.xml. Just wanted to check if that was on purpose or not...
          (Nice work by the way.)

          Show
          Remko Popma added a comment - Nick, while reading the commit email, I noticed that in the new webapp.xml manual page, in the section on Context Parameters, You give a few examples of using log4jConfiguration to point to a log4j config file. In these examples the config files are all named log4j.xml, not log4j2.xml. Just wanted to check if that was on purpose or not... (Nice work by the way.)
          Hide
          Nick Williams added a comment -

          Remko, a valid question. I did not want to use the name log4j2.xml so as to highlight the fact that you could name the file whatever you want using this context parameter. However, I can see how log4j.xml can be confusing. I'm wrapping up another commit regarding this issue, so I'll change the name to something more obviously different.

          Show
          Nick Williams added a comment - Remko, a valid question. I did not want to use the name log4j2.xml so as to highlight the fact that you could name the file whatever you want using this context parameter. However, I can see how log4j.xml can be confusing. I'm wrapping up another commit regarding this issue, so I'll change the name to something more obviously different.
          Hide
          Nick Williams added a comment -

          Completed for 2.0-beta8. log4j-web module/artifact is removed. log4j-core can now initialize/deinitialize itself automatically in Servlet 3.0 containers. In Servlet 2.5 containers users still have to use the listener, but they can do so with just log4j-core.

          Show
          Nick Williams added a comment - Completed for 2.0-beta8. log4j-web module/artifact is removed. log4j-core can now initialize/deinitialize itself automatically in Servlet 3.0 containers. In Servlet 2.5 containers users still have to use the listener, but they can do so with just log4j-core.

            People

            • Assignee:
              Unassigned
              Reporter:
              Nick Williams
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Time Tracking

                Estimated:
                Original Estimate - 72h
                72h
                Remaining:
                Remaining Estimate - 72h
                72h
                Logged:
                Time Spent - Not Specified
                Not Specified

                  Development