You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2014/10/06 00:56:51 UTC
[1/6] git commit: Add Cancellable interface.
Repository: logging-log4j2
Updated Branches:
refs/heads/master 4bfb0952f -> faa143979
Add Cancellable interface.
- Provides a tiny subset of RunnableFuture.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/69c96c9b
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/69c96c9b
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/69c96c9b
Branch: refs/heads/master
Commit: 69c96c9b05f183c76ff09799e0130c9f6dcf4daf
Parents: 4bfb095
Author: Matt Sicker <ma...@apache.org>
Authored: Sun Oct 5 15:49:12 2014 -0500
Committer: Matt Sicker <ma...@apache.org>
Committed: Sun Oct 5 15:49:12 2014 -0500
----------------------------------------------------------------------
.../logging/log4j/core/util/Cancellable.java | 30 ++++++++++++++++++++
1 file changed, 30 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/69c96c9b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Cancellable.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Cancellable.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Cancellable.java
new file mode 100644
index 0000000..bc58dd9
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Cancellable.java
@@ -0,0 +1,30 @@
+/*
+ * 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.util;
+
+/**
+ * Interface to cancel a Runnable callback.
+ *
+ * @since 2.1
+ */
+public interface Cancellable extends Runnable {
+
+ /**
+ * Cancels the execution of this Runnable callback. This method has no effect if this has already executed.
+ */
+ void cancel();
+}
[4/6] git commit: Create customizable ShutdownCallbackRegistry.
Posted by ma...@apache.org.
Create customizable ShutdownCallbackRegistry.
- Implements LOG4J2-868.
- Renamed ShutdownRegistrationStrategy to ShutdownCallbackRegistry.
- Shutdown callback registry has been scoped to Log4jContextFactory
for use in application containers.
- ShutdownCallbackRegistry can optionally implement LifeCycle.
- DefaultShutdownCallbackRegistry can also be extended.
- Added constructors to Log4jContextFactory (mainly seems useful
for subclasses).
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/cd5edee0
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/cd5edee0
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/cd5edee0
Branch: refs/heads/master
Commit: cd5edee067cb577d9d2f7607af41bf1f99da0a60
Parents: d9e52a3
Author: Matt Sicker <ma...@apache.org>
Authored: Sun Oct 5 17:52:40 2014 -0500
Committer: Matt Sicker <ma...@apache.org>
Committed: Sun Oct 5 17:52:40 2014 -0500
----------------------------------------------------------------------
.../logging/log4j/core/LoggerContext.java | 109 ++++--------
.../log4j/core/impl/Log4jContextFactory.java | 71 +++++++-
.../util/DefaultShutdownCallbackRegistry.java | 175 +++++++++++++++++++
.../DefaultShutdownRegistrationStrategy.java | 41 -----
.../core/util/ShutdownCallbackRegistry.java | 56 ++++++
.../core/util/ShutdownRegistrationStrategy.java | 61 -------
6 files changed, 332 insertions(+), 181 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/cd5edee0/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 fb3b57c..25c6bc1 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
@@ -19,8 +19,6 @@ package org.apache.logging.log4j.core;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
-import java.lang.ref.Reference;
-import java.lang.ref.SoftReference;
import java.net.URI;
import java.util.Collection;
import java.util.concurrent.ConcurrentHashMap;
@@ -39,15 +37,14 @@ import org.apache.logging.log4j.core.config.NullConfiguration;
import org.apache.logging.log4j.core.config.Reconfigurable;
import org.apache.logging.log4j.core.jmx.Server;
import org.apache.logging.log4j.core.util.Assert;
-import org.apache.logging.log4j.core.util.DefaultShutdownRegistrationStrategy;
-import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.Cancellable;
import org.apache.logging.log4j.core.util.NetUtils;
-import org.apache.logging.log4j.core.util.ShutdownRegistrationStrategy;
+import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.message.MessageFactory;
import org.apache.logging.log4j.spi.AbstractLogger;
-import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
-import static org.apache.logging.log4j.core.util.ShutdownRegistrationStrategy.SHUTDOWN_HOOK_MARKER;
+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
@@ -60,9 +57,6 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
private static final long serialVersionUID = 1L;
- private static final boolean SHUTDOWN_HOOK_ENABLED =
- PropertiesUtil.getProperties().getBooleanProperty(ShutdownRegistrationStrategy.SHUTDOWN_HOOK_ENABLED, true);
-
public static final String PROPERTY_CONFIG = "config";
private static final Configuration NULL_CONFIGURATION = new NullConfiguration();
@@ -77,14 +71,7 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
private Object externalContext;
private final String name;
private URI configLocation;
-
- /**
- * Once a shutdown hook thread executes, we can't remove it from the runtime (throws an exception). Therefore,
- * it's really pointless to keep a strongly accessible reference to said thread. Thus, please use a
- * SoftReference here to prevent possible cyclic memory references.
- */
- private Reference<Thread> shutdownThread;
- private ShutdownRegistrationStrategy shutdownRegistrationStrategy;
+ private Cancellable shutdownCallback;
private final Lock configLock = new ReentrantLock();
@@ -149,7 +136,9 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
if (this.isInitialized() || this.isStopped()) {
this.setStarting();
reconfigure();
- setUpShutdownHook();
+ if (this.config.isShutdownHookEnabled()) {
+ setUpShutdownHook();
+ }
this.setStarted();
}
} finally {
@@ -168,7 +157,9 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
if (configLock.tryLock()) {
try {
if (this.isInitialized() || this.isStopped()) {
- setUpShutdownHook();
+ if (this.config.isShutdownHookEnabled()) {
+ setUpShutdownHook();
+ }
this.setStarted();
}
} finally {
@@ -180,33 +171,25 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
}
private void setUpShutdownHook() {
- if (config.isShutdownHookEnabled() && SHUTDOWN_HOOK_ENABLED) {
- LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Shutdown hook enabled. Registering a new one.");
- shutdownThread = new SoftReference<Thread>(
- new Thread(new ShutdownThread(this), "log4j-shutdown")
- );
- addShutdownHook();
- }
- }
-
- private void addShutdownHook() {
- final Thread hook = getShutdownThread();
- if (hook != null) {
- final String shutdownStrategyClassName = PropertiesUtil.getProperties().getStringProperty(
- ShutdownRegistrationStrategy.SHUTDOWN_REGISTRATION_STRATEGY);
- if (shutdownStrategyClassName != null) {
- try {
- shutdownRegistrationStrategy = Loader.newCheckedInstanceOf(shutdownStrategyClassName,
- ShutdownRegistrationStrategy.class);
- } catch (final Exception e) {
- LOGGER.error(SHUTDOWN_HOOK_MARKER,
- "There was an error loading the ShutdownRegistrationStrategy [{}]. "
- + "Falling back to DefaultShutdownRegistrationStrategy.",
- shutdownStrategyClassName, e);
- shutdownRegistrationStrategy = new DefaultShutdownRegistrationStrategy();
- }
+ if (shutdownCallback == null) {
+ final LoggerContextFactory factory = LogManager.getFactory();
+ if (factory instanceof ShutdownCallbackRegistry) {
+ LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Shutdown hook enabled. Registering a new one.");
try {
- shutdownRegistrationStrategy.registerShutdownHook(hook);
+ this.shutdownCallback = ((ShutdownCallbackRegistry) factory).addShutdownCallback(new Runnable() {
+ @Override
+ public void run() {
+ final LoggerContext context = LoggerContext.this;
+ LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Stopping LoggerContext[name={}, {}]", context.getName(),
+ context);
+ context.stop();
+ }
+
+ @Override
+ public String toString() {
+ return "Shutdown callback for LoggerContext[name=" + LoggerContext.this.getName() + ']';
+ }
+ });
} catch (final IllegalStateException ise) {
LOGGER.fatal(SHUTDOWN_HOOK_MARKER, "Unable to register shutdown hook because JVM is shutting down.");
} catch (final SecurityException se) {
@@ -216,10 +199,6 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
}
}
- private Thread getShutdownThread() {
- return shutdownThread == null ? null : shutdownThread.get();
- }
-
@Override
public void stop() {
LOGGER.debug("Stopping LoggerContext[name={}, {}]...", getName(), this);
@@ -229,7 +208,10 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
return;
}
this.setStopping();
- tearDownShutdownHook();
+ if (shutdownCallback != null) {
+ shutdownCallback.cancel();
+ shutdownCallback = null;
+ }
final Configuration prev = config;
config = NULL_CONFIGURATION;
updateLoggers();
@@ -246,15 +228,6 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
LOGGER.debug("Stopped LoggerContext[name={}, {}]...", getName(), this);
}
- private void tearDownShutdownHook() {
- final Thread thread = this.getShutdownThread();
- if (shutdownRegistrationStrategy != null && thread != null) {
- shutdownRegistrationStrategy.unregisterShutdownHook(thread);
- LOGGER.debug(SHUTDOWN_HOOK_MARKER, "Enqueue shutdown hook for garbage collection.");
- shutdownThread.enqueue();
- }
- }
-
/**
* Gets the name.
*
@@ -491,20 +464,4 @@ public class LoggerContext extends AbstractLifeCycle implements org.apache.loggi
return new Logger(ctx, name, messageFactory);
}
- private static class ShutdownThread implements Runnable {
-
- private final LoggerContext context;
-
- public ShutdownThread(final LoggerContext context) {
- this.context = context;
- }
-
- @Override
- public void run() {
- LOGGER.debug("ShutdownThread stopping LoggerContext[name={}, {}]...", context.getName(), context);
- context.stop();
- LOGGER.debug("ShutdownThread stopped LoggerContext[name={}, {}].", context.getName(), context);
- }
- }
-
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/cd5edee0/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
index ee45061..67139c7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jContextFactory.java
@@ -25,8 +25,12 @@ import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
import org.apache.logging.log4j.core.selector.ContextSelector;
+import org.apache.logging.log4j.core.util.Assert;
+import org.apache.logging.log4j.core.util.Cancellable;
import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.core.util.DefaultShutdownCallbackRegistry;
import org.apache.logging.log4j.core.util.Loader;
+import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
import org.apache.logging.log4j.spi.LoggerContextFactory;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.PropertiesUtil;
@@ -34,17 +38,20 @@ import org.apache.logging.log4j.util.PropertiesUtil;
/**
* Factory to locate a ContextSelector and then load a LoggerContext.
*/
-public class Log4jContextFactory implements LoggerContextFactory {
+public class Log4jContextFactory implements LoggerContextFactory, ShutdownCallbackRegistry {
private static final StatusLogger LOGGER = StatusLogger.getLogger();
+ private static final boolean SHUTDOWN_HOOK_ENABLED =
+ PropertiesUtil.getProperties().getBooleanProperty(ShutdownCallbackRegistry.SHUTDOWN_HOOK_ENABLED, true);
private final ContextSelector selector;
+ private final ShutdownCallbackRegistry shutdownCallbackRegistry;
/**
* Initializes the ContextSelector from system property {@link Constants#LOG4J_CONTEXT_SELECTOR}.
*/
public Log4jContextFactory() {
- this(createContextSelector());
+ this(createContextSelector(), createShutdownCallbackRegistry());
}
/**
@@ -52,7 +59,34 @@ public class Log4jContextFactory implements LoggerContextFactory {
* @param selector the selector to use
*/
public Log4jContextFactory(final ContextSelector selector) {
- this.selector = selector;
+ this(selector, createShutdownCallbackRegistry());
+ }
+
+ /**
+ * Constructs a Log4jContextFactory using the ContextSelector from {@link Constants#LOG4J_CONTEXT_SELECTOR}
+ * and the provided ShutdownRegistrationStrategy.
+ *
+ * @param shutdownCallbackRegistry the ShutdownRegistrationStrategy to use
+ * @since 2.1
+ */
+ public Log4jContextFactory(final ShutdownCallbackRegistry shutdownCallbackRegistry) {
+ this(createContextSelector(), shutdownCallbackRegistry);
+ }
+
+ /**
+ * Constructs a Log4jContextFactory using the provided ContextSelector and ShutdownRegistrationStrategy.
+ *
+ * @param selector the selector to use
+ * @param shutdownCallbackRegistry the ShutdownRegistrationStrategy to use
+ * @since 2.1
+ */
+ public Log4jContextFactory(final ContextSelector selector,
+ final ShutdownCallbackRegistry shutdownCallbackRegistry) {
+ this.selector = Assert.requireNonNull(selector, "No ContextSelector provided");
+ this.shutdownCallbackRegistry = Assert.requireNonNull(shutdownCallbackRegistry,
+ "No ShutdownCallbackRegistry provided");
+ LOGGER.debug("Using ShutdownCallbackRegistry {}", shutdownCallbackRegistry.getClass());
+ initializeShutdownCallbackRegistry();
}
private static ContextSelector createContextSelector() {
@@ -67,6 +101,32 @@ public class Log4jContextFactory implements LoggerContextFactory {
return new ClassLoaderContextSelector();
}
+ private static ShutdownCallbackRegistry createShutdownCallbackRegistry() {
+ // TODO: this is such a common idiom it really deserves a utility method somewhere
+ final String registry = PropertiesUtil.getProperties().getStringProperty(
+ ShutdownCallbackRegistry.SHUTDOWN_CALLBACK_REGISTRY);
+ if (registry != null) {
+ try {
+ return Loader.newCheckedInstanceOf(registry, ShutdownCallbackRegistry.class);
+ } catch (final Exception e) {
+ LOGGER.error(SHUTDOWN_HOOK_MARKER,
+ "There was an error loading the ShutdownCallbackRegistry [{}]. "
+ + "Falling back to DefaultShutdownCallbackRegistry.", registry, e);
+ }
+ }
+ return new DefaultShutdownCallbackRegistry();
+ }
+
+ private void initializeShutdownCallbackRegistry() {
+ if (SHUTDOWN_HOOK_ENABLED && this.shutdownCallbackRegistry instanceof LifeCycle) {
+ try {
+ ((LifeCycle) this.shutdownCallbackRegistry).start();
+ } catch (final Exception e) {
+ LOGGER.error("There was an error starting the ShutdownCallbackRegistry.", e);
+ }
+ }
+ }
+
/**
* Loads the LoggerContext using the ContextSelector.
* @param fqcn The fully qualified class name of the caller.
@@ -167,4 +227,9 @@ public class Log4jContextFactory implements LoggerContextFactory {
selector.removeContext((LoggerContext) context);
}
}
+
+ @Override
+ public Cancellable addShutdownCallback(final Runnable callback) {
+ return SHUTDOWN_HOOK_ENABLED ? shutdownCallbackRegistry.addShutdownCallback(callback) : null;
+ }
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/cd5edee0/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
new file mode 100644
index 0000000..21cf8d2
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownCallbackRegistry.java
@@ -0,0 +1,175 @@
+/*
+ * 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.util;
+
+import java.io.Serializable;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LifeCycle;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * ShutdownRegistrationStrategy that simply uses {@link Runtime#addShutdownHook(Thread)}. If no strategy is specified,
+ * this one is used for shutdown hook registration.
+ *
+ * @since 2.1
+ */
+public class DefaultShutdownCallbackRegistry implements ShutdownCallbackRegistry, LifeCycle, Runnable, Serializable {
+
+ private static final long serialVersionUID = 1L;
+ protected static final Logger LOGGER = StatusLogger.getLogger();
+
+ private final AtomicReference<State> state = new AtomicReference<State>(State.INITIALIZED);
+ private final ThreadFactory threadFactory;
+ private final Collection<Cancellable> hooks = new CopyOnWriteArrayList<Cancellable>();
+ private Reference<Thread> shutdownHookRef;
+
+ /**
+ * Constructs a DefaultShutdownRegistrationStrategy.
+ */
+ public DefaultShutdownCallbackRegistry() {
+ this(Executors.privilegedThreadFactory());
+ }
+
+ /**
+ * Constructs a DefaultShutdownRegistrationStrategy using the given {@link ThreadFactory}.
+ *
+ * @param threadFactory the ThreadFactory to use to create a {@link Runtime} shutdown hook thread
+ */
+ protected DefaultShutdownCallbackRegistry(final ThreadFactory threadFactory) {
+ this.threadFactory = threadFactory;
+ }
+
+ /**
+ * Executes the registered shutdown callbacks.
+ */
+ @Override
+ public void run() {
+ if (state.compareAndSet(State.STARTED, State.STOPPING)) {
+ for (final Runnable hook : hooks) {
+ try {
+ hook.run();
+ } catch (final Throwable t) {
+ LOGGER.error(SHUTDOWN_HOOK_MARKER, "Caught exception executing shutdown hook {}", hook, t);
+ }
+ }
+ state.set(State.STOPPED);
+ }
+ }
+
+ @Override
+ public Cancellable addShutdownCallback(final Runnable callback) {
+ if (isStarted()) {
+ final Cancellable receipt = new Cancellable() {
+ // use a reference to prevent memory leaks
+ private final Reference<Runnable> hook = new SoftReference<Runnable>(callback);
+
+ @Override
+ public void cancel() {
+ hook.clear();
+ hooks.remove(this);
+ }
+
+ @Override
+ public void run() {
+ final Runnable hook = this.hook.get();
+ if (hook != null) {
+ hook.run();
+ this.hook.clear();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(hook.get());
+ }
+ };
+ hooks.add(receipt);
+ return receipt;
+ }
+ throw new IllegalStateException("Cannot add new shutdown hook as this is not started. Current state: " +
+ state.get().name());
+ }
+
+ /**
+ * Registers the shutdown thread only if this is initialized.
+ */
+ @Override
+ public void start() {
+ if (state.compareAndSet(State.INITIALIZED, State.STARTING)) {
+ try {
+ addShutdownHook(threadFactory.newThread(this));
+ state.set(State.STARTED);
+ } catch (final Exception e) {
+ LOGGER.catching(e);
+ state.set(State.STOPPED);
+ }
+ }
+ }
+
+ private void addShutdownHook(final Thread thread) {
+ shutdownHookRef = new WeakReference<Thread>(thread);
+ Runtime.getRuntime().addShutdownHook(thread);
+ }
+
+ /**
+ * Cancels the shutdown thread only if this is started.
+ */
+ @Override
+ public void stop() {
+ if (state.compareAndSet(State.STARTED, State.STOPPING)) {
+ try {
+ removeShutdownHook();
+ } finally {
+ state.set(State.STOPPED);
+ }
+ }
+ }
+
+ private void removeShutdownHook() {
+ final Thread shutdownThread = shutdownHookRef.get();
+ if (shutdownThread != null) {
+ Runtime.getRuntime().removeShutdownHook(shutdownThread);
+ shutdownHookRef.enqueue();
+ }
+ }
+
+ /**
+ * Indicates if this can accept shutdown hooks.
+ *
+ * @return true if this can accept shutdown hooks
+ */
+ @Override
+ public boolean isStarted() {
+ return state.get() == State.STARTED;
+ }
+
+ @Override
+ public boolean isStopped() {
+ return state.get() == State.STOPPED;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/cd5edee0/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownRegistrationStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownRegistrationStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownRegistrationStrategy.java
deleted file mode 100644
index 723ce59..0000000
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/DefaultShutdownRegistrationStrategy.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.util;
-
-import java.io.Serializable;
-
-/**
- * ShutdownRegistrationStrategy that simply uses {@link Runtime#addShutdownHook(Thread)}. If no strategy is specified,
- * this one is used for shutdown hook registration.
- *
- * @since 2.1
- */
-public class DefaultShutdownRegistrationStrategy implements ShutdownRegistrationStrategy, Serializable {
-
- private static final long serialVersionUID = 1L;
-
- @Override
- public void registerShutdownHook(final Thread hook) {
- Runtime.getRuntime().addShutdownHook(hook);
- }
-
- @Override
- public void unregisterShutdownHook(final Thread hook) {
- Runtime.getRuntime().removeShutdownHook(hook);
- }
-}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/cd5edee0/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistry.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistry.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistry.java
new file mode 100644
index 0000000..68478dd
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistry.java
@@ -0,0 +1,56 @@
+/*
+ * 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.util;
+
+import org.apache.logging.log4j.Marker;
+import org.apache.logging.log4j.MarkerManager;
+
+/**
+ * Registry used for Runnable shutdown callback instances. Due to differing requirements of how late in the JVM
+ * lifecycle Log4j should be shut down, this interface is provided for customizing how to register shutdown hook
+ * callbacks. Implementations may optionally implement {@link org.apache.logging.log4j.core.LifeCycle}.
+ *
+ * @since 2.1
+ */
+public interface ShutdownCallbackRegistry {
+
+ /**
+ * System property to set to choose the ShutdownCallbackRegistry.
+ */
+ String SHUTDOWN_CALLBACK_REGISTRY = "log4j.shutdownCallbackRegistry";
+
+ /**
+ * System property to set to override the global ability to register shutdown hooks.
+ */
+ String SHUTDOWN_HOOK_ENABLED = "log4j.shutdownHookEnabled";
+
+ /**
+ * Shared Marker to indicate log messages corresponding to shutdown hooks.
+ */
+ Marker SHUTDOWN_HOOK_MARKER = MarkerManager.getMarker("SHUTDOWN HOOK");
+
+ /**
+ * Adds a Runnable shutdown callback to this class.
+ *
+ * @param callback the shutdown callback to be executed upon shutdown.
+ * @return a Cancellable wrapper of the provided callback or {@code null} if the shutdown hook is disabled and
+ * cannot be added.
+ * @since 2.1
+ */
+ Cancellable addShutdownCallback(Runnable callback);
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/cd5edee0/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownRegistrationStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownRegistrationStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownRegistrationStrategy.java
deleted file mode 100644
index adeeda2..0000000
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ShutdownRegistrationStrategy.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.util;
-
-import org.apache.logging.log4j.Marker;
-import org.apache.logging.log4j.MarkerManager;
-
-/**
- * Strategy used for registering shutdown hook threads. Due to differing requirements of how late in the JVM lifecycle
- * Log4j should be shut down, this interface is provided for customizing how to register shutdown hook threads.
- *
- * @since 2.1
- */
-public interface ShutdownRegistrationStrategy {
-
- /**
- * System property to set to choose the ShutdownRegistryStrategy.
- */
- String SHUTDOWN_REGISTRATION_STRATEGY = "log4j.shutdownRegistrationStrategy";
-
- /**
- * System property to set to override the global ability to register shutdown hooks.
- */
- String SHUTDOWN_HOOK_ENABLED = "log4j.shutdownHookEnabled";
-
- /**
- * Shared Marker to indicate log messages corresponding to shutdown hooks.
- */
- Marker SHUTDOWN_HOOK_MARKER = MarkerManager.getMarker("SHUTDOWN HOOK");
-
- /**
- * Adds a shutdown hook to be executed upon JVM exit.
- *
- * @param hook a Thread in the {@code State.NEW} state
- * @throws IllegalStateException If the virtual machine is already in the process of shutting down
- */
- void registerShutdownHook(Thread hook);
-
- /**
- * Removes a shutdown hook.
- *
- * @param hook a previously registered shutdown hook Thread.
- * @throws IllegalStateException If the virtual machine is already in the process of shutting down
- */
- void unregisterShutdownHook(Thread hook);
-}
[2/6] git commit: Add mvn -DEBUG system property support to ILC.
Posted by ma...@apache.org.
Add mvn -DEBUG system property support to ILC.
- Just run mvn with the "-DEBUG" option to automatically enable
debug logging for the StatusLogger when using ILC.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/29304061
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/29304061
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/29304061
Branch: refs/heads/master
Commit: 29304061e98e074c709eadcce5d2fa47c8072a42
Parents: 69c96c9
Author: Matt Sicker <ma...@apache.org>
Authored: Sun Oct 5 17:18:23 2014 -0500
Committer: Matt Sicker <ma...@apache.org>
Committed: Sun Oct 5 17:18:23 2014 -0500
----------------------------------------------------------------------
.../org/apache/logging/log4j/junit/InitialLoggerContext.java | 7 +++++++
1 file changed, 7 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/29304061/log4j-core/src/test/java/org/apache/logging/log4j/junit/InitialLoggerContext.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/junit/InitialLoggerContext.java b/log4j-core/src/test/java/org/apache/logging/log4j/junit/InitialLoggerContext.java
index 2867b81..138edf4 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/junit/InitialLoggerContext.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/junit/InitialLoggerContext.java
@@ -16,6 +16,7 @@
*/
package org.apache.logging.log4j.junit;
+import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
@@ -31,6 +32,9 @@ import static org.junit.Assert.*;
/**
* JUnit {@link TestRule} for constructing a new LoggerContext using a specified configuration file.
+ * If the system property {@code EBUG} is set (e.g., through the command line option {@code -DEBUG}), then the
+ * StatusLogger will be set to the debug level. This allows for more debug messages as the StatusLogger will be in the
+ * error level until a configuration file has been read and parsed into a tree of Nodes.
*/
public class InitialLoggerContext implements TestRule {
@@ -46,6 +50,9 @@ public class InitialLoggerContext implements TestRule {
@Override
public Statement apply(final Statement base, final Description description) {
+ if (System.getProperties().containsKey("EBUG")) {
+ StatusLogger.getLogger().setLevel(Level.DEBUG);
+ }
testClassName = description.getClassName();
return new Statement() {
@Override
[6/6] git commit: Update changelog for LOG4J2-868.
Posted by ma...@apache.org.
Update changelog for LOG4J2-868.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/faa14397
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/faa14397
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/faa14397
Branch: refs/heads/master
Commit: faa14397987f199f30e77e938bf79d72a225e12d
Parents: 0efdad9
Author: Matt Sicker <ma...@apache.org>
Authored: Sun Oct 5 17:56:49 2014 -0500
Committer: Matt Sicker <ma...@apache.org>
Committed: Sun Oct 5 17:56:49 2014 -0500
----------------------------------------------------------------------
src/changes/changes.xml | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/faa14397/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index b4944e6..3a402f7 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -23,7 +23,11 @@
<title>Changes</title>
</properties>
<body>
- <release version="2.1" date="2014-10-04" description="GA Release 2.1">
+ <release version="2.1" date="2014-10-05" description="GA Release 2.1">
+ <action issue="LOG4J2-868" dev="mattsicker" type="add">
+ Add ShutdownCallbackRegistry interface for customizable shutdown callback handling. This is particularly
+ useful for application servers that wish to integrate with Log4j 2.
+ </action>
<action issue="LOG4J2-866" dev="rpopma" type="fix" due-to="Gerard Weatherby">
Documentation: fixed missing closing parenthesis in code example.
</action>
[5/6] git commit: Add test for ShutdownCallbackRegistry.
Posted by ma...@apache.org.
Add test for ShutdownCallbackRegistry.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/0efdad9e
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/0efdad9e
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/0efdad9e
Branch: refs/heads/master
Commit: 0efdad9ecbdc579503545c9e4ea3acfe6981d272
Parents: cd5edee
Author: Matt Sicker <ma...@apache.org>
Authored: Sun Oct 5 17:55:06 2014 -0500
Committer: Matt Sicker <ma...@apache.org>
Committed: Sun Oct 5 17:55:06 2014 -0500
----------------------------------------------------------------------
.../core/util/ShutdownCallbackRegistryTest.java | 96 ++++++++++++++++++++
.../resources/ShutdownCallbackRegistryTest.xml | 32 +++++++
2 files changed, 128 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0efdad9e/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java
new file mode 100644
index 0000000..56d9a58
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/util/ShutdownCallbackRegistryTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.util;
+
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.impl.Log4jContextFactory;
+import org.apache.logging.log4j.core.selector.ContextSelector;
+import org.apache.logging.log4j.junit.InitialLoggerContext;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.*;
+
+public class ShutdownCallbackRegistryTest {
+
+ @Rule
+ public final InitialLoggerContext ctx = new InitialLoggerContext("ShutdownCallbackRegistryTest.xml");
+
+ @BeforeClass
+ public static void setUpClass() throws Exception {
+ System.setProperty(ShutdownCallbackRegistry.SHUTDOWN_CALLBACK_REGISTRY, Registry.class.getName());
+ }
+
+ @Test
+ public void testShutdownCallbackRegistry() throws Exception {
+ final LoggerContext context = ctx.getContext();
+ assertTrue("LoggerContext should be started", context.isStarted());
+ assertThat(Registry.CALLBACKS, hasSize(1));
+ Registry.shutdown();
+ assertTrue("LoggerContext should be stopped", context.isStopped());
+ assertThat(Registry.CALLBACKS, hasSize(0));
+ final ContextSelector selector = ((Log4jContextFactory) LogManager.getFactory()).getSelector();
+ assertThat(selector.getLoggerContexts(), not(hasItem(context)));
+ }
+
+ public static class Registry implements ShutdownCallbackRegistry {
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private static final Collection<Cancellable> CALLBACKS = new LinkedList<Cancellable>();
+
+ @Override
+ public Cancellable addShutdownCallback(final Runnable callback) {
+ final Cancellable cancellable = new Cancellable() {
+ @Override
+ public void cancel() {
+ LOGGER.debug("Cancelled shutdown callback: {}", callback);
+ CALLBACKS.remove(this);
+ }
+
+ @Override
+ public void run() {
+ LOGGER.debug("Called shutdown callback: {}", callback);
+ callback.run();
+ }
+ };
+ synchronized (CALLBACKS) {
+ CALLBACKS.add(cancellable);
+ }
+ return cancellable;
+ }
+
+ private static void shutdown() {
+ synchronized (CALLBACKS) {
+ for (final Runnable callback : CALLBACKS) {
+ LOGGER.debug("Calling shutdown callback: {}", callback);
+ callback.run();
+ }
+ CALLBACKS.clear();
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/0efdad9e/log4j-core/src/test/resources/ShutdownCallbackRegistryTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/ShutdownCallbackRegistryTest.xml b/log4j-core/src/test/resources/ShutdownCallbackRegistryTest.xml
new file mode 100644
index 0000000..eb8ec4c
--- /dev/null
+++ b/log4j-core/src/test/resources/ShutdownCallbackRegistryTest.xml
@@ -0,0 +1,32 @@
+<!--
+ 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 name="ShutdownCallbackRegistryTest" status="off">
+ <Appenders>
+ <Console name="Console">
+ <PatternLayout pattern="%m%n"/>
+ </Console>
+ <List name="List"/>
+ </Appenders>
+ <Loggers>
+ <Logger name="org.apache.logging.log4j.core.util.ShutdownCallbackRegistryTest" level="trace" additivity="false">
+ <AppenderRef ref="List"/>
+ </Logger>
+ <Root level="error">
+ <AppenderRef ref="Console"/>
+ </Root>
+ </Loggers>
+</Configuration>
[3/6] git commit: Update configuration manual for
ShutdownCallbackRegistry rename.
Posted by ma...@apache.org.
Update configuration manual for ShutdownCallbackRegistry rename.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d9e52a36
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d9e52a36
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d9e52a36
Branch: refs/heads/master
Commit: d9e52a369d36fb360bc38fd7f885caad3477ffdc
Parents: 2930406
Author: Matt Sicker <ma...@apache.org>
Authored: Sun Oct 5 17:40:05 2014 -0500
Committer: Matt Sicker <ma...@apache.org>
Committed: Sun Oct 5 17:40:05 2014 -0500
----------------------------------------------------------------------
src/site/xdoc/manual/configuration.xml.vm | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d9e52a36/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 be1e529..766f43b 100644
--- a/src/site/xdoc/manual/configuration.xml.vm
+++ b/src/site/xdoc/manual/configuration.xml.vm
@@ -1330,13 +1330,13 @@ public class AwesomeTest {
</td>
</tr>
<tr>
- <td>log4j.shutdownRegistrationStrategy</td>
+ <td>log4j.shutdownCallbackRegistry</td>
<!-- deliberately inserted spaces to allow line break -->
- <td>org.apache.logging .log4j.core.util .DefaultShutdownRegistrationStrategy</td>
+ <td>org.apache.logging .log4j.core.util .DefaultShutdownCallbackRegistry</td>
<td>
Fully specified class name of a class implementing
- <a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/util/ShutdownRegistrationStrategy.html">ShutdownRegistrationStrategy</a>.
- If specified, an instance of this class is used instead of <tt>DefaultShutdownRegistrationStrategy</tt>.
+ <a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/util/ShutdownCallbackRegistry.html">ShutdownCallbackRegistry</a>.
+ If specified, an instance of this class is used instead of <tt>DefaultShutdownCallbackRegistry</tt>.
The specified class must have a default constructor.
</td>
</tr>