Revert to (mostly) previous version that still includes StatusConsoleListener
git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/log4j2/branches/LOG4J2-609@1610903 13f79535-47bb-0310-9956-ffa450edef68
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 9598a1d..c22c50c 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
@@ -34,6 +34,7 @@
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.core.util.Patterns;
import com.fasterxml.jackson.core.JsonParser;
@@ -68,11 +69,19 @@
}
}
processAttributes(rootNode, root);
+ final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
+ .withStatus(getDefaultStatus());
for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
final String key = entry.getKey();
final String value = getStrSubstitutor().replace(entry.getValue());
- if ("shutdownHook".equalsIgnoreCase(key)) {
+ if ("status".equalsIgnoreCase(key)) {
+ statusConfig.withStatus(value);
+ } else if ("dest".equalsIgnoreCase(key)) {
+ statusConfig.withDestination(value);
+ } else if ("shutdownHook".equalsIgnoreCase(key)) {
isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+ } else if ("verbose".equalsIgnoreCase(entry.getKey())) {
+ statusConfig.withVerbosity(value);
} else if ("packages".equalsIgnoreCase(key)) {
final String[] packages = value.split(Patterns.COMMA_SEPARATOR);
for (final String p : packages) {
@@ -89,6 +98,7 @@
createAdvertiser(value, configSource, buffer, "application/json");
}
}
+ statusConfig.initialize();
if (getName() == null) {
setName(configSource.getLocation());
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
new file mode 100644
index 0000000..60abf2f
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConfiguration.java
@@ -0,0 +1,202 @@
+/*
+ * 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.config.status;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.status.StatusListener;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Configuration for setting up {@link StatusConsoleListener} instances.
+ */
+public class StatusConfiguration {
+
+ private static final Level DEFAULT_STATUS = Level.ERROR;
+ private static final Verbosity DEFAULT_VERBOSITY = Verbosity.QUIET;
+
+ private final Collection<String> errorMessages = Collections.synchronizedCollection(new LinkedList<String>());
+ private final StatusLogger logger = StatusLogger.getLogger();
+
+ private volatile boolean initialized = false;
+
+ private Class<? extends StatusConsoleListener> destination = StatusStdOutListener.class;
+ private Level status = DEFAULT_STATUS;
+ private Verbosity verbosity = DEFAULT_VERBOSITY;
+ private String[] verboseClasses;
+
+ /**
+ * Specifies how verbose the StatusLogger should be.
+ */
+ public static enum Verbosity {
+ QUIET, VERBOSE;
+
+ /**
+ * Parses the verbosity property into an enum.
+ *
+ * @param value property value to parse.
+ * @return enum corresponding to value, or QUIET by default.
+ */
+ public static Verbosity toVerbosity(final String value) {
+ return Boolean.parseBoolean(value) ? VERBOSE : QUIET;
+ }
+ }
+
+ /**
+ * Logs an error message to the StatusLogger. If the StatusLogger hasn't been set up yet, queues the message to be
+ * logged after initialization.
+ *
+ * @param message error message to log.
+ */
+ public void error(final String message) {
+ if (!this.initialized) {
+ this.errorMessages.add(message);
+ } else {
+ this.logger.error(message);
+ }
+ }
+
+ /**
+ * Specifies the destination for StatusLogger events. This can be {@code out} (default) for using
+ * {@link System#out standard out}, {@code err} for using {@link System#err standard error}, or a file URI to
+ * which log events will be written. If the provided URI is invalid, then the default destination of standard
+ * out will be used.
+ *
+ * @param destination where status log messages should be output.
+ * @return {@code this}
+ */
+ public StatusConfiguration withDestination(final String destination) {
+ if ("out".equalsIgnoreCase(destination)) {
+ this.destination = StatusStdOutListener.class;
+ } else if ("err".equalsIgnoreCase(destination)) {
+ this.destination = StatusStdErrListener.class;
+ } else {
+ this.error("Invalid destination [" + destination + "]. Only 'out' or 'err' are supported. Defaulting to 'out'.");
+ this.destination = StatusStdOutListener.class;
+ }
+ return this;
+ }
+
+ /**
+ * Specifies the logging level by name to use for filtering StatusLogger messages.
+ *
+ * @param status name of logger level to filter below.
+ * @return {@code this}
+ * @see Level
+ */
+ public StatusConfiguration withStatus(final String status) {
+ this.status = Level.toLevel(status, null);
+ if (this.status == null) {
+ this.error("Invalid status level specified: " + status + ". Defaulting to ERROR.");
+ this.status = Level.ERROR;
+ }
+ return this;
+ }
+
+ /**
+ * Specifies the logging level to use for filtering StatusLogger messages.
+ *
+ * @param status logger level to filter below.
+ * @return {@code this}
+ */
+ public StatusConfiguration withStatus(final Level status) {
+ this.status = status;
+ return this;
+ }
+
+ /**
+ * Specifies the verbosity level to log at. This only applies to classes configured by
+ * {@link #withVerboseClasses(String...) verboseClasses}.
+ *
+ * @param verbosity basic filter for status logger messages.
+ * @return {@code this}
+ */
+ public StatusConfiguration withVerbosity(final String verbosity) {
+ this.verbosity = Verbosity.toVerbosity(verbosity);
+ return this;
+ }
+
+ /**
+ * Specifies which class names to filter if the configured verbosity level is QUIET.
+ *
+ * @param verboseClasses names of classes to filter if not using VERBOSE.
+ * @return {@code this}
+ */
+ public StatusConfiguration withVerboseClasses(final String... verboseClasses) {
+ this.verboseClasses = verboseClasses;
+ return this;
+ }
+
+ /**
+ * Configures and initializes the StatusLogger using the configured options in this instance.
+ */
+ public void initialize() {
+ if (!this.initialized) {
+ if (this.status == Level.OFF) {
+ this.initialized = true;
+ } else {
+ final boolean configured = configureExistingStatusConsoleListener();
+ if (!configured) {
+ registerNewStatusConsoleListener();
+ }
+ migrateSavedLogMessages();
+ }
+ }
+ }
+
+ private boolean configureExistingStatusConsoleListener() {
+ boolean configured = false;
+ for (final StatusListener statusListener : this.logger.getListeners()) {
+ if (this.destination.isInstance(statusListener)) {
+ final StatusConsoleListener listener = (StatusConsoleListener) statusListener;
+ listener.setStatusLevel(this.status);
+ if (this.verbosity == Verbosity.QUIET) {
+ listener.setFilters(this.verboseClasses);
+ }
+ configured = true;
+ }
+ }
+ return configured;
+ }
+
+
+ private void registerNewStatusConsoleListener() {
+ StatusConsoleListener listener;
+ try {
+ listener = this.destination.newInstance();
+ listener.setStatusLevel(this.status);
+ if (this.verbosity == Verbosity.QUIET) {
+ listener.setFilters(this.verboseClasses);
+ }
+ this.logger.registerListener(listener);
+ } catch (ReflectiveOperationException e) {
+ logger.error("Cannot create listener of type " + destination.getClass());
+ }
+ }
+
+ private void migrateSavedLogMessages() {
+ for (final String message : this.errorMessages) {
+ this.logger.error(message);
+ }
+ this.initialized = true;
+ this.errorMessages.clear();
+ }
+}
\ No newline at end of file
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConsoleListener.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConsoleListener.java
new file mode 100644
index 0000000..d029cbb
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusConsoleListener.java
@@ -0,0 +1,86 @@
+/*
+ * 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.config.status;
+
+import java.io.IOException;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.status.StatusData;
+import org.apache.logging.log4j.status.StatusListener;
+
+/**
+ * StatusListener that writes to the Console.
+ */
+public abstract class StatusConsoleListener implements StatusListener {
+
+ protected Level level;
+ private String[] filters = null;
+
+ /**
+ * Creates the StatusConsoleListener using the supplied Level.
+ */
+ public StatusConsoleListener() {
+ this(Level.FATAL);
+ }
+
+ /**
+ * Creates the StatusConsoleListener using the supplied Level.
+ * @param level The Level of status messages that should appear on the console.
+ */
+ public StatusConsoleListener(final Level level) {
+ this.level = level;
+ }
+
+ /**
+ * Sets the level to a new value.
+ * @param level The new Level.
+ */
+ public void setStatusLevel(final Level level) {
+ this.level = level;
+ }
+
+ @Override
+ public Level getStatusLevel() {
+ return level;
+ }
+
+ /**
+ * Adds package name filters to exclude.
+ * @param filters An array of package names to exclude.
+ */
+ public void setFilters(final String... filters) {
+ this.filters = filters;
+ }
+
+ protected boolean isEnabledFor(final StatusData data) {
+ if (filters == null) {
+ return true;
+ }
+ final String caller = data.getStackTraceElement().getClassName();
+ for (final String filter : filters) {
+ if (caller.startsWith(filter)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // don't close system streams
+ }
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdErrListener.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdErrListener.java
new file mode 100644
index 0000000..59bd007
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdErrListener.java
@@ -0,0 +1,14 @@
+package org.apache.logging.log4j.core.config.status;
+
+import org.apache.logging.log4j.status.StatusData;
+
+public class StatusStdErrListener extends StatusConsoleListener {
+
+ @Override
+ public void log(StatusData data) {
+ if (isEnabledFor(data)) {
+ System.err.println(data.getFormattedStatus());
+ }
+ }
+
+}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdOutListener.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdOutListener.java
new file mode 100644
index 0000000..83631e1
--- /dev/null
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/status/StatusStdOutListener.java
@@ -0,0 +1,14 @@
+package org.apache.logging.log4j.core.config.status;
+
+import org.apache.logging.log4j.status.StatusData;
+
+public class StatusStdOutListener extends StatusConsoleListener {
+
+ @Override
+ public void log(StatusData data) {
+ if (isEnabledFor(data)) {
+ System.out.println(data.getFormattedStatus());
+ }
+ }
+
+}
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 309bf66..eadcbbc 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
@@ -43,6 +43,7 @@
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
import org.apache.logging.log4j.core.config.plugins.util.ResolverUtil;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.core.util.Loader;
import org.apache.logging.log4j.core.util.Patterns;
import org.w3c.dom.Attr;
@@ -133,11 +134,19 @@
final Document document = newDocumentBuilder().parse(source);
rootElement = document.getDocumentElement();
final Map<String, String> attrs = processAttributes(rootNode, rootElement);
+ final StatusConfiguration statusConfig = new StatusConfiguration().withVerboseClasses(VERBOSE_CLASSES)
+ .withStatus(getDefaultStatus());
for (final Map.Entry<String, String> entry : attrs.entrySet()) {
final String key = entry.getKey();
final String value = getStrSubstitutor().replace(entry.getValue());
- if ("shutdownHook".equalsIgnoreCase(key)) {
+ if ("status".equalsIgnoreCase(key)) {
+ statusConfig.withStatus(value);
+ } else if ("dest".equalsIgnoreCase(key)) {
+ statusConfig.withDestination(value);
+ } else if ("shutdownHook".equalsIgnoreCase(key)) {
isShutdownHookEnabled = !"disable".equalsIgnoreCase(value);
+ } else if ("verbose".equalsIgnoreCase(key)) {
+ statusConfig.withVerbosity(value);
} else if ("packages".equalsIgnoreCase(key)) {
final String[] packages = value.split(Patterns.COMMA_SEPARATOR);
for (final String p : packages) {
@@ -158,6 +167,7 @@
createAdvertiser(value, configSource, buffer, "text/xml");
}
}
+ statusConfig.initialize();
} catch (final SAXException domEx) {
LOGGER.error("Error parsing " + configSource.getLocation(), domEx);
} catch (final IOException ioe) {
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java
index 1146664..9b12394 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CustomConfigurationTest.java
@@ -69,7 +69,7 @@
assertTrue("Configuration is not an XmlConfiguration", config instanceof XmlConfiguration);
for (final StatusListener listener : StatusLogger.getLogger().getListeners()) {
if (listener instanceof StatusConsoleListener) {
- assertSame(((StatusConsoleListener) listener).getLevel(), Level.INFO);
+ assertSame(((StatusConsoleListener) listener).getStatusLevel(), Level.INFO);
break;
}
}
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java
index b51d8b0..7710d71 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueAppenderTest.java
@@ -59,7 +59,7 @@
public static void setupClass() throws Exception {
// MockContextFactory becomes the primary JNDI provider
final StatusStdOutListener listener = new StatusStdOutListener();
- listener.setLevel(Level.ERROR);
+ listener.setStatusLevel(Level.ERROR);
StatusLogger.getLogger().registerListener(listener);
MockContextFactory.setAsInitial();
context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java
index ed6e284..938916b 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueFailoverTest.java
@@ -87,7 +87,7 @@
private static void setupQueue() throws Exception {
// MockContextFactory becomes the primary JNDI provider
final StatusStdOutListener listener = new StatusStdOutListener();
- listener.setLevel(Level.ERROR);
+ listener.setStatusLevel(Level.ERROR);
StatusLogger.getLogger().registerListener(listener);
MockContextFactory.setAsInitial();
context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java
index 6881ca6..5a6b055 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsQueueTest.java
@@ -65,7 +65,7 @@
public static void setupClass() throws Exception {
// MockContextFactory becomes the primary JNDI provider
final StatusStdOutListener listener = new StatusStdOutListener();
- listener.setLevel(Level.ERROR);
+ listener.setStatusLevel(Level.ERROR);
StatusLogger.getLogger().registerListener(listener);
MockContextFactory.setAsInitial();
context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java
index 47f811e..1ffcb0c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicFailoverTest.java
@@ -86,7 +86,7 @@
private static void setupQueue() throws Exception {
// MockContextFactory becomes the primary JNDI provider
final StatusStdOutListener listener = new StatusStdOutListener();
- listener.setLevel(Level.ERROR);
+ listener.setStatusLevel(Level.ERROR);
StatusLogger.getLogger().registerListener(listener);
MockContextFactory.setAsInitial();
context = new InitialContext();
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java
index 3565c40..0029fb6 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/net/jms/JmsTopicTest.java
@@ -65,7 +65,7 @@
public static void setupClass() throws Exception {
// MockContextFactory becomes the primary JNDI provider
final StatusStdOutListener listener = new StatusStdOutListener();
- listener.setLevel(Level.ERROR);
+ listener.setStatusLevel(Level.ERROR);
StatusLogger.getLogger().registerListener(listener);
MockContextFactory.setAsInitial();
context = new InitialContext();