You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2014/02/07 18:49:34 UTC
svn commit: r1565741 - in /logging/log4j/log4j2/trunk:
log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/
log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/ src/changes/
Author: rpopma
Date: Fri Feb 7 17:49:34 2014
New Revision: 1565741
URL: http://svn.apache.org/r1565741
Log:
LOG4J2-530 JMX Client GUI should dynamically update when LoggerContext MBeans are registered/unregistered in MBean server
Modified:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java
logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/Client.java
logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/ClientGUI.java
logging/log4j/log4j2/trunk/src/changes/changes.xml
Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java?rev=1565741&r1=1565740&r2=1565741&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/jmx/LoggerContextAdminMBean.java Fri Feb 7 17:49:34 2014
@@ -20,16 +20,19 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Map;
+import javax.management.ObjectName;
+
/**
* The MBean interface for monitoring and managing a {@code LoggerContext}.
*/
public interface LoggerContextAdminMBean {
/**
- * ObjectName pattern ({@value}) for LoggerContextAdmin MBeans.
- * This pattern contains a variable, which is the name of the logger context.
+ * ObjectName pattern ({@value} ) for LoggerContextAdmin MBeans. This
+ * pattern contains a variable, which is the name of the logger context.
* <p>
* You can find all registered LoggerContextAdmin MBeans like this:
* </p>
+ *
* <pre>
* MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
* String pattern = String.format(LoggerContextAdminMBean.PATTERN, "*");
@@ -37,14 +40,16 @@ public interface LoggerContextAdminMBean
* </pre>
* <p>
* Some characters are not allowed in ObjectNames. The logger context name
- * may be quoted. When LoggerContextAdmin MBeans are
- * registered, their ObjectNames are created using this pattern as follows:
+ * may be quoted. When LoggerContextAdmin MBeans are registered, their
+ * ObjectNames are created using this pattern as follows:
* </p>
+ *
* <pre>
* String ctxName = Server.escape(loggerContext.getName());
* String name = String.format(PATTERN, ctxName);
* ObjectName objectName = new ObjectName(name);
* </pre>
+ *
* @see Server#escape(String)
*/
String PATTERN = Server.DOMAIN + ":type=%s";
@@ -52,27 +57,33 @@ public interface LoggerContextAdminMBean
/**
* Notification that the {@code Configuration} of the instrumented
* {@code LoggerContext} has been reconfigured. Notifications of this type
- * ({@value}) do not carry a message or user data.
+ * ({@value} ) do not carry a message or user data.
*/
String NOTIF_TYPE_RECONFIGURED = "com.apache.logging.log4j.core.jmx.config.reconfigured";
/**
+ * Returns the {@code ObjectName} that this MBean is registered with in the
+ * MBean server.
+ */
+ ObjectName getObjectName();
+
+ /**
* Returns the status of the instrumented {@code LoggerContext}.
- *
+ *
* @return the LoggerContext status.
*/
String getStatus();
/**
* Returns the name of the instrumented {@code LoggerContext}.
- *
+ *
* @return the name of the instrumented {@code LoggerContext}.
*/
String getName();
/**
* Returns the configuration location URI as a String.
- *
+ *
* @return the configuration location
*/
String getConfigLocationURI();
@@ -80,22 +91,21 @@ public interface LoggerContextAdminMBean
/**
* Sets the configuration location to the specified URI. This will cause the
* instrumented {@code LoggerContext} to reconfigure.
- *
+ *
* @param configLocation location of the configuration file in
* {@link java.net.URI} format.
* @throws URISyntaxException if the format of the specified
* configLocationURI is incorrect
* @throws IOException if an error occurred reading the specified location
*/
- void setConfigLocationURI(String configLocation) throws URISyntaxException,
- IOException;
+ void setConfigLocationURI(String configLocation) throws URISyntaxException, IOException;
/**
* Returns the configuration text, which may be the contents of the
* configuration file or the text that was last set with a call to
* {@code setConfigText}. If reading a file, this method assumes the file's
* character encoding is UTF-8.
- *
+ *
* @return the configuration text
* @throws IOException if a problem occurred reading the contents of the
* config file.
@@ -106,7 +116,7 @@ public interface LoggerContextAdminMBean
* Returns the configuration text, which may be the contents of the
* configuration file or the text that was last set with a call to
* {@code setConfigText}.
- *
+ *
* @param charsetName the encoding to use to convert the file's bytes into
* the resulting string.
* @return the configuration text
@@ -119,7 +129,7 @@ public interface LoggerContextAdminMBean
* Sets the configuration text. This does not replace the contents of the
* configuration file, but <em>does</em> cause the instrumented
* {@code LoggerContext} to be reconfigured with the specified text.
- *
+ *
* @param configText the configuration text in XML or JSON format
* @param charsetName name of the {@code Charset} used to convert the
* specified configText to bytes
@@ -130,7 +140,7 @@ public interface LoggerContextAdminMBean
/**
* Returns the name of the Configuration of the instrumented LoggerContext.
- *
+ *
* @return the Configuration name
*/
String getConfigName();
@@ -138,7 +148,7 @@ public interface LoggerContextAdminMBean
/**
* Returns the class name of the {@code Configuration} of the instrumented
* LoggerContext.
- *
+ *
* @return the class name of the {@code Configuration}.
*/
String getConfigClassName();
@@ -146,7 +156,7 @@ public interface LoggerContextAdminMBean
/**
* Returns a string description of all Filters configured in the
* {@code Configuration} of the instrumented LoggerContext.
- *
+ *
* @return a string description of all Filters configured
*/
String getConfigFilter();
@@ -154,7 +164,7 @@ public interface LoggerContextAdminMBean
/**
* Returns the class name of the object that is monitoring the configuration
* file for modifications.
- *
+ *
* @return the class name of the object that is monitoring the configuration
* file for modifications
*/
@@ -162,7 +172,7 @@ public interface LoggerContextAdminMBean
/**
* Returns a map with configured properties.
- *
+ *
* @return a map with configured properties.
*/
Map<String, String> getConfigProperties();
Modified: logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/Client.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/Client.java?rev=1565741&r1=1565740&r2=1565741&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/Client.java (original)
+++ logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/Client.java Fri Feb 7 17:49:34 2014
@@ -40,6 +40,7 @@ import org.apache.logging.log4j.core.jmx
public class Client {
private JMXConnector connector;
private final MBeanServerConnection connection;
+
/**
* Constructs a new {@code Client} object and creates proxies for all known
* remote MBeans.
@@ -93,14 +94,18 @@ public class Client {
List<LoggerContextAdminMBean> result = new ArrayList<LoggerContextAdminMBean>();
final Set<ObjectName> contextNames = find(LoggerContextAdminMBean.PATTERN);
for (final ObjectName contextName : contextNames) {
- final LoggerContextAdminMBean ctx = JMX.newMBeanProxy(connection, //
- contextName, //
- LoggerContextAdminMBean.class, false);
- result.add(ctx);
+ result.add(getLoggerContextAdmin(contextName));
}
return result;
}
+ public LoggerContextAdminMBean getLoggerContextAdmin(ObjectName name) {
+ final LoggerContextAdminMBean ctx = JMX.newMBeanProxy(connection, //
+ name, //
+ LoggerContextAdminMBean.class, false);
+ return ctx;
+ }
+
/**
* Closes the client connection to its server. Any ongoing or new requests
* to the MBeanServerConnection will fail.
@@ -149,4 +154,39 @@ public class Client {
StatusLoggerAdminMBean.class, true); // notificationBroadcaster
return proxy;
}
+
+ /**
+ * Returns {@code true} if the specified {@code ObjectName} is for a
+ * {@code LoggerContextAdminMBean}, {@code false} otherwise.
+ *
+ * @param mbeanName the {@code ObjectName} to check.
+ * @return {@code true} if the specified {@code ObjectName} is for a
+ * {@code LoggerContextAdminMBean}, {@code false} otherwise
+ */
+ public boolean isLoggerContext(ObjectName mbeanName) {
+ return Server.DOMAIN.equals(mbeanName.getDomain()) //
+ && mbeanName.getKeyPropertyList().containsKey("type") //
+ && mbeanName.getKeyPropertyList().size() == 1;
+ }
+
+ /**
+ * Returns the {@code ObjectName} of the {@code StatusLoggerAdminMBean}
+ * associated with the specified {@code LoggerContextAdminMBean}.
+ *
+ * @param loggerContextObjName the {@code ObjectName} of a
+ * {@code LoggerContextAdminMBean}
+ * @return {@code ObjectName} of the {@code StatusLoggerAdminMBean}
+ */
+ public ObjectName getStatusLoggerObjectName(ObjectName loggerContextObjName) {
+ if (!isLoggerContext(loggerContextObjName)) {
+ throw new IllegalArgumentException("Not a LoggerContext: " + loggerContextObjName);
+ }
+ final String cxtName = loggerContextObjName.getKeyProperty("type");
+ final String name = String.format(StatusLoggerAdminMBean.PATTERN, cxtName);
+ try {
+ return new ObjectName(name);
+ } catch (MalformedObjectNameException ex) {
+ throw new IllegalStateException(name, ex);
+ }
+ }
}
Modified: logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/ClientGUI.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/ClientGUI.java?rev=1565741&r1=1565740&r2=1565741&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/ClientGUI.java (original)
+++ logging/log4j/log4j2/trunk/log4j-jmx-gui/src/main/java/org/apache/logging/log4j/jmx/gui/ClientGUI.java Fri Feb 7 17:49:34 2014
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.jmx.gui
import java.awt.BorderLayout;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.io.IOException;
@@ -28,6 +29,7 @@ import java.util.Map;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
+import javax.management.ListenerNotFoundException;
import javax.management.MBeanServerDelegate;
import javax.management.MBeanServerNotification;
import javax.management.MalformedObjectNameException;
@@ -68,7 +70,8 @@ import org.apache.logging.log4j.core.jmx
public class ClientGUI extends JPanel implements NotificationListener {
private static final long serialVersionUID = -253621277232291174L;
private final Client client;
- private Map<String, JTextArea> statusLogTextAreaMap = new HashMap<String, JTextArea>();
+ private Map<ObjectName, Component> contextObjNameToTabbedPaneMap = new HashMap<ObjectName, Component>();
+ private Map<ObjectName, JTextArea> statusLogTextAreaMap = new HashMap<ObjectName, JTextArea>();
private JTabbedPane tabbedPaneContexts;
public ClientGUI(final Client client) throws IOException, JMException {
@@ -80,7 +83,7 @@ public class ClientGUI extends JPanel im
ObjectName addRemoveNotifs = MBeanServerDelegate.DELEGATE_NAME;
NotificationFilterSupport filter = new NotificationFilterSupport();
filter.enableType(Server.DOMAIN); // only interested in Log4J2 MBeans
- client.getConnection().addNotificationListener(addRemoveNotifs, this, filter, null);
+ client.getConnection().addNotificationListener(addRemoveNotifs, this, null, null);
}
private void createWidgets() {
@@ -90,27 +93,46 @@ public class ClientGUI extends JPanel im
}
private void populateWidgets() throws IOException, JMException {
-
for (final LoggerContextAdminMBean ctx : client.getLoggerContextAdmins()) {
- JTabbedPane contextTabs = new JTabbedPane();
- tabbedPaneContexts.addTab("LoggerContext: " + ctx.getName(), contextTabs);
+ addWidgetForLoggerContext(ctx);
+ }
+ }
- String contextName = ctx.getName();
- StatusLoggerAdminMBean status = client.getStatusLoggerAdmin(contextName);
- if (status != null) {
- JTextArea text = createTextArea();
- final String[] messages = status.getStatusDataHistory();
- for (final String message : messages) {
- text.append(message + "\n");
- }
- statusLogTextAreaMap.put(status.getContextName(), text);
- registerListeners(status);
- JScrollPane scroll = scroll(text);
- contextTabs.addTab("StatusLogger", scroll);
+ private void addWidgetForLoggerContext(final LoggerContextAdminMBean ctx) throws MalformedObjectNameException,
+ IOException, InstanceNotFoundException {
+ JTabbedPane contextTabs = new JTabbedPane();
+ contextObjNameToTabbedPaneMap.put(ctx.getObjectName(), contextTabs);
+ tabbedPaneContexts.addTab("LoggerContext: " + ctx.getName(), contextTabs);
+
+ String contextName = ctx.getName();
+ StatusLoggerAdminMBean status = client.getStatusLoggerAdmin(contextName);
+ if (status != null) {
+ JTextArea text = createTextArea();
+ final String[] messages = status.getStatusDataHistory();
+ for (final String message : messages) {
+ text.append(message + "\n");
}
+ statusLogTextAreaMap.put(ctx.getObjectName(), text);
+ registerListeners(status);
+ JScrollPane scroll = scroll(text);
+ contextTabs.addTab("StatusLogger", scroll);
+ }
- final ClientEditConfigPanel editor = new ClientEditConfigPanel(ctx);
- contextTabs.addTab("Configuration", editor);
+ final ClientEditConfigPanel editor = new ClientEditConfigPanel(ctx);
+ contextTabs.addTab("Configuration", editor);
+ }
+
+ private void removeWidgetForLoggerContext(ObjectName loggerContextObjName) throws JMException, IOException {
+ Component tab = contextObjNameToTabbedPaneMap.get(loggerContextObjName);
+ if (tab != null) {
+ tabbedPaneContexts.remove(tab);
+ }
+ statusLogTextAreaMap.remove(loggerContextObjName);
+ final ObjectName objName = client.getStatusLoggerObjectName(loggerContextObjName);
+ try {
+ // System.out.println("Remove listener for " + objName);
+ client.getConnection().removeNotificationListener(objName, this);
+ } catch (ListenerNotFoundException ignored) {
}
}
@@ -148,6 +170,7 @@ public class ClientGUI extends JPanel im
final NotificationFilterSupport filter = new NotificationFilterSupport();
filter.enableType(StatusLoggerAdminMBean.NOTIF_TYPE_MESSAGE);
final ObjectName objName = status.getObjectName();
+ // System.out.println("Add listener for " + objName);
client.getConnection().addNotificationListener(objName, this, filter, status.getContextName());
}
@@ -172,17 +195,43 @@ public class ClientGUI extends JPanel im
}
/**
- * @param mbeanName
+ * Called every time a Log4J2 MBean was registered in the MBean server.
+ *
+ * @param mbeanName ObjectName of the registered Log4J2 MBean
*/
private void onMBeanRegistered(ObjectName mbeanName) {
- // TODO update widgets if logger context was added
+ if (client.isLoggerContext(mbeanName)) {
+ try {
+ LoggerContextAdminMBean ctx = client.getLoggerContextAdmin(mbeanName);
+ addWidgetForLoggerContext(ctx);
+ } catch (Exception ex) {
+ handle("Could not add tab for new MBean " + mbeanName, ex);
+ }
+ }
}
/**
- * @param mbeanName
+ * Called every time a Log4J2 MBean was unregistered from the MBean server.
+ *
+ * @param mbeanName ObjectName of the unregistered Log4J2 MBean
*/
private void onMBeanUnregistered(ObjectName mbeanName) {
- // TODO update widgets if logger context was removed
+ if (client.isLoggerContext(mbeanName)) {
+ try {
+ removeWidgetForLoggerContext(mbeanName);
+ } catch (Exception ex) {
+ handle("Could not remove tab for " + mbeanName, ex);
+ }
+ }
+ }
+
+ private void handle(String msg, Exception ex) {
+ System.err.println(msg);
+ ex.printStackTrace();
+
+ StringWriter sw = new StringWriter(1024);
+ ex.printStackTrace(new PrintWriter(sw));
+ JOptionPane.showMessageDialog(this, sw.toString(), msg, JOptionPane.ERROR_MESSAGE);
}
/**
Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1565741&r1=1565740&r2=1565741&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Fri Feb 7 17:49:34 2014
@@ -21,6 +21,12 @@
</properties>
<body>
<release version="2.0-RC1" date="2014-MM-DD" description="Bug fixes and enhancements">
+ <action issue="LOG4J2-530" dev="rpopma" type="add">
+ JMX Client GUI should dynamically update when LoggerContext MBeans are registered/unregistered in MBean server.
+ </action>
+ <action issue="LOG4J2-500" dev="rpopma" type="fix">
+ Unloading one webapp unloads JMX MBeans for all webapps.
+ </action>
<action issue="LOG4J2-511" dev="rpopma" type="fix" due-to="James Pretorius">
Stop AsyncLoggerConfig Disruptor thread(s), then AsyncAppender thread(s) first
before stopping other appenders.