You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2013/07/21 01:18:23 UTC

svn commit: r1505238 - in /logging/log4j/log4j2/trunk: core/src/main/java/org/apache/logging/log4j/core/ core/src/main/java/org/apache/logging/log4j/core/config/ core/src/test/java/org/apache/logging/log4j/core/ core/src/test/resources/ src/changes/ sr...

Author: rgoers
Date: Sat Jul 20 23:18:23 2013
New Revision: 1505238

URL: http://svn.apache.org/r1505238
Log:
LOG4J2-318 - Allow shutdown hook to be disabled in the configuration

Added:
    logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/ShutdownDisabledTest.java
      - copied, changed from r1505096, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java
    logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test3.xml
      - copied, changed from r1505096, logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test2.xml
Modified:
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java
    logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml
    logging/log4j/log4j2/trunk/src/site/xdoc/manual/configuration.xml.vm

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java Sat Jul 20 23:18:23 2013
@@ -144,15 +144,20 @@ public class LoggerContext implements or
     public void start() {
         if (configLock.tryLock()) {
             try {
-                if (status == Status.INITIALIZED || status == Status.STOPPED) {
+                if ((status == Status.INITIALIZED || status == Status.STOPPED)) {
                     status = Status.STARTING;
                     reconfigure();
-                    shutdownThread = new ShutdownThread(this);
-                    try {
-                        Runtime.getRuntime().addShutdownHook(shutdownThread);
-                    } catch (final SecurityException se) {
-                        LOGGER.warn("Unable to register shutdown hook due to security restrictions");
-                        shutdownThread = null;
+                    if (config.isShutdownHookEnabled()) {
+                        shutdownThread = new ShutdownThread(this);
+                        try {
+                            Runtime.getRuntime().addShutdownHook(shutdownThread);
+                        } catch (final IllegalStateException ise) {
+                            LOGGER.warn("Unable to register shutdown hook due to JVM state");
+                            shutdownThread = null;
+                        } catch (final SecurityException se) {
+                            LOGGER.warn("Unable to register shutdown hook due to security restrictions");
+                            shutdownThread = null;
+                        }
                     }
                     status = Status.STARTED;
                 }
@@ -169,10 +174,13 @@ public class LoggerContext implements or
     public void start(final Configuration config) {
         if (configLock.tryLock()) {
             try {
-                if (status == Status.INITIALIZED || status == Status.STOPPED) {
+                if ((status == Status.INITIALIZED || status == Status.STOPPED) && config.isShutdownHookEnabled() ) {
                     shutdownThread = new ShutdownThread(this);
                     try {
                         Runtime.getRuntime().addShutdownHook(shutdownThread);
+                    } catch (final IllegalStateException ise) {
+                        LOGGER.warn("Unable to register shutdown hook due to JVM state");
+                        shutdownThread = null;
                     } catch (final SecurityException se) {
                         LOGGER.warn("Unable to register shutdown hook due to security restrictions");
                         shutdownThread = null;

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/BaseConfiguration.java Sat Jul 20 23:18:23 2013
@@ -86,6 +86,11 @@ public class BaseConfiguration extends A
      */
     protected Advertiser advertiser = new DefaultAdvertiser();
 
+    /**
+     *
+     */
+    protected boolean isShutdownHookEnabled = true;
+
     private String name;
 
     private ConcurrentMap<String, Appender<?>> appenders = new ConcurrentHashMap<String, Appender<?>>();
@@ -150,6 +155,10 @@ public class BaseConfiguration extends A
         stopFilter();
     }
 
+    public boolean isShutdownHookEnabled() {
+        return isShutdownHookEnabled;
+    }
+
     protected void setup() {
     }
 

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java Sat Jul 20 23:18:23 2013
@@ -81,10 +81,12 @@ public interface Configuration extends F
     void addComponent(String name, Object object);
 
     void setConfigurationMonitor(ConfigurationMonitor monitor);
-    
+
     ConfigurationMonitor getConfigurationMonitor();
-    
+
     void setAdvertiser(Advertiser advertiser);
-    
+
     Advertiser getAdvertiser();
+
+    boolean isShutdownHookEnabled();
 }

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/JSONConfiguration.java Sat Jul 20 23:18:23 2013
@@ -110,6 +110,9 @@ public class JSONConfiguration extends B
                             }
                         }
                     }
+                } else if ("shutdownHook".equalsIgnoreCase(entry.getKey())) {
+                    String hook = getSubst().replace(entry.getValue());
+                    isShutdownHookEnabled = !hook.equalsIgnoreCase("disable");
                 } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
                     verbose = Boolean.parseBoolean(getSubst().replace(entry.getValue()));
                 } else if ("packages".equalsIgnoreCase(entry.getKey())) {

Modified: logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java (original)
+++ logging/log4j/log4j2/trunk/core/src/main/java/org/apache/logging/log4j/core/config/XMLConfiguration.java Sat Jul 20 23:18:23 2013
@@ -116,7 +116,7 @@ public class XMLConfiguration extends Ba
                         messages.add("Invalid status specified: " + entry.getValue() + ". Defaulting to " + status);
                     }
                 } else if ("dest".equalsIgnoreCase(entry.getKey())) {
-                    final String dest = entry.getValue();
+                    final String dest = getSubst().replace(entry.getValue());
                     if (dest != null) {
                         if (dest.equalsIgnoreCase("err")) {
                             stream = System.err;
@@ -130,6 +130,9 @@ public class XMLConfiguration extends Ba
                             }
                         }
                     }
+                } else if ("shutdownHook".equalsIgnoreCase(entry.getKey())) {
+                    String hook = getSubst().replace(entry.getValue());
+                    isShutdownHookEnabled = !hook.equalsIgnoreCase("disable");
                 } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
                     verbose = Boolean.parseBoolean(getSubst().replace(entry.getValue()));
                 } else if ("packages".equalsIgnoreCase(getSubst().replace(entry.getKey()))) {

Copied: logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/ShutdownDisabledTest.java (from r1505096, logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/ShutdownDisabledTest.java?p2=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/ShutdownDisabledTest.java&p1=logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java&r1=1505096&r2=1505238&rev=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/LoggerTest.java (original)
+++ logging/log4j/log4j2/trunk/core/src/test/java/org/apache/logging/log4j/core/ShutdownDisabledTest.java Sat Jul 20 23:18:23 2013
@@ -45,13 +45,11 @@ import static org.junit.Assert.*;
 /**
  *
  */
-public class LoggerTest {
+public class ShutdownDisabledTest {
 
-    private static final String CONFIG = "log4j-test2.xml";
+    private static final String CONFIG = "log4j-test3.xml";
     private static Configuration config;
     private static ListAppender<LogEvent> app;
-    private static ListAppender<String> host;
-    private static ListAppender<String> noThrown;
     private static LoggerContext ctx;
 
     @BeforeClass
@@ -71,196 +69,13 @@ public class LoggerTest {
     @SuppressWarnings("unchecked")
     public void before() {
         config = ctx.getConfiguration();
-        for (final Map.Entry<String, Appender<?>> entry : config.getAppenders().entrySet()) {
-            if (entry.getKey().equals("List")) {
-                app = (ListAppender<LogEvent>) entry.getValue();
-            } else if (entry.getKey().equals("HostTest")) {
-                host = (ListAppender<String>) entry.getValue();
-            } else if (entry.getKey().equals("NoThrowable")) {
-                noThrown = (ListAppender<String>) entry.getValue();
-            }
-        }
-        assertNotNull("No Appender", app);
-        assertNotNull("No Host Appender", host);
-        app.clear();
-        host.clear();
-    }
-
-
-    org.apache.logging.log4j.Logger logger = LogManager.getLogger("LoggerTest");
-
-    @Test
-    public void basicFlow() {
-        logger.entry();
-        logger.exit();
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 2, actual " + events.size(), events.size() == 2);
-        app.clear();
-    }
-
-    @Test
-    public void simpleFlow() {
-        logger.entry(CONFIG);
-        logger.exit(0);
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 2, actual " + events.size(), events.size() == 2);
-        app.clear();
-    }
-
-    @Test
-    public void throwing() {
-        logger.throwing(new IllegalArgumentException("Test Exception"));
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        app.clear();
-    }
-
-    @Test
-    public void catching() {
-        try {
-            throw new NullPointerException();
-        } catch (final Exception e) {
-            logger.catching(e);
-        }
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        app.clear();
-    }
-
-    @Test
-    public void debug() {
-        logger.debug("Debug message");
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        app.clear();
-    }
-
-    @Test
-    public void getLogger_String_MessageFactoryMismatch() {
-        final Logger testLogger = testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatch",
-                StringFormatterMessageFactory.INSTANCE, ParameterizedMessageFactory.INSTANCE);
-        testLogger.debug("%,d", Integer.MAX_VALUE);
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        assertEquals(String.format("%,d", Integer.MAX_VALUE), events.get(0).getMessage().getFormattedMessage());
     }
 
     @Test
-    public void getLogger_String_MessageFactoryMismatchNull() {
-        final Logger testLogger =  testMessageFactoryMismatch("getLogger_String_MessageFactoryMismatchNull", StringFormatterMessageFactory.INSTANCE, null);
-        testLogger.debug("%,d", Integer.MAX_VALUE);
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        assertEquals(String.format("%,d", Integer.MAX_VALUE), events.get(0).getMessage().getFormattedMessage());
+    public void testShutdownFlag() {
+        assertNotNull("No configuration", config);
+        assertFalse("Shutdown hook is enabled", config.isShutdownHookEnabled());
     }
 
-    private Logger testMessageFactoryMismatch(final String name, final MessageFactory messageFactory1, final MessageFactory messageFactory2) {
-        final Logger testLogger = (Logger) LogManager.getLogger(name, messageFactory1);
-        assertNotNull(testLogger);
-        assertEquals(messageFactory1, testLogger.getMessageFactory());
-        final Logger testLogger2 = (Logger) LogManager.getLogger(name, messageFactory2);
-        assertEquals(messageFactory1, testLogger2.getMessageFactory());
-        return testLogger;
-    }
-
-    @Test
-    public void debugObject() {
-        logger.debug(new Date());
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        app.clear();
-    }
-
-    @Test
-    public void debugWithParms() {
-        logger.debug("Hello, {}", "World");
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        app.clear();
-    }
-
-    @Test
-    public void testHostname() {
-        final org.apache.logging.log4j.Logger testLogger = LogManager.getLogger("org.apache.logging.log4j.hosttest");
-        testLogger.debug("Hello, {}", "World");
-        final List<String> msgs = host.getMessages();
-        assertTrue("Incorrect number of events. Expected 1, actual " + msgs.size(), msgs.size() == 1);
-        final String expected = NetUtils.getLocalHostname() + Constants.LINE_SEP;
-        assertTrue("Incorrect hostname - expected " + expected + " actual - " + msgs.get(0),
-            msgs.get(0).endsWith(expected));
-
-    }
-
-    @Test
-    public void testImpliedThrowable() {
-        final org.apache.logging.log4j.Logger testLogger = LogManager.getLogger("org.apache.logging.log4j.hosttest");
-        testLogger.debug("This is a test", new Throwable("Testing"));
-        final List<String> msgs = host.getMessages();
-        assertTrue("Incorrect number of messages. Expected 1, actual " + msgs.size(), msgs.size() == 1);
-        final String expected = "java.lang.Throwable: Testing";
-        assertTrue("Incorrect message data", msgs.get(0).contains(expected));
-    }
-
-
-    @Test
-    public void testSuppressedThrowable() {
-        final org.apache.logging.log4j.Logger testLogger = LogManager.getLogger("org.apache.logging.log4j.nothrown");
-        testLogger.debug("This is a test", new Throwable("Testing"));
-        final List<String> msgs = noThrown.getMessages();
-        assertTrue("Incorrect number of messages. Expected 1, actual " + msgs.size(), msgs.size() == 1);
-        final String suppressed = "java.lang.Throwable: Testing";
-        assertTrue("Incorrect message data", !msgs.get(0).contains(suppressed));
-    }
-
-
-    @Test
-    public void mdc() {
-        ThreadContext.put("TestYear", "2010");
-        logger.debug("Debug message");
-        ThreadContext.clear();
-        logger.debug("Debug message");
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 2, actual " + events.size(), events.size() == 2);
-        app.clear();
-    }
-
-    @Test
-    public void structuredData() {
-        ThreadContext.put("loginId", "JohnDoe");
-        ThreadContext.put("ipAddress", "192.168.0.120");
-        ThreadContext.put("locale", Locale.US.getDisplayName());
-        final StructuredDataMessage msg = new StructuredDataMessage("Audit@18060", "Transfer Complete", "Transfer");
-        msg.put("ToAccount", "123456");
-        msg.put("FromAccount", "123457");
-        msg.put("Amount", "200.00");
-        logger.info(MarkerManager.getMarker("EVENT"), msg);
-        ThreadContext.clear();
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-        app.clear();
-    }
-
-    @Test
-    public void testReconfiguration() throws Exception {
-        final File file = new File("target/test-classes/" + CONFIG);
-        final long orig = file.lastModified();
-        final long newTime = orig + 10000;
-        file.setLastModified(newTime);
-        Thread.sleep(6000);
-        for (int i = 0; i < 17; ++i) {
-            logger.debug("Reconfigure");
-        }
-        final Configuration cfg = ctx.getConfiguration();
-        assertNotNull("No configuration", cfg);
-        assertTrue("Reconfiguration failed", cfg != config);
-    }
-
-    @Test
-    public void testAdditivity() throws Exception {
-        final Logger localLogger = (Logger) LogManager.getLogger("org.apache.test");
-        localLogger.error("Test parent additivity");
-        final List<LogEvent> events = app.getEvents();
-        assertTrue("Incorrect number of events. Expected 1, actual " + events.size(), events.size() == 1);
-    }
 }
 

Copied: logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test3.xml (from r1505096, logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test2.xml)
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test3.xml?p2=logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test3.xml&p1=logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test2.xml&r1=1505096&r2=1505238&rev=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test2.xml (original)
+++ logging/log4j/log4j2/trunk/core/src/test/resources/log4j-test3.xml Sat Jul 20 23:18:23 2013
@@ -16,64 +16,21 @@
  limitations under the License.
 
 -->
-<configuration status="ERROR" name="XMLConfigTest" monitorInterval="5" packages="org.apache.logging.log4j.test">
-  <properties>
-    <property name="filename">target/test.log</property>
-  </properties>
-  <ThresholdFilter level="trace"/>
-
+<configuration status="ERROR" name="XMLConfigTest" monitorInterval="5" packages="org.apache.logging.log4j.test"
+    shutdownHook="disable">
   <appenders>
     <Console name="STDOUT">
       <PatternLayout pattern="%m MDC%X%n"/>
-      <filters>
-        <MarkerFilter marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
-        <MarkerFilter marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
-      </filters>
-    </Console>
-    <Console name="FLOW">
-      <PatternLayout pattern="%C{1}.%M %m %ex%n"/>
-      <filters>
-        <MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
-        <MarkerFilter marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
-      </filters>
     </Console>
-    <File name="File" fileName="${filename}">
-      <PatternLayout>
-        <pattern>%d %p %C{1.} [%t] %m%n</pattern>
-      </PatternLayout>
-    </File>
     <List name="List">
     </List>
-    <List name="HostTest">
-      <PatternLayout pattern="%d %p %C{1.} [%t] %m ${hostName}%n"/>
-    </List>
-    <List name="NoThrowable">
-      <PatternLayout pattern="%d %p %C{1.} [%t] %m%n%ex{0}"/>
-    </List>
   </appenders>
 
   <loggers>
     <logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
-      <ThreadContextMapFilter>
-        <KeyValuePair key="test" value="123"/>
-      </ThreadContextMapFilter>
       <appender-ref ref="STDOUT"/>
     </logger>>
 
-    <logger name="org.apache.logging.log4j.hosttest" level="debug" additivity="false">
-      <appender-ref ref="HostTest"/>
-    </logger>
-
-
-    <logger name="org.apache.logging.log4j.nothrown" level="debug" additivity="false">
-      <appender-ref ref="NoThrowable"/>
-    </logger>
-
-
-    <logger name="org.apache.logging.log4j.test2" level="debug" additivity="false">
-      <appender-ref ref="File"/>
-    </logger>
-    <logger name="org" level="error" additivity="true"/>
     <root level="trace">
       <appender-ref ref="List"/>
     </root>

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sat Jul 20 23:18:23 2013
@@ -21,6 +21,9 @@
   </properties>
   <body>
     <release version="2.0-beta9" date="soon, very soon" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-318" dev="rgoers" type="update">
+        Allow shutdown hook to be disabled in the configuration.
+      </action>
       <action issue="LOG4J2-166" dev="rgoers" type="fix">
         RoutingAppender's default Route can now be an appender reference.
       </action>

Modified: logging/log4j/log4j2/trunk/src/site/xdoc/manual/configuration.xml.vm
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/site/xdoc/manual/configuration.xml.vm?rev=1505238&r1=1505237&r2=1505238&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/site/xdoc/manual/configuration.xml.vm (original)
+++ logging/log4j/log4j2/trunk/src/site/xdoc/manual/configuration.xml.vm Sat Jul 20 23:18:23 2013
@@ -326,6 +326,7 @@ public class Bar {
                 <td>dest</td>
                 <td>Either "err", which will send output to stderr, or a file path or URL.</td>
               </tr>
+
               <tr>
                 <td>monitorInterval</td>
                 <td>The minimum amount of time, in seconds, that must elapse before the file configuration
@@ -347,6 +348,11 @@ public class Bar {
                   will take place.</td>
               </tr>
               <tr>
+                 <td>shutdownHook</td>
+                 <td>Specifies whether or not Log4j should automatically shutdown when the JVM shuts down. The
+                 shutdown hook is enabled by default but may be disabled by setting this attribute to "disable"</td>
+              </tr>
+              <tr>
                 <td>status</td>
                 <td>The level of internal Log4j events that should be logged to the console.</td>
               </tr>