You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by mi...@apache.org on 2016/10/03 16:54:43 UTC

logging-log4j2 git commit: LOG4J2-1623 Configurable JVM shutdown hook timeout

Repository: logging-log4j2
Updated Branches:
  refs/heads/LOG4J2-1623 [created] 705e27253


LOG4J2-1623  Configurable JVM shutdown hook timeout


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/705e2725
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/705e2725
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/705e2725

Branch: refs/heads/LOG4J2-1623
Commit: 705e27253ca14cdf0e50039cada041065e308aee
Parents: 3176c96
Author: Mikael St�ldal <mi...@magine.com>
Authored: Mon Oct 3 18:54:27 2016 +0200
Committer: Mikael St�ldal <mi...@magine.com>
Committed: Mon Oct 3 18:54:27 2016 +0200

----------------------------------------------------------------------
 .../logging/log4j/core/LoggerContext.java       |  9 ++--
 .../core/config/AbstractConfiguration.java      | 10 +++++
 .../log4j/core/config/Configuration.java        |  2 +
 .../builder/api/ConfigurationBuilder.java       |  7 ++++
 .../config/builder/impl/BuiltConfiguration.java |  4 ++
 .../impl/DefaultConfigurationBuilder.java       | 14 +++++++
 .../composite/CompositeConfiguration.java       |  2 +
 .../core/config/json/JsonConfiguration.java     |  9 ++--
 .../PropertiesConfigurationBuilder.java         |  3 ++
 .../log4j/core/config/xml/XmlConfiguration.java |  3 +-
 .../core/ShutdownTimeoutConfigurationTest.java  | 44 ++++++++++++++++++++
 .../builder/ConfigurationBuilderTest.java       |  5 ++-
 .../resources/log4j-test-shutdownTimeout.xml    | 38 +++++++++++++++++
 src/changes/changes.xml                         |  5 +++
 src/site/xdoc/manual/configuration.xml.vm       |  8 +++-
 15 files changed, 151 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 7e13963..c964965 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -16,8 +16,6 @@
  */
 package org.apache.logging.log4j.core;
 
-import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
-
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
@@ -38,7 +36,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationListener;
-import org.apache.logging.log4j.core.config.ConfigurationSource; // SUPPRESS CHECKSTYLE
+import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.NullConfiguration;
 import org.apache.logging.log4j.core.config.Reconfigurable;
@@ -56,6 +54,8 @@ import org.apache.logging.log4j.spi.LoggerRegistry;
 import org.apache.logging.log4j.spi.Terminable;
 import org.apache.logging.log4j.util.PropertiesUtil;
 
+import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
+
 /**
  * The LoggerContext is the anchor for the logging system. It maintains a list of all the loggers requested by
  * applications and a reference to the Configuration. The Configuration will contain the configured loggers, appenders,
@@ -265,6 +265,7 @@ public class LoggerContext extends AbstractLifeCycle
             if (factory instanceof ShutdownCallbackRegistry) {
                 LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Shutdown hook enabled. Registering a new one.");
                 try {
+                    final long shutdownTimeoutMillis = this.configuration.getShutdownTimeoutMillis();
                     this.shutdownCallback = ((ShutdownCallbackRegistry) factory).addShutdownCallback(new Runnable() {
                         @Override
                         public void run() {
@@ -272,7 +273,7 @@ public class LoggerContext extends AbstractLifeCycle
                             final LoggerContext context = LoggerContext.this;
                             LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Stopping LoggerContext[name={}, {}]",
                                     context.getName(), context);
-                            context.stop();
+                            context.stop(shutdownTimeoutMillis, TimeUnit.MILLISECONDS);
                         }
 
                         @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
index c740b8c..3a6a58e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
@@ -102,6 +102,11 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
     protected boolean isShutdownHookEnabled = true;
 
     /**
+     * Shutdown timeout in milliseconds.
+     */
+    protected long shutdownTimeoutMillis = 0;
+
+    /**
      * The Script manager.
      */
     protected ScriptManager scriptManager;
@@ -395,6 +400,11 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
         return isShutdownHookEnabled;
     }
 
