You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2024/02/14 12:59:41 UTC
(logging-log4j2) branch fix/configuration-status-attribute created (now 2fd0d0c37b)
This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a change to branch fix/configuration-status-attribute
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
at 2fd0d0c37b Register a single reference counted StatusConsoleListener
This branch includes the following new commits:
new 2fd0d0c37b Register a single reference counted StatusConsoleListener
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(logging-log4j2) 01/01: Register a single reference counted StatusConsoleListener
Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch fix/configuration-status-attribute
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
commit 2fd0d0c37b078047cb9240e9be607bde80f24699
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Wed Feb 14 13:57:04 2024 +0100
Register a single reference counted StatusConsoleListener
This adds a single `StatusConsoleListener` that is registered by the
first Log4j Core configuration active and removed by the last one.
---
.../log4j/config/PropertiesConfiguration.java | 4 +-
.../org/apache/log4j/xml/XmlConfiguration.java | 4 +-
.../log4j/status/StatusConsoleListener.java | 26 ++-------
.../apache/logging/log4j/status/StatusLogger.java | 3 +-
.../log4j/core/config/AbstractConfiguration.java | 9 +++
.../config/builder/impl/BuiltConfiguration.java | 5 +-
.../config/composite/CompositeConfiguration.java | 2 +-
.../log4j/core/config/json/JsonConfiguration.java | 2 +-
.../core/config/status/StatusConfiguration.java | 64 ++++++++++++++++++++--
.../log4j/core/config/xml/XmlConfiguration.java | 2 +-
src/site/_release-notes/_2.x.x.adoc | 1 +
11 files changed, 81 insertions(+), 41 deletions(-)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
index 3fc3d88ffe..2a30a83079 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -45,7 +45,6 @@ import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.core.filter.ThresholdFilter;
import org.apache.logging.log4j.util.LoaderUtil;
@@ -313,8 +312,7 @@ public class PropertiesConfiguration extends Log4j1Configuration {
status = OptionConverter.toBoolean(value, false) ? "debug" : "error";
}
- final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(status);
- statusConfig.initialize();
+ getStatusConfiguration().withStatus(status).initialize();
// if log4j.reset=true then reset hierarchy
final String reset = properties.getProperty(RESET_KEY);
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
index 0aeaa77675..ab4d53ed9d 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -46,7 +46,6 @@ import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.core.config.status.StatusConfiguration;
import org.apache.logging.log4j.core.filter.ThresholdFilter;
import org.apache.logging.log4j.status.StatusLogger;
import org.apache.logging.log4j.util.LoaderUtil;
@@ -745,8 +744,7 @@ public class XmlConfiguration extends Log4j1Configuration {
status = OptionConverter.toBoolean(confDebug, true) ? "debug" : "error";
}
- final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(status);
- statusConfig.initialize();
+ getStatusConfiguration().withStatus(status).initialize();
final String threshold = subst(element.getAttribute(THRESHOLD_ATTR));
if (threshold != null) {
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusConsoleListener.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusConsoleListener.java
index 99bcd8d1a7..15babbfb42 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusConsoleListener.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusConsoleListener.java
@@ -34,10 +34,6 @@ public class StatusConsoleListener implements StatusListener {
private final Lock lock = new ReentrantLock();
- private final Level initialLevel;
-
- private final PrintStream initialStream;
-
// `volatile` is necessary to correctly read the `level` without holding the lock
private volatile Level level;
@@ -65,8 +61,8 @@ public class StatusConsoleListener implements StatusListener {
* @throws NullPointerException on null {@code level} or {@code stream}
*/
public StatusConsoleListener(final Level level, final PrintStream stream) {
- this.initialLevel = this.level = requireNonNull(level, "level");
- this.initialStream = this.stream = requireNonNull(stream, "stream");
+ this.level = requireNonNull(level, "level");
+ this.stream = requireNonNull(stream, "stream");
}
/**
@@ -149,21 +145,9 @@ public class StatusConsoleListener implements StatusListener {
@Deprecated
public void setFilters(final String... filters) {}
- /**
- * Resets the level and output stream to its initial values, and closes the output stream, if it is a non-system one.
- */
@Override
- public void close() {
- final OutputStream oldStream;
- lock.lock();
- try {
- oldStream = stream;
- stream = initialStream;
- level = initialLevel;
- } finally {
- lock.unlock();
- }
- closeNonSystemStream(oldStream);
+ public void close() throws IOException {
+ closeNonSystemStream(stream);
}
private static void closeNonSystemStream(final OutputStream stream) {
@@ -171,7 +155,7 @@ public class StatusConsoleListener implements StatusListener {
if (stream != System.out && stream != System.err) {
try {
stream.close();
- } catch (IOException error) {
+ } catch (final IOException error) {
// We are at the lowest level of the system.
// Hence, there is nothing better we can do but dumping the failure.
error.printStackTrace(System.err);
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
index 2abc93857d..ecedeba8cb 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/status/StatusLogger.java
@@ -444,7 +444,7 @@ public class StatusLogger extends AbstractLogger {
}
/**
- * Clears the event buffer, removes the <em>registered</em> (not the fallback one!) listeners, and resets the fallback listener.
+ * Clears the event buffer, removes the <em>registered</em> (not the fallback one!) listeners.
*/
public void reset() {
listenerWriteLock.lock();
@@ -458,7 +458,6 @@ public class StatusLogger extends AbstractLogger {
} finally {
listenerWriteLock.unlock();
}
- fallbackListener.close();
buffer.clear();
}
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 d95202be2a..959d7c1677 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
@@ -55,6 +55,7 @@ import org.apache.logging.log4j.core.config.arbiters.SelectArbiter;
import org.apache.logging.log4j.core.config.plugins.util.PluginBuilder;
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.status.StatusConfiguration;
import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.core.layout.PatternLayout;
import org.apache.logging.log4j.core.lookup.ConfigurationStrSubstitutor;
@@ -145,6 +146,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
private AsyncWaitStrategyFactory asyncWaitStrategyFactory;
private NanoClock nanoClock = new DummyNanoClock();
private final WeakReference<LoggerContext> loggerContext;
+ private final StatusConfiguration statusConfiguration;
/**
* Constructor.
@@ -158,6 +160,8 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
componentMap.put(Configuration.CONTEXT_PROPERTIES, propertyMap);
pluginManager = new PluginManager(Node.CATEGORY);
rootNode = new Node();
+ statusConfiguration =
+ new StatusConfiguration().withStatus(getDefaultStatus()).withConfiguration(this);
setState(State.INITIALIZING);
}
@@ -451,6 +455,7 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
}
setStopped();
LOGGER.debug("Stopped {} OK", this);
+ statusConfiguration.stop();
return true;
}
@@ -1231,4 +1236,8 @@ public abstract class AbstractConfiguration extends AbstractFilterable implement
public void setNanoClock(final NanoClock nanoClock) {
this.nanoClock = Objects.requireNonNull(nanoClock, "nanoClock");
}
+
+ protected StatusConfiguration getStatusConfiguration() {
+ return statusConfiguration;
+ }
}
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 f1ec35e06a..49a34ae997 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
@@ -38,7 +38,6 @@ import org.apache.logging.log4j.core.util.Patterns;
* @since 2.4
*/
public class BuiltConfiguration extends AbstractConfiguration {
- private final StatusConfiguration statusConfig;
protected Component rootComponent;
private Component loggersComponent;
private Component appendersComponent;
@@ -51,7 +50,6 @@ public class BuiltConfiguration extends AbstractConfiguration {
public BuiltConfiguration(
final LoggerContext loggerContext, final ConfigurationSource source, final Component rootComponent) {
super(loggerContext, source);
- statusConfig = new StatusConfiguration().withStatus(getDefaultStatus());
for (final Component component : rootComponent.getComponents()) {
switch (component.getPluginType()) {
case "Scripts": {
@@ -131,8 +129,9 @@ public class BuiltConfiguration extends AbstractConfiguration {
super.createAdvertiser(advertiserString, configSource, buffer, contentType);
}
+ @Override
public StatusConfiguration getStatusConfiguration() {
- return statusConfig;
+ return super.getStatusConfiguration();
}
public void setPluginPackages(final String packages) {
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 bf859b1411..25faebc50b 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
@@ -76,7 +76,7 @@ public class CompositeConfiguration extends AbstractConfiguration implements Rec
for (final AbstractConfiguration config : configurations) {
mergeStrategy.mergeRootProperties(rootNode, config);
}
- final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(getDefaultStatus());
+ final StatusConfiguration statusConfig = getStatusConfiguration();
for (final Map.Entry<String, String> entry : rootNode.getAttributes().entrySet()) {
final String key = entry.getKey();
final String value = getConfigurationStrSubstitutor().replace(entry.getValue());
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 b574070a43..2a4d5a7039 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
@@ -64,7 +64,7 @@ public class JsonConfiguration extends AbstractConfiguration implements Reconfig
}
}
processAttributes(rootNode, root);
- final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(getDefaultStatus());
+ final StatusConfiguration statusConfig = getStatusConfiguration();
int monitorIntervalSeconds = 0;
for (final Map.Entry<String, String> entry :
rootNode.getAttributes().entrySet()) {
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
index 1a1c22835a..f61a6b1a97 100644
--- 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
@@ -23,22 +23,32 @@ import java.io.FileOutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Map;
+import java.util.WeakHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.util.FileUtils;
import org.apache.logging.log4j.core.util.NetUtils;
import org.apache.logging.log4j.status.StatusConsoleListener;
import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.PropertiesUtil;
/**
* Configuration for setting up the {@link StatusLogger} fallback listener.
*/
public class StatusConfiguration {
- private static final StatusLogger LOGGER = StatusLogger.getLogger();
+ private static final Logger LOGGER = StatusLogger.getLogger();
+ private static final Level DEFAULT_LEVEL = Level.toLevel(
+ PropertiesUtil.getProperties().getStringProperty(StatusLogger.DEFAULT_STATUS_LISTENER_LEVEL), Level.ERROR);
- private final Lock lock = new ReentrantLock();
+ // Guard all accesses to listener and activeConfigurations
+ private static final Lock lock = new ReentrantLock();
+ private static StatusConsoleListener listener = new StatusConsoleListener(DEFAULT_LEVEL);
+ private static Map<Configuration, Void> activeConfigurations = new WeakHashMap<>();
private volatile boolean initialized;
@@ -48,6 +58,9 @@ public class StatusConfiguration {
@Nullable
private Level level;
+ @Nullable
+ private Configuration configuration;
+
/**
* Specifies how verbose the StatusLogger should be.
* @deprecated This class is not used anymore and only kept for binary backward compatibility.
@@ -179,19 +192,38 @@ public class StatusConfiguration {
return this;
}
+ /**
+ * Sets the logger context associated with this configuration.
+ * @param configuration A logger context.
+ * @return this
+ */
+ public StatusConfiguration withConfiguration(final Configuration configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
/**
* Configures and initializes the StatusLogger using the configured options in this instance.
*/
public void initialize() {
lock.lock();
try {
- if (!this.initialized) {
- final StatusConsoleListener fallbackListener = LOGGER.getFallbackListener();
+ if (!initialized) {
+ final boolean registerListener = activeConfigurations.isEmpty();
+ if (configuration != null) {
+ activeConfigurations.put(configuration, null);
+ } else {
+ LOGGER.error("The required `configuration` parameter is missing.");
+ return;
+ }
if (output != null) {
- fallbackListener.setStream(output);
+ listener.setStream(output);
}
if (level != null) {
- fallbackListener.setLevel(level);
+ listener.setLevel(level);
+ }
+ if (registerListener) {
+ StatusLogger.getLogger().registerListener(listener);
}
initialized = true;
}
@@ -199,4 +231,24 @@ public class StatusConfiguration {
lock.unlock();
}
}
+
+ /**
+ * Stops the associated status logger.
+ */
+ public void stop() {
+ lock.lock();
+ try {
+ if (configuration != null) {
+ activeConfigurations.remove(configuration, null);
+ } else {
+ LOGGER.error("The required `configuration` parameter is missing.");
+ return;
+ }
+ if (activeConfigurations.isEmpty()) {
+ StatusLogger.getLogger().removeListener(listener);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
}
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 6f6d2f1233..6230b0f0c0 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
@@ -106,7 +106,7 @@ public class XmlConfiguration extends AbstractConfiguration implements Reconfigu
}
rootElement = document.getDocumentElement();
final Map<String, String> attrs = processAttributes(rootNode, rootElement);
- final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(getDefaultStatus());
+ final StatusConfiguration statusConfig = getStatusConfiguration();
int monitorIntervalSeconds = 0;
for (final Map.Entry<String, String> entry : attrs.entrySet()) {
final String key = entry.getKey();
diff --git a/src/site/_release-notes/_2.x.x.adoc b/src/site/_release-notes/_2.x.x.adoc
index 79dc38f44b..b2de7e1564 100644
--- a/src/site/_release-notes/_2.x.x.adoc
+++ b/src/site/_release-notes/_2.x.x.adoc
@@ -45,6 +45,7 @@ This releases contains ...
* Fix regression in `JdkMapAdapterStringMap` performance. (https://github.com/apache/logging-log4j2/issues/2238[2238])
* Allow deserialization of all arrays of allowed classes. (https://issues.apache.org/jira/browse/LOG4J2-3680[LOG4J2-3680])
* Fix forgotten `threadName` field in `RingBufferLogEvent#clear()` (https://github.com/apache/logging-log4j2/issues/2234[2234])
+* Fix `StringBuilder` cache corruption on recursive access
* Fixed use of `SecurityManager` in `LoaderUtil` where `AccessController::doPrivileged` should only be invoked when a `SecurityManager` is installed. Some runtimes do not seem to have this method available. (https://github.com/apache/logging-log4j2/issues/2129[2129])
* Fix `log4j-spring-cloud-config-client` dependencies to include only those required. (https://github.com/apache/logging-log4j2/pull/2157[2157])
* Fix typo in Kubernetes `clientKeyData` configuration property.