From 052f8027910030e9ee4c752d2b396985fc29f9bd Mon Sep 17 00:00:00 2001
From: Ryan Schmitt
Date: Wed, 13 Aug 2025 11:40:42 -0700
Subject: [PATCH] Raise default async discard threshold to ERROR
There are two basic scenarios where the ring buffer fills up. One is
that an application is simply logging too much and the flushing process
can't keep up, and in this case a discard threshold of WARN or INFO is
probably sufficient to mitigate the problem. However, if flushing has
stopped making progress altogether, e.g. due to a full or failed disk,
then logging calls will block indefinitely. This can result in a
production outage.
This change sets the default discard threshold to ERROR, in order to
better mitigate the scenario where the disk fills up, fails, or is in
the process of failing. With this threshold, logging should only block
at the FATAL level, which would typically mean that the operation is
already failing anyway.
---
.../core/async/AsyncQueueFullPolicyFactoryTest.java | 4 ++--
.../core/async/AsyncQueueFullPolicyFactory.java | 12 ++++++------
.../.2.x.x/3880-default-discard-threshold.xml | 12 ++++++++++++
3 files changed, 20 insertions(+), 8 deletions(-)
create mode 100644 src/changelog/.2.x.x/3880-default-discard-threshold.xml
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java
index 8a21114e6fc..2a232df836e 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactoryTest.java
@@ -75,7 +75,7 @@ void testCreateDiscardingRouterDefaultThresholdLevelInfo() {
AsyncQueueFullPolicyFactory.PROPERTY_NAME_ASYNC_EVENT_ROUTER,
AsyncQueueFullPolicyFactory.PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER);
assertEquals(
- Level.INFO,
+ Level.ERROR,
((DiscardingAsyncQueueFullPolicy) AsyncQueueFullPolicyFactory.create()).getThresholdLevel());
}
@@ -85,7 +85,7 @@ void testCreateDiscardingRouterCaseInsensitive() {
AsyncQueueFullPolicyFactory.PROPERTY_NAME_ASYNC_EVENT_ROUTER,
toRootLowerCase(AsyncQueueFullPolicyFactory.PROPERTY_VALUE_DISCARDING_ASYNC_EVENT_ROUTER));
assertEquals(
- Level.INFO,
+ Level.ERROR,
((DiscardingAsyncQueueFullPolicy) AsyncQueueFullPolicyFactory.create()).getThresholdLevel());
}
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java
index c8c0fd44d46..e84945369c7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/AsyncQueueFullPolicyFactory.java
@@ -30,10 +30,10 @@
* Property {@code "log4j2.AsyncQueueFullPolicy"} controls the routing behaviour. If this property is not specified or has
* value {@code "Default"}, this factory creates {@link DefaultAsyncQueueFullPolicy} objects.
*
- * If this property has value {@code "Discard"}, this factory creates {@link DiscardingAsyncQueueFullPolicy} objects.
- * By default, this router discards events of level {@code INFO}, {@code DEBUG} and {@code TRACE} if the queue is full.
- * This can be adjusted with property {@code "log4j2.DiscardThreshold"} (name of the level at which to start
- * discarding).
+ * If this property has value {@code "Discard"}, this factory creates {@link DiscardingAsyncQueueFullPolicy} objects. By
+ * default, this router discards events of level {@code ERROR}, {@code WARN}, {@code INFO}, {@code DEBUG} and {@code
+ * TRACE} if the queue is full. This can be adjusted with property {@code "log4j2.DiscardThreshold"} (name of the level
+ * at which to start discarding).
*
* For any other value, this
* factory interprets the value as the fully qualified name of a class implementing the {@link AsyncQueueFullPolicy}
@@ -104,8 +104,8 @@ private static AsyncQueueFullPolicy createCustomRouter(final String router) {
private static AsyncQueueFullPolicy createDiscardingAsyncQueueFullPolicy() {
final PropertiesUtil util = PropertiesUtil.getProperties();
- final String level = util.getStringProperty(PROPERTY_NAME_DISCARDING_THRESHOLD_LEVEL, Level.INFO.name());
- final Level thresholdLevel = Level.toLevel(level, Level.INFO);
+ final String level = util.getStringProperty(PROPERTY_NAME_DISCARDING_THRESHOLD_LEVEL, Level.ERROR.name());
+ final Level thresholdLevel = Level.toLevel(level, Level.ERROR);
LOGGER.debug("Creating custom DiscardingAsyncQueueFullPolicy(discardThreshold:{})", thresholdLevel);
return new DiscardingAsyncQueueFullPolicy(thresholdLevel);
}
diff --git a/src/changelog/.2.x.x/3880-default-discard-threshold.xml b/src/changelog/.2.x.x/3880-default-discard-threshold.xml
new file mode 100644
index 00000000000..ce13fb959b1
--- /dev/null
+++ b/src/changelog/.2.x.x/3880-default-discard-threshold.xml
@@ -0,0 +1,12 @@
+
+
+
+
+ Raise the async logger's default discard threshold to ERROR. This is intended to improve application resilience in the event of a full or failing disk.
+
+