+    @Override
+    public long getShutdownTimeoutMillis() {
+        return shutdownTimeoutMillis;
+    }
+
     public void setup() {
         // default does nothing, subclasses do work.
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
index 1a55b48..95e6edc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
@@ -128,6 +128,8 @@ public interface Configuration extends Filterable {
 
     boolean isShutdownHookEnabled();
 
+    long getShutdownTimeoutMillis();
+
     ConfigurationScheduler getScheduler();
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
index 4dc9b69..b115651 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.config.builder.api;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
@@ -367,6 +368,12 @@ public interface ConfigurationBuilder<T extends Configuration> extends Builder<T
      */
     ConfigurationBuilder<T> setShutdownHook(String flag);
 
+    /**
+     * Specifies how long time appenders and other plugins will get to shutdown when the JVM shuts down.
+     * Default is zero. (Not used if {@link #setShutdownHook(String)} is set to "disable".)
+     * @return this builder instance.
+     */
+    ConfigurationBuilder<T> setShutdownTimeout(long timeout, TimeUnit timeUnit);
 
     /**
      * Sets the level of the StatusLogger.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
index aa7761c..c241dfb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
@@ -147,6 +147,10 @@ public class BuiltConfiguration extends AbstractConfiguration {
         isShutdownHookEnabled = !"disable".equalsIgnoreCase(flag);
     }
 
+    public void setShutdownTimeoutMillis(long shutdownTimeoutMillis) {
+        this.shutdownTimeoutMillis = shutdownTimeoutMillis;
+    }
+
     public void setMonitorInterval(final int intervalSeconds) {
         if (this instanceof Reconfigurable && intervalSeconds > 0) {
             final ConfigurationSource configSource = getConfigurationSource();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
index d8531d6..183094d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/builder/impl/DefaultConfigurationBuilder.java
@@ -22,6 +22,7 @@ import java.io.StringWriter;
 import java.lang.reflect.Constructor;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
@@ -71,6 +72,7 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
     private String destination;
     private String packages;
     private String shutdownFlag;
+    private long shutdownTimeoutMillis;
     private String advertiser;
     private LoggerContext loggerContext;
     private String name;
@@ -186,6 +188,9 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
             if (shutdownFlag != null) {
                 configuration.setShutdownHook(shutdownFlag);
             }
+            if (shutdownTimeoutMillis > 0) {
+                configuration.setShutdownTimeoutMillis(shutdownTimeoutMillis);
+            }
             if (advertiser != null) {
                 configuration.createAdvertiser(advertiser, source);
             }
@@ -249,6 +254,9 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
         if (shutdownFlag != null) {
             xmlWriter.writeAttribute("shutdownHook", shutdownFlag);
         }
+        if (shutdownTimeoutMillis > 0) {
+            xmlWriter.writeAttribute("shutdownTimeout", String.valueOf(shutdownTimeoutMillis));
+        }
         if (advertiser != null) {
             xmlWriter.writeAttribute("advertiser", advertiser);
         }
@@ -514,6 +522,12 @@ public class DefaultConfigurationBuilder<T extends BuiltConfiguration> implement
     }
 
     @Override
+    public ConfigurationBuilder<T> setShutdownTimeout(final long timeout, final TimeUnit timeUnit) {
+        this.shutdownTimeoutMillis = timeUnit.toMillis(timeout);
+        return this;
+    }
+
+    @Override
     public ConfigurationBuilder<T> setStatusLevel(final Level level) {
         this.level = level;
         return this;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index fa941d7..e38c62b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
@@ -87,6 +87,8 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
                 statusConfig.withDestination(value);
             } else if ("shutdownHook".equalsIgnoreCase(key)) {
                 isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+            } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                shutdownTimeoutMillis = Long.parseLong(value);
             } else if ("verbose".equalsIgnoreCase(key)) {
                 statusConfig.withVerbosity(value);
             } else if ("packages".equalsIgnoreCase(key)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
index 497496a..5b38dfb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfiguration.java
@@ -26,6 +26,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AbstractConfiguration;
 import org.apache.logging.log4j.core.config.Configuration;
@@ -40,10 +43,6 @@ import org.apache.logging.log4j.core.config.status.StatusConfiguration;
 import org.apache.logging.log4j.core.util.FileWatcher;
 import org.apache.logging.log4j.core.util.Patterns;
 
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
 /**
  * Creates a Node hierarchy from a JSON file.
  */
@@ -81,6 +80,8 @@ public class JsonConfiguration extends AbstractConfiguration implements Reconfig
                     statusConfig.withDestination(value);
                 } else if ("shutdownHook".equalsIgnoreCase(key)) {
                     isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+                } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                    shutdownTimeoutMillis = Long.parseLong(value);
                 } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
                     statusConfig.withVerbosity(value);
                 } else if ("packages".equalsIgnoreCase(key)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
index a4362b7..3d24a9b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/PropertiesConfigurationBuilder.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.config.properties;
 
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Appender;
@@ -54,6 +55,7 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory
     private static final String ADVERTISER_KEY = "advertiser";
     private static final String STATUS_KEY = "status";
     private static final String SHUTDOWN_HOOK = "shutdownHook";
+    private static final String SHUTDOWN_TIMEOUT = "shutdownTimeout";
     private static final String VERBOSE = "verbose";
     private static final String DEST = "dest";
     private static final String PACKAGES = "packages";
@@ -89,6 +91,7 @@ public class PropertiesConfigurationBuilder extends ConfigurationBuilderFactory
         builder
             .setStatusLevel(Level.toLevel(rootProperties.getProperty(STATUS_KEY), Level.ERROR))
             .setShutdownHook(rootProperties.getProperty(SHUTDOWN_HOOK))
+            .setShutdownTimeout(Long.parseLong(rootProperties.getProperty(SHUTDOWN_TIMEOUT, "0")), TimeUnit.MILLISECONDS)
             .setVerbosity(rootProperties.getProperty(VERBOSE))
             .setDestination(rootProperties.getProperty(DEST))
             .setPackages(rootProperties.getProperty(PACKAGES))

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
index 2608552..51f31d4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
@@ -24,7 +24,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -120,6 +119,8 @@ public class XmlConfiguration extends AbstractConfiguration implements Reconfigu
                     statusConfig.withDestination(value);
                 } else if ("shutdownHook".equalsIgnoreCase(key)) {
                     isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+                } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                    shutdownTimeoutMillis = Long.parseLong(value);
                 } else if ("verbose".equalsIgnoreCase(key)) {
                     statusConfig.withVerbosity(value);
                 } else if ("packages".equalsIgnoreCase(key)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/test/java/org/apache/logging/log4j/core/ShutdownTimeoutConfigurationTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/ShutdownTimeoutConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/ShutdownTimeoutConfigurationTest.java
new file mode 100644
index 0000000..5e0734c
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/ShutdownTimeoutConfigurationTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core;
+
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class ShutdownTimeoutConfigurationTest {
+
+    private static final String CONFIG = "log4j-test-shutdownTimeout.xml";
+
+    @ClassRule
+    public static LoggerContextRule context = new LoggerContextRule(CONFIG);
+
+    @Test
+    public void testShutdownFlag() {
+        final Configuration config = context.getConfiguration();
+        assertNotNull("No configuration", config);
+        assertEquals(5000, config.getShutdownTimeoutMillis());
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java
index 2d48605..431ac01 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.core.config.builder;
 
+import java.util.concurrent.TimeUnit;
+
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.appender.ConsoleAppender;
@@ -36,6 +38,7 @@ public class ConfigurationBuilderTest {
     private void addTestFixtures(final String name, final ConfigurationBuilder<BuiltConfiguration> builder) {
         builder.setConfigurationName(name);
         builder.setStatusLevel(Level.ERROR);
+        builder.setShutdownTimeout(5000, TimeUnit.MILLISECONDS);
         builder.add(builder.newScriptFile("target/test-classes/scripts/filter.groovy").addIsWatched(true));
         builder.add(builder.newFilter("ThresholdFilter", Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
                 .addAttribute("level", Level.DEBUG));
@@ -56,7 +59,7 @@ public class ConfigurationBuilderTest {
 
     private final static String expectedXml =
             "<?xml version='1.0' encoding='UTF-8'?>" + EOL +
-            "<Configuration name=\"config name\" status=\"ERROR\" packages=\"foo,bar\">" + EOL +
+            "<Configuration name=\"config name\" status=\"ERROR\" packages=\"foo,bar\" shutdownTimeout=\"5000\">" + EOL +
                 INDENT + "<Properties>" + EOL +
                 INDENT + INDENT + "<Property name=\"MyKey\">MyValue</Property>" + EOL +
                 INDENT + "</Properties>" + EOL +

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml b/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
new file mode 100644
index 0000000..19b25c9
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="OFF" name="XMLConfigTest" monitorInterval="5" shutdownTimeout="5000">
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m MDC%X%n"/>
+    </Console>
+    <List name="List">
+    </List>
+  </Appenders>
+
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
+      <AppenderRef ref="STDOUT"/>
+    </Logger>>
+
+    <Root level="trace">
+      <AppenderRef ref="List"/>
+    </Root>
+  </Loggers>
+
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index cd2f379..6bd144c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -23,6 +23,11 @@
     <title>Changes</title>
   </properties>
   <body>
+    <release version="2.7.1" date="2016-XX-XX" description="GA Release 2.7.1">
+      <action issue="LOG4J2-1623" dev="mikes" type="fix">
+        Configurable JVM shutdown hook timeout.
+      </action>
+    </release>
     <release version="2.7" date="2016-10-02" description="GA Release 2.7">
       <action issue="LOG4J2-1618" dev="rpopma" type="fix" due-to="Raman Gupta">
         Fixed ClassCastException when using JUL logging during shutdown.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/705e2725/src/site/xdoc/manual/configuration.xml.vm
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm
index 60419a4..acd41fd 100644
--- a/src/site/xdoc/manual/configuration.xml.vm
+++ b/src/site/xdoc/manual/configuration.xml.vm
@@ -408,6 +408,10 @@ public class Bar {
                  shutdown hook is enabled by default but may be disabled by setting this attribute to "disable"</td>
               </tr>
               <tr>
+                 <td>shutdownTimeout</td>
+                 <td>Specifies how many milliseconds appenders and other plugins will get to shutdown when the JVM shuts down.
+                 Default is zero. (Not used if <tt>shutdownHook</tt> is set to "disable".)</td>
+              <tr>
                 <td>status</td>
                 <td>The level of internal Log4j events that should be logged to the console.
                 Valid values for this attribute are "trace", "debug", "info", "warn", "error" and "fatal".
@@ -841,8 +845,8 @@ public class Bar {
             </p>
             <p>
               Properties configuration files support the advertiser, monitorInterval, name, packages, shutdownHook,
-              status, verbose, and dest attrbutes. See <a href="#ConfigurationSyntax">Configuration Syntax</a> for the
-              definitions of these attributes.
+              shutdownTimeout, status, verbose, and dest attrbutes. See <a href="#ConfigurationSyntax">Configuration Syntax</a>
+              for the definitions of these attributes.
             </p>
           <pre class="prettyprint linenums">
 status = error


Re: logging-log4j2 git commit: LOG4J2-1623 Configurable JVM shutdown hook timeout

Posted by Mikael Ståldal <mi...@magine.com>.
That might make sense, but I propose we do that separately since it's not
related to what I am working on.

On Mon, Oct 3, 2016 at 11:28 PM, Gary Gregory <ga...@gmail.com>
wrote:

> WRT:
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/composite/CompositeConfiguration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org
> /apache/logging/log4j/core/config/composite/CompositeConfiguration.java
> index fa941d7..e38c62b 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/composite/CompositeConfiguration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/composite/CompositeConfiguration.java
> @@ -87,6 +87,8 @@ public class CompositeConfiguration extends
> AbstractConfiguration implements Rec
>                  statusConfig.withDestination(value);
>              } else if ("shutdownHook".equalsIgnoreCase(key)) {
>                  isShutdownHookEnabled = !"disable".equalsIgnoreCase(va
> lue);
> +            } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
> +                shutdownTimeoutMillis = Long.parseLong(value);
>              } else if ("verbose".equalsIgnoreCase(key)) {
>                  statusConfig.withVerbosity(value);
>              } else if ("packages".equalsIgnoreCase(key)) {
>
> How about a switch on String instead of an old-school cascading if-else?
>
> Gary
>
> ---------- Forwarded message ----------
> From: <mi...@apache.org>
> Date: Mon, Oct 3, 2016 at 9:54 AM
> Subject: logging-log4j2 git commit: LOG4J2-1623 Configurable JVM shutdown
> hook timeout
> To: commits@logging.apache.org
>
>
> Repository: logging-log4j2
> Updated Branches:
>   refs/heads/LOG4J2-1623 [created] 705e27253
>
>
> LOG4J2-1623  Configurable JVM shutdown hook timeout
>
>
> Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
> Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit
> /705e2725
> Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/705e2725
> Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/705e2725
>
> Branch: refs/heads/LOG4J2-1623
> Commit: 705e27253ca14cdf0e50039cada041065e308aee
> Parents: 3176c96
> Author: Mikael Ståldal <mi...@magine.com>
> Authored: Mon Oct 3 18:54:27 2016 +0200
> Committer: Mikael Ståldal <mi...@magine.com>
> Committed: Mon Oct 3 18:54:27 2016 +0200
>
> ----------------------------------------------------------------------
>  .../logging/log4j/core/LoggerContext.java       |  9 ++--
>  .../core/config/AbstractConfiguration.java      | 10 +++++
>  .../log4j/core/config/Configuration.java        |  2 +
>  .../builder/api/ConfigurationBuilder.java       |  7 ++++
>  .../config/builder/impl/BuiltConfiguration.java |  4 ++
>  .../impl/DefaultConfigurationBuilder.java       | 14 +++++++
>  .../composite/CompositeConfiguration.java       |  2 +
>  .../core/config/json/JsonConfiguration.java     |  9 ++--
>  .../PropertiesConfigurationBuilder.java         |  3 ++
>  .../log4j/core/config/xml/XmlConfiguration.java |  3 +-
>  .../core/ShutdownTimeoutConfigurationTest.java  | 44 ++++++++++++++++++++
>  .../builder/ConfigurationBuilderTest.java       |  5 ++-
>  .../resources/log4j-test-shutdownTimeout.xml    | 38 +++++++++++++++++
>  src/changes/changes.xml                         |  5 +++
>  src/site/xdoc/manual/configuration.xml.vm       |  8 +++-
>  15 files changed, 151 insertions(+), 12 deletions(-)
> ----------------------------------------------------------------------
>
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/LoggerContext.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/Log
> gerContext.java
> index 7e13963..c964965 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/Log
> gerContext.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/Log
> gerContext.java
> @@ -16,8 +16,6 @@
>   */
>  package org.apache.logging.log4j.core;
>
> -import static org.apache.logging.log4j.core.
> util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
> -
>  import java.beans.PropertyChangeEvent;
>  import java.beans.PropertyChangeListener;
>  import java.io.File;
> @@ -38,7 +36,7 @@ import org.apache.logging.log4j.LogManager;
>  import org.apache.logging.log4j.core.config.Configuration;
>  import org.apache.logging.log4j.core.config.ConfigurationFactory;
>  import org.apache.logging.log4j.core.config.ConfigurationListener;
> -import org.apache.logging.log4j.core.config.ConfigurationSource; //
> SUPPRESS CHECKSTYLE
> +import org.apache.logging.log4j.core.config.ConfigurationSource;
>  import org.apache.logging.log4j.core.config.DefaultConfiguration;
>  import org.apache.logging.log4j.core.config.NullConfiguration;
>  import org.apache.logging.log4j.core.config.Reconfigurable;
> @@ -56,6 +54,8 @@ import org.apache.logging.log4j.spi.LoggerRegistry;
>  import org.apache.logging.log4j.spi.Terminable;
>  import org.apache.logging.log4j.util.PropertiesUtil;
>
> +import static org.apache.logging.log4j.core.
> util.ShutdownCallbackRegistry.SHUTDOWN_HOOK_MARKER;
> +
>  /**
>   * The LoggerContext is the anchor for the logging system. It maintains a
> list of all the loggers requested by
>   * applications and a reference to the Configuration. The Configuration
> will contain the configured loggers, appenders,
> @@ -265,6 +265,7 @@ public class LoggerContext extends AbstractLifeCycle
>              if (factory instanceof ShutdownCallbackRegistry) {
>                  LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Shutdown hook
> enabled. Registering a new one.");
>                  try {
> +                    final long shutdownTimeoutMillis =
> this.configuration.getShutdownTimeoutMillis();
>                      this.shutdownCallback = ((ShutdownCallbackRegistry)
> factory).addShutdownCallback(new Runnable() {
>                          @Override
>                          public void run() {
> @@ -272,7 +273,7 @@ public class LoggerContext extends AbstractLifeCycle
>                              final LoggerContext context =
> LoggerContext.this;
>                              LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Stopping
> LoggerContext[name={}, {}]",
>                                      context.getName(), context);
> -                            context.stop();
> +                            context.stop(shutdownTimeoutMillis,
> TimeUnit.MILLISECONDS);
>                          }
>
>                          @Override
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/AbstractConfiguration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/AbstractConfiguration.java
> index c740b8c..3a6a58e 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/AbstractConfiguration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/AbstractConfiguration.java
> @@ -102,6 +102,11 @@ public abstract class AbstractConfiguration extends
> AbstractFilterable implement
>      protected boolean isShutdownHookEnabled = true;
>
>      /**
> +     * Shutdown timeout in milliseconds.
> +     */
> +    protected long shutdownTimeoutMillis = 0;
> +
> +    /**
>       * The Script manager.
>       */
>      protected ScriptManager scriptManager;
> @@ -395,6 +400,11 @@ public abstract class AbstractConfiguration extends
> AbstractFilterable implement
>          return isShutdownHookEnabled;
>      }
>
> +    @Override
> +    public long getShutdownTimeoutMillis() {
> +        return shutdownTimeoutMillis;
> +    }
> +
>      public void setup() {
>          // default does nothing, subclasses do work.
>      }
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/Configuration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/Configuration.java
> index 1a55b48..95e6edc 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/Configuration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/Configuration.java
> @@ -128,6 +128,8 @@ public interface Configuration extends Filterable {
>
>      boolean isShutdownHookEnabled();
>
> +    long getShutdownTimeoutMillis();
> +
>      ConfigurationScheduler getScheduler();
>
>      /**
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/builder/api/ConfigurationBuilder.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/api/ConfigurationBuilder.java b/log4j-core/src/main/java/org
> /apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
> index 4dc9b69..b115651 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/api/ConfigurationBuilder.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/api/ConfigurationBuilder.java
> @@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.
> config.builder.api;
>
>  import java.io.IOException;
>  import java.io.OutputStream;
> +import java.util.concurrent.TimeUnit;
>
>  import org.apache.logging.log4j.Level;
>  import org.apache.logging.log4j.core.Filter;
> @@ -367,6 +368,12 @@ public interface ConfigurationBuilder<T extends
> Configuration> extends Builder<T
>       */
>      ConfigurationBuilder<T> setShutdownHook(String flag);
>
> +    /**
> +     * Specifies how long time appenders and other plugins will get to
> shutdown when the JVM shuts down.
> +     * Default is zero. (Not used if {@link #setShutdownHook(String)} is
> set to "disable".)
> +     * @return this builder instance.
> +     */
> +    ConfigurationBuilder<T> setShutdownTimeout(long timeout, TimeUnit
> timeUnit);
>
>      /**
>       * Sets the level of the StatusLogger.
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/builder/impl/BuiltConfiguration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/BuiltConfiguration.java b/log4j-core/src/main/java/org
> /apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
> index aa7761c..c241dfb 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/BuiltConfiguration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/BuiltConfiguration.java
> @@ -147,6 +147,10 @@ public class BuiltConfiguration extends
> AbstractConfiguration {
>          isShutdownHookEnabled = !"disable".equalsIgnoreCase(flag);
>      }
>
> +    public void setShutdownTimeoutMillis(long shutdownTimeoutMillis) {
> +        this.shutdownTimeoutMillis = shutdownTimeoutMillis;
> +    }
> +
>      public void setMonitorInterval(final int intervalSeconds) {
>          if (this instanceof Reconfigurable && intervalSeconds > 0) {
>              final ConfigurationSource configSource =
> getConfigurationSource();
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/builder/impl/DefaultConfigurationBuilder.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/DefaultConfigurationBuilder.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/DefaultConfigurationBuilder.java
> index d8531d6..183094d 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/DefaultConfigurationBuilder.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/builder/impl/DefaultConfigurationBuilder.java
> @@ -22,6 +22,7 @@ import java.io.StringWriter;
>  import java.lang.reflect.Constructor;
>  import java.util.List;
>  import java.util.Map;
> +import java.util.concurrent.TimeUnit;
>  import javax.xml.stream.XMLOutputFactory;
>  import javax.xml.stream.XMLStreamException;
>  import javax.xml.stream.XMLStreamWriter;
> @@ -71,6 +72,7 @@ public class DefaultConfigurationBuilder<T extends
> BuiltConfiguration> implement
>      private String destination;
>      private String packages;
>      private String shutdownFlag;
> +    private long shutdownTimeoutMillis;
>      private String advertiser;
>      private LoggerContext loggerContext;
>      private String name;
> @@ -186,6 +188,9 @@ public class DefaultConfigurationBuilder<T extends
> BuiltConfiguration> implement
>              if (shutdownFlag != null) {
>                  configuration.setShutdownHook(shutdownFlag);
>              }
> +            if (shutdownTimeoutMillis > 0) {
> +                configuration.setShutdownTimeo
> utMillis(shutdownTimeoutMillis);
> +            }
>              if (advertiser != null) {
>                  configuration.createAdvertiser(advertiser, source);
>              }
> @@ -249,6 +254,9 @@ public class DefaultConfigurationBuilder<T extends
> BuiltConfiguration> implement
>          if (shutdownFlag != null) {
>              xmlWriter.writeAttribute("shutdownHook", shutdownFlag);
>          }
> +        if (shutdownTimeoutMillis > 0) {
> +            xmlWriter.writeAttribute("shutdownTimeout",
> String.valueOf(shutdownTimeoutMillis));
> +        }
>          if (advertiser != null) {
>              xmlWriter.writeAttribute("advertiser", advertiser);
>          }
> @@ -514,6 +522,12 @@ public class DefaultConfigurationBuilder<T extends
> BuiltConfiguration> implement
>      }
>
>      @Override
> +    public ConfigurationBuilder<T> setShutdownTimeout(final long timeout,
> final TimeUnit timeUnit) {
> +        this.shutdownTimeoutMillis = timeUnit.toMillis(timeout);
> +        return this;
> +    }
> +
> +    @Override
>      public ConfigurationBuilder<T> setStatusLevel(final Level level) {
>          this.level = level;
>          return this;
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/composite/CompositeConfiguration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/composite/CompositeConfiguration.java b/log4j-core/src/main/java/org
> /apache/logging/log4j/core/config/composite/CompositeConfiguration.java
> index fa941d7..e38c62b 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/composite/CompositeConfiguration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/composite/CompositeConfiguration.java
> @@ -87,6 +87,8 @@ public class CompositeConfiguration extends
> AbstractConfiguration implements Rec
>                  statusConfig.withDestination(value);
>              } else if ("shutdownHook".equalsIgnoreCase(key)) {
>                  isShutdownHookEnabled = !"disable".equalsIgnoreCase(va
> lue);
> +            } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
> +                shutdownTimeoutMillis = Long.parseLong(value);
>              } else if ("verbose".equalsIgnoreCase(key)) {
>                  statusConfig.withVerbosity(value);
>              } else if ("packages".equalsIgnoreCase(key)) {
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/json/JsonConfiguration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/json/JsonConfiguration.java b/log4j-core/src/main/java/org
> /apache/logging/log4j/core/config/json/JsonConfiguration.java
> index 497496a..5b38dfb 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/json/JsonConfiguration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/json/JsonConfiguration.java
> @@ -26,6 +26,9 @@ import java.util.Iterator;
>  import java.util.List;
>  import java.util.Map;
>
> +import com.fasterxml.jackson.core.JsonParser;
> +import com.fasterxml.jackson.databind.JsonNode;
> +import com.fasterxml.jackson.databind.ObjectMapper;
>  import org.apache.logging.log4j.core.LoggerContext;
>  import org.apache.logging.log4j.core.config.AbstractConfiguration;
>  import org.apache.logging.log4j.core.config.Configuration;
> @@ -40,10 +43,6 @@ import org.apache.logging.log4j.core.
> config.status.StatusConfiguration;
>  import org.apache.logging.log4j.core.util.FileWatcher;
>  import org.apache.logging.log4j.core.util.Patterns;
>
> -import com.fasterxml.jackson.core.JsonParser;
> -import com.fasterxml.jackson.databind.JsonNode;
> -import com.fasterxml.jackson.databind.ObjectMapper;
> -
>  /**
>   * Creates a Node hierarchy from a JSON file.
>   */
> @@ -81,6 +80,8 @@ public class JsonConfiguration extends
> AbstractConfiguration implements Reconfig
>                      statusConfig.withDestination(value);
>                  } else if ("shutdownHook".equalsIgnoreCase(key)) {
>                      isShutdownHookEnabled = !"disable".equalsIgnoreCase(va
> lue);
> +                } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
> +                    shutdownTimeoutMillis = Long.parseLong(value);
>                  } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
>                      statusConfig.withVerbosity(value);
>                  } else if ("packages".equalsIgnoreCase(key)) {
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/properties/PropertiesConfigurationBuilder.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/properties/PropertiesConfigurationBuilder.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/properties/PropertiesConfigurationBuilder.java
> index a4362b7..3d24a9b 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/properties/PropertiesConfigurationBuilder.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/properties/PropertiesConfigurationBuilder.java
> @@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.config.properties;
>
>  import java.util.Map;
>  import java.util.Properties;
> +import java.util.concurrent.TimeUnit;
>
>  import org.apache.logging.log4j.Level;
>  import org.apache.logging.log4j.core.Appender;
> @@ -54,6 +55,7 @@ public class PropertiesConfigurationBuilder extends
> ConfigurationBuilderFactory
>      private static final String ADVERTISER_KEY = "advertiser";
>      private static final String STATUS_KEY = "status";
>      private static final String SHUTDOWN_HOOK = "shutdownHook";
> +    private static final String SHUTDOWN_TIMEOUT = "shutdownTimeout";
>      private static final String VERBOSE = "verbose";
>      private static final String DEST = "dest";
>      private static final String PACKAGES = "packages";
> @@ -89,6 +91,7 @@ public class PropertiesConfigurationBuilder extends
> ConfigurationBuilderFactory
>          builder
>              .setStatusLevel(Level.toLevel(rootProperties.getProperty(STATUS_KEY),
> Level.ERROR))
>              .setShutdownHook(rootProperties.getProperty(SHUTDOWN_HOOK))
> +            .setShutdownTimeout(Long.parseLong(rootProperties.getProperty(SHUTDOWN_TIMEOUT,
> "0")), TimeUnit.MILLISECONDS)
>              .setVerbosity(rootProperties.getProperty(VERBOSE))
>              .setDestination(rootProperties.getProperty(DEST))
>              .setPackages(rootProperties.getProperty(PACKAGES))
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/main/java/org/apache/logging/log4j/co
> re/config/xml/XmlConfiguration.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/xml/XmlConfiguration.java
> index 2608552..51f31d4 100644
> --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/xml/XmlConfiguration.java
> +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/con
> fig/xml/XmlConfiguration.java
> @@ -24,7 +24,6 @@ import java.util.ArrayList;
>  import java.util.Arrays;
>  import java.util.List;
>  import java.util.Map;
> -
>  import javax.xml.XMLConstants;
>  import javax.xml.parsers.DocumentBuilder;
>  import javax.xml.parsers.DocumentBuilderFactory;
> @@ -120,6 +119,8 @@ public class XmlConfiguration extends
> AbstractConfiguration implements Reconfigu
>                      statusConfig.withDestination(value);
>                  } else if ("shutdownHook".equalsIgnoreCase(key)) {
>                      isShutdownHookEnabled = !"disable".equalsIgnoreCase(va
> lue);
> +                } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
> +                    shutdownTimeoutMillis = Long.parseLong(value);
>                  } else if ("verbose".equalsIgnoreCase(key)) {
>                      statusConfig.withVerbosity(value);
>                  } else if ("packages".equalsIgnoreCase(key)) {
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/test/java/org/apache/logging/log4j/co
> re/ShutdownTimeoutConfigurationTest.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/Shu
> tdownTimeoutConfigurationTest.java b/log4j-core/src/test/java/org
> /apache/logging/log4j/core/ShutdownTimeoutConfigurationTest.java
> new file mode 100644
> index 0000000..5e0734c
> --- /dev/null
> +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/Shu
> tdownTimeoutConfigurationTest.java
> @@ -0,0 +1,44 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one or more
> + * contributor license agreements. See the NOTICE file distributed with
> + * this work for additional information regarding copyright ownership.
> + * The ASF licenses this file to You under the Apache license, Version 2.0
> + * (the "License"); you may not use this file except in compliance with
> + * the License. You may obtain a copy of the License at
> + *
> + *      http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> + * See the license for the specific language governing permissions and
> + * limitations under the license.
> + */
> +package org.apache.logging.log4j.core;
> +
> +import org.apache.logging.log4j.core.config.Configuration;
> +import org.apache.logging.log4j.junit.LoggerContextRule;
> +import org.junit.ClassRule;
> +import org.junit.Test;
> +
> +import static org.junit.Assert.*;
> +
> +/**
> + *
> + */
> +public class ShutdownTimeoutConfigurationTest {
> +
> +    private static final String CONFIG = "log4j-test-shutdownTimeout.xm
> l";
> +
> +    @ClassRule
> +    public static LoggerContextRule context = new
> LoggerContextRule(CONFIG);
> +
> +    @Test
> +    public void testShutdownFlag() {
> +        final Configuration config = context.getConfiguration();
> +        assertNotNull("No configuration", config);
> +        assertEquals(5000, config.getShutdownTimeoutMillis());
> +    }
> +
> +}
> +
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/test/java/org/apache/logging/log4j/co
> re/config/builder/ConfigurationBuilderTest.java
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/con
> fig/builder/ConfigurationBuilderTest.java b/log4j-core/src/test/java/org
> /apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java
> index 2d48605..431ac01 100644
> --- a/log4j-core/src/test/java/org/apache/logging/log4j/core/con
> fig/builder/ConfigurationBuilderTest.java
> +++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/con
> fig/builder/ConfigurationBuilderTest.java
> @@ -16,6 +16,8 @@
>   */
>  package org.apache.logging.log4j.core.config.builder;
>
> +import java.util.concurrent.TimeUnit;
> +
>  import org.apache.logging.log4j.Level;
>  import org.apache.logging.log4j.core.Filter;
>  import org.apache.logging.log4j.core.appender.ConsoleAppender;
> @@ -36,6 +38,7 @@ public class ConfigurationBuilderTest {
>      private void addTestFixtures(final String name, final
> ConfigurationBuilder<BuiltConfiguration> builder) {
>          builder.setConfigurationName(name);
>          builder.setStatusLevel(Level.ERROR);
> +        builder.setShutdownTimeout(5000, TimeUnit.MILLISECONDS);
>          builder.add(builder.newScriptFile("target/test-classes/
> scripts/filter.groovy").addIsWatched(true));
>          builder.add(builder.newFilter("ThresholdFilter",
> Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
>                  .addAttribute("level", Level.DEBUG));
> @@ -56,7 +59,7 @@ public class ConfigurationBuilderTest {
>
>      private final static String expectedXml =
>              "<?xml version='1.0' encoding='UTF-8'?>" + EOL +
> -            "<Configuration name=\"config name\" status=\"ERROR\"
> packages=\"foo,bar\">" + EOL +
> +            "<Configuration name=\"config name\" status=\"ERROR\"
> packages=\"foo,bar\" shutdownTimeout=\"5000\">" + EOL +
>                  INDENT + "<Properties>" + EOL +
>                  INDENT + INDENT + "<Property
> name=\"MyKey\">MyValue</Property>" + EOL +
>                  INDENT + "</Properties>" + EOL +
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
> ----------------------------------------------------------------------
> diff --git a/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
> b/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
> new file mode 100644
> index 0000000..19b25c9
> --- /dev/null
> +++ b/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
> @@ -0,0 +1,38 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> + Licensed to the Apache Software Foundation (ASF) under one or more
> + contributor license agreements.  See the NOTICE file distributed with
> + this work for additional information regarding copyright ownership.
> + The ASF licenses this file to You under the Apache License, Version 2.0
> + (the "License"); you may not use this file except in compliance with
> + the License.  You may obtain a copy of the License at
> +
> +      http://www.apache.org/licenses/LICENSE-2.0
> +
> + Unless required by applicable law or agreed to in writing, software
> + distributed under the License is distributed on an "AS IS" BASIS,
> + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + See the License for the specific language governing permissions and
> + limitations under the License.
> +
> +-->
> +<Configuration status="OFF" name="XMLConfigTest" monitorInterval="5"
> shutdownTimeout="5000">
> +  <Appenders>
> +    <Console name="STDOUT">
> +      <PatternLayout pattern="%m MDC%X%n"/>
> +    </Console>
> +    <List name="List">
> +    </List>
> +  </Appenders>
> +
> +  <Loggers>
> +    <Logger name="org.apache.logging.log4j.test1" level="debug"
> additivity="false">
> +      <AppenderRef ref="STDOUT"/>
> +    </Logger>>
> +
> +    <Root level="trace">
> +      <AppenderRef ref="List"/>
> +    </Root>
> +  </Loggers>
> +
> +</Configuration>
> \ No newline at end of file
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/src/changes/changes.xml
> ----------------------------------------------------------------------
> diff --git a/src/changes/changes.xml b/src/changes/changes.xml
> index cd2f379..6bd144c 100644
> --- a/src/changes/changes.xml
> +++ b/src/changes/changes.xml
> @@ -23,6 +23,11 @@
>      <title>Changes</title>
>    </properties>
>    <body>
> +    <release version="2.7.1" date="2016-XX-XX" description="GA Release
> 2.7.1">
> +      <action issue="LOG4J2-1623" dev="mikes" type="fix">
> +        Configurable JVM shutdown hook timeout.
> +      </action>
> +    </release>
>      <release version="2.7" date="2016-10-02" description="GA Release 2.7">
>        <action issue="LOG4J2-1618" dev="rpopma" type="fix" due-to="Raman
> Gupta">
>          Fixed ClassCastException when using JUL logging during shutdown.
>
> http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7
> 05e2725/src/site/xdoc/manual/configuration.xml.vm
> ----------------------------------------------------------------------
> diff --git a/src/site/xdoc/manual/configuration.xml.vm
> b/src/site/xdoc/manual/configuration.xml.vm
> index 60419a4..acd41fd 100644
> --- a/src/site/xdoc/manual/configuration.xml.vm
> +++ b/src/site/xdoc/manual/configuration.xml.vm
> @@ -408,6 +408,10 @@ public class Bar {
>                   shutdown hook is enabled by default but may be disabled
> by setting this attribute to "disable"</td>
>                </tr>
>                <tr>
> +                 <td>shutdownTimeout</td>
> +                 <td>Specifies how many milliseconds appenders and other
> plugins will get to shutdown when the JVM shuts down.
> +                 Default is zero. (Not used if <tt>shutdownHook</tt> is
> set to "disable".)</td>
> +              <tr>
>                  <td>status</td>
>                  <td>The level of internal Log4j events that should be
> logged to the console.
>                  Valid values for this attribute are "trace", "debug",
> "info", "warn", "error" and "fatal".
> @@ -841,8 +845,8 @@ public class Bar {
>              </p>
>              <p>
>                Properties configuration files support the advertiser,
> monitorInterval, name, packages, shutdownHook,
> -              status, verbose, and dest attrbutes. See <a
> href="#ConfigurationSyntax">Configuration Syntax</a> for the
> -              definitions of these attributes.
> +              shutdownTimeout, status, verbose, and dest attrbutes. See
> <a href="#ConfigurationSyntax">Configuration Syntax</a>
> +              for the definitions of these attributes.
>              </p>
>            <pre class="prettyprint linenums">
>  status = error
>
>
>
>
> --
> E-Mail: garydgregory@gmail.com | ggregory@apache.org
> Java Persistence with Hibernate, Second Edition
> <http://www.manning.com/bauer3/>
> JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
> Spring Batch in Action <http://www.manning.com/templier/>
> Blog: http://garygregory.wordpress.com
> Home: http://garygregory.com/
> Tweet! http://twitter.com/GaryGregory
>



-- 
[image: MagineTV]

*Mikael Ståldal*
Senior software developer

*Magine TV*
mikael.staldal@magine.com
Grev Turegatan 3  | 114 46 Stockholm, Sweden  |   www.magine.com

Privileged and/or Confidential Information may be contained in this
message. If you are not the addressee indicated in this message
(or responsible for delivery of the message to such a person), you may not
copy or deliver this message to anyone. In such case,
you should destroy this message and kindly notify the sender by reply
email.

Fwd: logging-log4j2 git commit: LOG4J2-1623 Configurable JVM shutdown hook timeout

Posted by Gary Gregory <ga...@gmail.com>.
WRT:

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/composite/CompositeConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index fa941d7..e38c62b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/composite/CompositeConfiguration.java
@@ -87,6 +87,8 @@ public class CompositeConfiguration extends
AbstractConfiguration implements Rec
                 statusConfig.withDestination(value);
             } else if ("shutdownHook".equalsIgnoreCase(key)) {
                 isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+            } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                shutdownTimeoutMillis = Long.parseLong(value);
             } else if ("verbose".equalsIgnoreCase(key)) {
                 statusConfig.withVerbosity(value);
             } else if ("packages".equalsIgnoreCase(key)) {

How about a switch on String instead of an old-school cascading if-else?

Gary

---------- Forwarded message ----------
From: <mi...@apache.org>
Date: Mon, Oct 3, 2016 at 9:54 AM
Subject: logging-log4j2 git commit: LOG4J2-1623 Configurable JVM shutdown
hook timeout
To: commits@logging.apache.org


Repository: logging-log4j2
Updated Branches:
  refs/heads/LOG4J2-1623 [created] 705e27253


LOG4J2-1623  Configurable JVM shutdown hook timeout


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/
commit/705e2725
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/705e2725
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/705e2725

Branch: refs/heads/LOG4J2-1623
Commit: 705e27253ca14cdf0e50039cada041065e308aee
Parents: 3176c96
Author: Mikael Ståldal <mi...@magine.com>
Authored: Mon Oct 3 18:54:27 2016 +0200
Committer: Mikael Ståldal <mi...@magine.com>
Committed: Mon Oct 3 18:54:27 2016 +0200

----------------------------------------------------------------------
 .../logging/log4j/core/LoggerContext.java       |  9 ++--
 .../core/config/AbstractConfiguration.java      | 10 +++++
 .../log4j/core/config/Configuration.java        |  2 +
 .../builder/api/ConfigurationBuilder.java       |  7 ++++
 .../config/builder/impl/BuiltConfiguration.java |  4 ++
 .../impl/DefaultConfigurationBuilder.java       | 14 +++++++
 .../composite/CompositeConfiguration.java       |  2 +
 .../core/config/json/JsonConfiguration.java     |  9 ++--
 .../PropertiesConfigurationBuilder.java         |  3 ++
 .../log4j/core/config/xml/XmlConfiguration.java |  3 +-
 .../core/ShutdownTimeoutConfigurationTest.java  | 44 ++++++++++++++++++++
 .../builder/ConfigurationBuilderTest.java       |  5 ++-
 .../resources/log4j-test-shutdownTimeout.xml    | 38 +++++++++++++++++
 src/changes/changes.xml                         |  5 +++
 src/site/xdoc/manual/configuration.xml.vm       |  8 +++-
 15 files changed, 151 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/LoggerContext.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 7e13963..c964965 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
LoggerContext.java
@@ -16,8 +16,6 @@
  */
 package org.apache.logging.log4j.core;

-import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.
SHUTDOWN_HOOK_MARKER;
-
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
@@ -38,7 +36,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationListener;
-import org.apache.logging.log4j.core.config.ConfigurationSource; //
SUPPRESS CHECKSTYLE
+import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.core.config.DefaultConfiguration;
 import org.apache.logging.log4j.core.config.NullConfiguration;
 import org.apache.logging.log4j.core.config.Reconfigurable;
@@ -56,6 +54,8 @@ import org.apache.logging.log4j.spi.LoggerRegistry;
 import org.apache.logging.log4j.spi.Terminable;
 import org.apache.logging.log4j.util.PropertiesUtil;

+import static org.apache.logging.log4j.core.util.ShutdownCallbackRegistry.
SHUTDOWN_HOOK_MARKER;
+
 /**
  * The LoggerContext is the anchor for the logging system. It maintains a
list of all the loggers requested by
  * applications and a reference to the Configuration. The Configuration
will contain the configured loggers, appenders,
@@ -265,6 +265,7 @@ public class LoggerContext extends AbstractLifeCycle
             if (factory instanceof ShutdownCallbackRegistry) {
                 LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Shutdown hook enabled.
Registering a new one.");
                 try {
+                    final long shutdownTimeoutMillis = this.configuration.
getShutdownTimeoutMillis();
                     this.shutdownCallback = ((ShutdownCallbackRegistry)
factory).addShutdownCallback(new Runnable() {
                         @Override
                         public void run() {
@@ -272,7 +273,7 @@ public class LoggerContext extends AbstractLifeCycle
                             final LoggerContext context =
LoggerContext.this;
                             LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Stopping
LoggerContext[name={}, {}]",
                                     context.getName(), context);
-                            context.stop();
+                            context.stop(shutdownTimeoutMillis,
TimeUnit.MILLISECONDS);
                         }

                         @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/
AbstractConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/AbstractConfiguration.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/AbstractConfiguration.java
index c740b8c..3a6a58e 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/AbstractConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/AbstractConfiguration.java
@@ -102,6 +102,11 @@ public abstract class AbstractConfiguration extends
AbstractFilterable implement
     protected boolean isShutdownHookEnabled = true;

     /**
+     * Shutdown timeout in milliseconds.
+     */
+    protected long shutdownTimeoutMillis = 0;
+
+    /**
      * The Script manager.
      */
     protected ScriptManager scriptManager;
@@ -395,6 +400,11 @@ public abstract class AbstractConfiguration extends
AbstractFilterable implement
         return isShutdownHookEnabled;
     }

+    @Override
+    public long getShutdownTimeoutMillis() {
+        return shutdownTimeoutMillis;
+    }
+
     public void setup() {
         // default does nothing, subclasses do work.
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/Configuration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configuration.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/Configuration.java
index 1a55b48..95e6edc 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/Configuration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/Configuration.java
@@ -128,6 +128,8 @@ public interface Configuration extends Filterable {

     boolean isShutdownHookEnabled();

+    long getShutdownTimeoutMillis();
+
     ConfigurationScheduler getScheduler();

     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/builder/api/ConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/api/ConfigurationBuilder.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/builder/api/ConfigurationBuilder.java
index 4dc9b69..b115651 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/api/ConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/api/ConfigurationBuilder.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.config.builder.api;

 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.concurrent.TimeUnit;

 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
@@ -367,6 +368,12 @@ public interface ConfigurationBuilder<T extends
Configuration> extends Builder<T
      */
     ConfigurationBuilder<T> setShutdownHook(String flag);

+    /**
+     * Specifies how long time appenders and other plugins will get to
shutdown when the JVM shuts down.
+     * Default is zero. (Not used if {@link #setShutdownHook(String)} is
set to "disable".)
+     * @return this builder instance.
+     */
+    ConfigurationBuilder<T> setShutdownTimeout(long timeout, TimeUnit
timeUnit);

     /**
      * Sets the level of the StatusLogger.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/builder/impl/BuiltConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/BuiltConfiguration.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/builder/impl/BuiltConfiguration.java
index aa7761c..c241dfb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/BuiltConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/BuiltConfiguration.java
@@ -147,6 +147,10 @@ public class BuiltConfiguration extends
AbstractConfiguration {
         isShutdownHookEnabled = !"disable".equalsIgnoreCase(flag);
     }

+    public void setShutdownTimeoutMillis(long shutdownTimeoutMillis) {
+        this.shutdownTimeoutMillis = shutdownTimeoutMillis;
+    }
+
     public void setMonitorInterval(final int intervalSeconds) {
         if (this instanceof Reconfigurable && intervalSeconds > 0) {
             final ConfigurationSource configSource =
getConfigurationSource();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/builder/impl/DefaultConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/DefaultConfigurationBuilder.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/DefaultConfigurationBuilder.java
index d8531d6..183094d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/DefaultConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/builder/impl/DefaultConfigurationBuilder.java
@@ -22,6 +22,7 @@ import java.io.StringWriter;
 import java.lang.reflect.Constructor;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
@@ -71,6 +72,7 @@ public class DefaultConfigurationBuilder<T extends
BuiltConfiguration> implement
     private String destination;
     private String packages;
     private String shutdownFlag;
+    private long shutdownTimeoutMillis;
     private String advertiser;
     private LoggerContext loggerContext;
     private String name;
@@ -186,6 +188,9 @@ public class DefaultConfigurationBuilder<T extends
BuiltConfiguration> implement
             if (shutdownFlag != null) {
                 configuration.setShutdownHook(shutdownFlag);
             }
+            if (shutdownTimeoutMillis > 0) {
+                configuration.setShutdownTimeoutMillis(
shutdownTimeoutMillis);
+            }
             if (advertiser != null) {
                 configuration.createAdvertiser(advertiser, source);
             }
@@ -249,6 +254,9 @@ public class DefaultConfigurationBuilder<T extends
BuiltConfiguration> implement
         if (shutdownFlag != null) {
             xmlWriter.writeAttribute("shutdownHook", shutdownFlag);
         }
+        if (shutdownTimeoutMillis > 0) {
+            xmlWriter.writeAttribute("shutdownTimeout", String.valueOf(
shutdownTimeoutMillis));
+        }
         if (advertiser != null) {
             xmlWriter.writeAttribute("advertiser", advertiser);
         }
@@ -514,6 +522,12 @@ public class DefaultConfigurationBuilder<T extends
BuiltConfiguration> implement
     }

     @Override
+    public ConfigurationBuilder<T> setShutdownTimeout(final long timeout,
final TimeUnit timeUnit) {
+        this.shutdownTimeoutMillis = timeUnit.toMillis(timeout);
+        return this;
+    }
+
+    @Override
     public ConfigurationBuilder<T> setStatusLevel(final Level level) {
         this.level = level;
         return this;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/composite/CompositeConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/composite/CompositeConfiguration.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/composite/CompositeConfiguration.java
index fa941d7..e38c62b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/composite/CompositeConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/composite/CompositeConfiguration.java
@@ -87,6 +87,8 @@ public class CompositeConfiguration extends
AbstractConfiguration implements Rec
                 statusConfig.withDestination(value);
             } else if ("shutdownHook".equalsIgnoreCase(key)) {
                 isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+            } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                shutdownTimeoutMillis = Long.parseLong(value);
             } else if ("verbose".equalsIgnoreCase(key)) {
                 statusConfig.withVerbosity(value);
             } else if ("packages".equalsIgnoreCase(key)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/
JsonConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/json/JsonConfiguration.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/json/JsonConfiguration.java
index 497496a..5b38dfb 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/json/JsonConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/json/JsonConfiguration.java
@@ -26,6 +26,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Map;

+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AbstractConfiguration;
 import org.apache.logging.log4j.core.config.Configuration;
@@ -40,10 +43,6 @@ import org.apache.logging.log4j.core.config.status.
StatusConfiguration;
 import org.apache.logging.log4j.core.util.FileWatcher;
 import org.apache.logging.log4j.core.util.Patterns;

-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
 /**
  * Creates a Node hierarchy from a JSON file.
  */
@@ -81,6 +80,8 @@ public class JsonConfiguration extends
AbstractConfiguration implements Reconfig
                     statusConfig.withDestination(value);
                 } else if ("shutdownHook".equalsIgnoreCase(key)) {
                     isShutdownHookEnabled = !"disable".equalsIgnoreCase(
value);
+                } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                    shutdownTimeoutMillis = Long.parseLong(value);
                 } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
                     statusConfig.withVerbosity(value);
                 } else if ("packages".equalsIgnoreCase(key)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/
core/config/properties/PropertiesConfigurationBuilder.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/properties/PropertiesConfigurationBuilder.java
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/properties/
PropertiesConfigurationBuilder.java
index a4362b7..3d24a9b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/properties/PropertiesConfigurationBuilder.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/properties/PropertiesConfigurationBuilder.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.config.properties;

 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.TimeUnit;

 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Appender;
@@ -54,6 +55,7 @@ public class PropertiesConfigurationBuilder extends
ConfigurationBuilderFactory
     private static final String ADVERTISER_KEY = "advertiser";
     private static final String STATUS_KEY = "status";
     private static final String SHUTDOWN_HOOK = "shutdownHook";
+    private static final String SHUTDOWN_TIMEOUT = "shutdownTimeout";
     private static final String VERBOSE = "verbose";
     private static final String DEST = "dest";
     private static final String PACKAGES = "packages";
@@ -89,6 +91,7 @@ public class PropertiesConfigurationBuilder extends
ConfigurationBuilderFactory
         builder
             .setStatusLevel(Level.toLevel(rootProperties.getProperty(STATUS_KEY),
Level.ERROR))
             .setShutdownHook(rootProperties.getProperty(SHUTDOWN_HOOK))
+            .setShutdownTimeout(Long.parseLong(rootProperties.getProperty(SHUTDOWN_TIMEOUT,
"0")), TimeUnit.MILLISECONDS)
             .setVerbosity(rootProperties.getProperty(VERBOSE))
             .setDestination(rootProperties.getProperty(DEST))
             .setPackages(rootProperties.getProperty(PACKAGES))

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/
XmlConfiguration.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/xml/XmlConfiguration.java b/log4j-core/src/main/java/
org/apache/logging/log4j/core/config/xml/XmlConfiguration.java
index 2608552..51f31d4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/xml/XmlConfiguration.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/
config/xml/XmlConfiguration.java
@@ -24,7 +24,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
-
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -120,6 +119,8 @@ public class XmlConfiguration extends
AbstractConfiguration implements Reconfigu
                     statusConfig.withDestination(value);
                 } else if ("shutdownHook".equalsIgnoreCase(key)) {
                     isShutdownHookEnabled = !"disable".equalsIgnoreCase(
value);
+                } else if ("shutdownTimeout".equalsIgnoreCase(key)) {
+                    shutdownTimeoutMillis = Long.parseLong(value);
                 } else if ("verbose".equalsIgnoreCase(key)) {
                     statusConfig.withVerbosity(value);
                 } else if ("packages".equalsIgnoreCase(key)) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/test/java/org/apache/logging/log4j/core/
ShutdownTimeoutConfigurationTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/
ShutdownTimeoutConfigurationTest.java b/log4j-core/src/test/java/
org/apache/logging/log4j/core/ShutdownTimeoutConfigurationTest.java
new file mode 100644
index 0000000..5e0734c
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/
ShutdownTimeoutConfigurationTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache license, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
+ */
+package org.apache.logging.log4j.core;
+
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class ShutdownTimeoutConfigurationTest {
+
+    private static final String CONFIG = "log4j-test-shutdownTimeout.xml";
+
+    @ClassRule
+    public static LoggerContextRule context = new
LoggerContextRule(CONFIG);
+
+    @Test
+    public void testShutdownFlag() {
+        final Configuration config = context.getConfiguration();
+        assertNotNull("No configuration", config);
+        assertEquals(5000, config.getShutdownTimeoutMillis());
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/test/java/org/apache/logging/log4j/
core/config/builder/ConfigurationBuilderTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/
config/builder/ConfigurationBuilderTest.java b/log4j-core/src/test/java/
org/apache/logging/log4j/core/config/builder/ConfigurationBuilderTest.java
index 2d48605..431ac01 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/
ConfigurationBuilderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/builder/
ConfigurationBuilderTest.java
@@ -16,6 +16,8 @@
  */
 package org.apache.logging.log4j.core.config.builder;

+import java.util.concurrent.TimeUnit;
+
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.appender.ConsoleAppender;
@@ -36,6 +38,7 @@ public class ConfigurationBuilderTest {
     private void addTestFixtures(final String name, final
ConfigurationBuilder<BuiltConfiguration> builder) {
         builder.setConfigurationName(name);
         builder.setStatusLevel(Level.ERROR);
+        builder.setShutdownTimeout(5000, TimeUnit.MILLISECONDS);
         builder.add(builder.newScriptFile("target/test-
classes/scripts/filter.groovy").addIsWatched(true));
         builder.add(builder.newFilter("ThresholdFilter",
Filter.Result.ACCEPT, Filter.Result.NEUTRAL)
                 .addAttribute("level", Level.DEBUG));
@@ -56,7 +59,7 @@ public class ConfigurationBuilderTest {

     private final static String expectedXml =
             "<?xml version='1.0' encoding='UTF-8'?>" + EOL +
-            "<Configuration name=\"config name\" status=\"ERROR\"
packages=\"foo,bar\">" + EOL +
+            "<Configuration name=\"config name\" status=\"ERROR\"
packages=\"foo,bar\" shutdownTimeout=\"5000\">" + EOL +
                 INDENT + "<Properties>" + EOL +
                 INDENT + INDENT + "<Property
name=\"MyKey\">MyValue</Property>"
+ EOL +
                 INDENT + "</Properties>" + EOL +

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
b/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
new file mode 100644
index 0000000..19b25c9
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-test-shutdownTimeout.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<Configuration status="OFF" name="XMLConfigTest" monitorInterval="5"
shutdownTimeout="5000">
+  <Appenders>
+    <Console name="STDOUT">
+      <PatternLayout pattern="%m MDC%X%n"/>
+    </Console>
+    <List name="List">
+    </List>
+  </Appenders>
+
+  <Loggers>
+    <Logger name="org.apache.logging.log4j.test1" level="debug"
additivity="false">
+      <AppenderRef ref="STDOUT"/>
+    </Logger>>
+
+    <Root level="trace">
+      <AppenderRef ref="List"/>
+    </Root>
+  </Loggers>
+
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index cd2f379..6bd144c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -23,6 +23,11 @@
     <title>Changes</title>
   </properties>
   <body>
+    <release version="2.7.1" date="2016-XX-XX" description="GA Release
2.7.1">
+      <action issue="LOG4J2-1623" dev="mikes" type="fix">
+        Configurable JVM shutdown hook timeout.
+      </action>
+    </release>
     <release version="2.7" date="2016-10-02" description="GA Release 2.7">
       <action issue="LOG4J2-1618" dev="rpopma" type="fix" due-to="Raman
Gupta">
         Fixed ClassCastException when using JUL logging during shutdown.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/
705e2725/src/site/xdoc/manual/configuration.xml.vm
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/configuration.xml.vm
b/src/site/xdoc/manual/configuration.xml.vm
index 60419a4..acd41fd 100644
--- a/src/site/xdoc/manual/configuration.xml.vm
+++ b/src/site/xdoc/manual/configuration.xml.vm
@@ -408,6 +408,10 @@ public class Bar {
                  shutdown hook is enabled by default but may be disabled
by setting this attribute to "disable"</td>
               </tr>
               <tr>
+                 <td>shutdownTimeout</td>
+                 <td>Specifies how many milliseconds appenders and other
plugins will get to shutdown when the JVM shuts down.
+                 Default is zero. (Not used if <tt>shutdownHook</tt> is
set to "disable".)</td>
+              <tr>
                 <td>status</td>
                 <td>The level of internal Log4j events that should be
logged to the console.
                 Valid values for this attribute are "trace", "debug",
"info", "warn", "error" and "fatal".
@@ -841,8 +845,8 @@ public class Bar {
             </p>
             <p>
               Properties configuration files support the advertiser,
monitorInterval, name, packages, shutdownHook,
-              status, verbose, and dest attrbutes. See <a
href="#ConfigurationSyntax">Configuration Syntax</a> for the
-              definitions of these attributes.
+              shutdownTimeout, status, verbose, and dest attrbutes. See <a
href="#ConfigurationSyntax">Configuration Syntax</a>
+              for the definitions of these attributes.
             </p>
           <pre class="prettyprint linenums">
 status = error




-- 
E-Mail: garydgregory@gmail.com | ggregory@apache.org
Java Persistence with Hibernate, Second Edition
<http://www.manning.com/bauer3/>
JUnit in Action, Second Edition <http://www.manning.com/tahchiev/>
Spring Batch in Action <http://www.manning.com/templier/>
Blog: http://garygregory.wordpress.com
Home: http://garygregory.com/
Tweet! http://twitter.com/GaryGregory