Unloading one webapp unloads JMX MBeans for all webapps

Details

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.

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:

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

depends upon

LOG4J2-529Log4j2 does not auto-initialize on webapp deploy or auto-deinitialize on undeploy

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.

Remko Popma
added a comment - 31/Jan/14 16:04 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.

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.

Nick Williams
added a comment - 31/Jan/14 19:07 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.

(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)

Remko Popma
added a comment - 03/Feb/14 14:57 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)

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.)

Remko Popma
added a comment - 05/Feb/14 10:26 - 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.)

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.

Remko Popma
added a comment - 07/Feb/14 03:11 - 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.