Log4j 2
  1. Log4j 2
  2. LOG4J2-500

Unloading one webapp unloads JMX MBeans for all webapps

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0-rc1
    • Fix Version/s: 2.0-rc1
    • Component/s: JMX
    • Labels:
      None

      Description

      As a stopgap solution for LOG4J2-406, all MBeans are unregistered when a LoggerContext is stopped.

      In an application server, multiple web applications can be deployed and undeployed independently and a better solution would only unregister the MBeans associated with the web application that is being undeployed.

      Current MBean ObjectNames look like this (simplified):

      ...StatusLogger
      ...ContextSelector
      ...LoggerContext,ctx=%s
      ...LoggerConfig,ctx=%s,name=%s
      ...Appender,ctx=%s,name=%s
      ...
      

      Assuming that every web application has a unique name, and this name becomes the name of the LoggerContext, then one solution would be to create StatusLogger and ContextSelector MBeans that have the LoggerContext name in their ObjectName:

      ...StatusLogger,ctx=%s
      ...ContextSelector,ctx=%s
      ...LoggerContext,ctx=%s
      ...LoggerConfig,ctx=%s,name=%s
      ...Appender,ctx=%s,name=%s
      ...
      

      This way, every web application would have its own StatusLogger and ContextSelector MBeans. The MBeans may point to the same (shared) underlying StatusLogger and ContextSelector objects. When a web application is undeployed, unregistering all MBeans associated with the LoggerContext will not affect any MBeans associated with another web application (which has it own, separate, LoggerContext).

        Issue Links

          Activity

          Hide
          Remko Popma added a comment - - edited

          The new ObjectNames correctly separate MBeans for multiple web applications. Unloading a webapp now correctly unregisters the MBeans for only that LoggerContext.

          Two items remain:

          1. (at least in Tomcat 7.0.50 and 8.0.1) listeners and filters need to be configured in web.xml in order for the Log4j2 MBeans to be unregistered when the web application is undeployed. We expected that to happen automatically in Servlet 3.0 containers. LOG4J2-529 was created to track this issue.
          2. The Log4J2 JMX GUI needs to dynamically update and add/remove the relevant tabs when MBeans for a LoggerContext are registered/unregistered. LOG4J2-530 tracks this issue.
          Show
          Remko Popma added a comment - - edited The new ObjectNames correctly separate MBeans for multiple web applications. Unloading a webapp now correctly unregisters the MBeans for only that LoggerContext. Two items remain: (at least in Tomcat 7.0.50 and 8.0.1) listeners and filters need to be configured in web.xml in order for the Log4j2 MBeans to be unregistered when the web application is undeployed. We expected that to happen automatically in Servlet 3.0 containers. LOG4J2-529 was created to track this issue. The Log4J2 JMX GUI needs to dynamically update and add/remove the relevant tabs when MBeans for a LoggerContext are registered/unregistered. LOG4J2-530 tracks this issue.
          Hide
          Remko Popma added a comment - - edited

          I may need some help with this...

          With the current version of trunk, MBeans are not unregistering when a webapp is undeployed. As far as I can tell, the LoggerContext.stop() method is never called. I've tested on Tomcat 7.0.50 and 8.0.1.

          I have log4j-api and log4j-core jar files in WEB-INF/lib, and a jsp file that instantiates a Logger and calls logger.info() on it. No listeners or anything. Displaying the JSP page in a browser correctly causes the MBeans to get registered: I can see status logger debug messages ("Registering MBean org.apache.logging.log4j2...") in the Tomcat console.

          When undeploying the webapp, I expected the Log4jWebInitializerImpl.deinitialize() method to be called, but I don't see the log message "Removing LoggerContext for " + this.name + "." in the console or in any log file...
          On the same hand, I also cannot find any initialization log messages. (I expected to see the "Log4jServletContainerInitializer starting up Log4j in Servlet 3.0+ environment." message somewhere but cannot find it.)

          Show
          Remko Popma added a comment - - edited I may need some help with this... With the current version of trunk, MBeans are not unregistering when a webapp is undeployed. As far as I can tell, the LoggerContext.stop() method is never called. I've tested on Tomcat 7.0.50 and 8.0.1. I have log4j-api and log4j-core jar files in WEB-INF/lib, and a jsp file that instantiates a Logger and calls logger.info() on it. No listeners or anything. Displaying the JSP page in a browser correctly causes the MBeans to get registered: I can see status logger debug messages ("Registering MBean org.apache.logging.log4j2...") in the Tomcat console. When undeploying the webapp, I expected the Log4jWebInitializerImpl.deinitialize() method to be called, but I don't see the log message "Removing LoggerContext for " + this.name + "." in the console or in any log file... On the same hand, I also cannot find any initialization log messages. (I expected to see the "Log4jServletContainerInitializer starting up Log4j in Servlet 3.0+ environment." message somewhere but cannot find it.)
          Hide
          Remko Popma added a comment -

          This is still in progress, but I've made the following changes in revisions 1563745 and 1563911:

          ObjectName changes
          (NEW JMX ObjectNames ARE INCOMPATIBLE WITH BETA-9 AND OLDER VERSIONS)

          • Appenders: org.apache.logging.log4j2:type=%s,component=Appenders,name=%s
          • Async Appenders: org.apache.logging.log4j2:type=%s,component=AsyncAppenders,name=%s
          • ContextSelector: org.apache.logging.log4j2:type=%s,component=ContextSelector
          • LoggerConfigs: org.apache.logging.log4j2:type=%s,component=Loggers,name=%s
          • LoggerContext: org.apache.logging.log4j2:type=%s
          • RingBuffer for all loggers async: org.apache.logging.log4j2:type=%s,component=AsyncLoggerRingBuffer
          • RingBuffer for mixed sync/async: org.apache.logging.log4j2:type=%s,component=Loggers,name=%s,subtype=RingBuffer
          • StatusLogger: org.apache.logging.log4j2:type=%s,component=StatusLogger

          (In case you wonder why these ObjectNames have type=LoggerContextName and not name=LoggerContextName. JConsole will assume that every ObjectName has a type property and will prioritize the type property when building the navigation tree. Google "JMX Best Practices" for details.)

          JMX Client GUI

          • Now has a tab for each active LoggerContext
          • Each LoggerContext tab is itself a tabbed pane with a LoggerStatus tab and a configuration editor tab
          • Updated screenshots in JMX Client GUI manual page

          Granular Unloading
          LoggerContext will now only unregister its own MBeans when stopped (unloading a webapp only unregisters the MBeans for that webapp)

          TODO

          • Test with web application (multiple active contexts, loading/unloading)
          • Document somewhere that the MBean ObjectNames are changing with this release
          • (Optional) Add screenshots with multiple active Logger Contexts
          • (Optional) Dynamically update client GUI when a web application is loaded and MBeans are registered (or unloaded and MBeans are unregistered)
          Show
          Remko Popma added a comment - This is still in progress, but I've made the following changes in revisions 1563745 and 1563911: ObjectName changes (NEW JMX ObjectNames ARE INCOMPATIBLE WITH BETA-9 AND OLDER VERSIONS) Appenders: org.apache.logging.log4j2:type=%s,component=Appenders,name=%s Async Appenders: org.apache.logging.log4j2:type=%s,component=AsyncAppenders,name=%s ContextSelector: org.apache.logging.log4j2:type=%s,component=ContextSelector LoggerConfigs: org.apache.logging.log4j2:type=%s,component=Loggers,name=%s LoggerContext: org.apache.logging.log4j2:type=%s RingBuffer for all loggers async: org.apache.logging.log4j2:type=%s,component=AsyncLoggerRingBuffer RingBuffer for mixed sync/async: org.apache.logging.log4j2:type=%s,component=Loggers,name=%s,subtype=RingBuffer StatusLogger: org.apache.logging.log4j2:type=%s,component=StatusLogger (In case you wonder why these ObjectNames have type=LoggerContextName and not name=LoggerContextName . JConsole will assume that every ObjectName has a type property and will prioritize the type property when building the navigation tree. Google "JMX Best Practices" for details.) JMX Client GUI Now has a tab for each active LoggerContext Each LoggerContext tab is itself a tabbed pane with a LoggerStatus tab and a configuration editor tab Updated screenshots in JMX Client GUI manual page Granular Unloading LoggerContext will now only unregister its own MBeans when stopped (unloading a webapp only unregisters the MBeans for that webapp) TODO Test with web application (multiple active contexts, loading/unloading) Document somewhere that the MBean ObjectNames are changing with this release (Optional) Add screenshots with multiple active Logger Contexts (Optional) Dynamically update client GUI when a web application is loaded and MBeans are registered (or unloaded and MBeans are unregistered)
          Hide
          Nick Williams added a comment -

          It can be both.

          If a web application has the Log4j libraries in its /WEB-INF/lib directory, it ALWAYS has its own StatusLogger class that is not the same as the StatusLogger class of any application or the container. This is true even if the container also provides Log4j libraries. However, if the container provides Log4j libraries and the application DOES NOT, then an application would share the container's StatusLogger class.

          So with all that said, the most complex scenario imaginable is that the container provides the Log4j libraries, multiple applications are deployed, and some of those applications provide their own Log4j libraries while others don't. In this case, there will be multiple StatusLogger classes, but not necessarily as many as there are applications using Log4j. Fun, huh?

          So, in short, the GUI does need to show separate text areas for each StatusLogger.

          Show
          Nick Williams added a comment - It can be both. If a web application has the Log4j libraries in its /WEB-INF/lib directory, it ALWAYS has its own StatusLogger class that is not the same as the StatusLogger class of any application or the container. This is true even if the container also provides Log4j libraries. However, if the container provides Log4j libraries and the application DOES NOT, then an application would share the container's StatusLogger class. So with all that said, the most complex scenario imaginable is that the container provides the Log4j libraries, multiple applications are deployed, and some of those applications provide their own Log4j libraries while others don't. In this case, there will be multiple StatusLogger classes, but not necessarily as many as there are applications using Log4j. Fun, huh? So, in short, the GUI does need to show separate text areas for each StatusLogger.
          Hide
          Remko Popma added a comment -

          This is not as straight-forward as I thought: it turns out that registering StatusLogger multiple times (once for each LoggerContext) impacts the GUI.

          I haven't figured out yet if it really is the same StatusLogger instance that is registered multiple times, or whether multiple webapps (by having different classloaders) actually have different StatusLogger instances. And just to make it extra fun, perhaps both are possible, depending on whether the log4j2 jar files are in the web container lib folder (and shared between web applications) or bundled with the web application (in WEB-INF/lib)...

          If multiple StatusLoggers are possible then the GUI needs to show separate text areas for each StatusLogger.

          Show
          Remko Popma added a comment - This is not as straight-forward as I thought: it turns out that registering StatusLogger multiple times (once for each LoggerContext) impacts the GUI. I haven't figured out yet if it really is the same StatusLogger instance that is registered multiple times, or whether multiple webapps (by having different classloaders) actually have different StatusLogger instances. And just to make it extra fun, perhaps both are possible, depending on whether the log4j2 jar files are in the web container lib folder (and shared between web applications) or bundled with the web application (in WEB-INF/lib)... If multiple StatusLoggers are possible then the GUI needs to show separate text areas for each StatusLogger.
          Hide
          Remko Popma added a comment -

          Not yet. Should be fairly straight-forward. I'll try to resolve it this week.

          Show
          Remko Popma added a comment - Not yet. Should be fairly straight-forward. I'll try to resolve it this week.
          Hide
          Nick Williams added a comment -

          Remko, have you had a chance to look at this anymore? We should get this fixed before GA.

          Show
          Nick Williams added a comment - Remko, have you had a chance to look at this anymore? We should get this fixed before GA.

            People

            • Assignee:
              Remko Popma
              Reporter:
              Remko Popma
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development