You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ra...@apache.org on 2026/10/06 19:35:40 UTC
(logging-log4j2) branch main updated: [main] Honor bufferSize and bufferedIo in ConsoleAppender (#4341 port) (#4342)
This is an automated email from the ASF dual-hosted git repository.
ramanathan1504 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/main by this push:
new 23bfb298cd [main] Honor bufferSize and bufferedIo in ConsoleAppender (#4341 port) (#4342)
23bfb298cd is described below
commit 23bfb298cd4cbf5a05d82b9d03a1ef66c35a2ba6
Author: Abhinav <al...@gmail.com>
AuthorDate: Wed Oct 7 01:05:34 2026 +0530
[main] Honor bufferSize and bufferedIo in ConsoleAppender (#4341 port) (#4342)
* [main] Honor bufferSize and bufferedIo in ConsoleAppender (#4338)
* Port review fixes from #4341 to main
The 2.x PR picked up three review changes after this port was opened, so
main was left holding the pre-review revision:
- drop the bufferSize/bufferedIo warning: bufferSize defaults to 8192, so
it fired for every bufferedIo="false" console that never set a buffer
size, and the Console manager uses bufferSize regardless
- keep bufferedIo out of the manager name: the manager does not vary with
bufferedIo, only the appender's flush flag does, so including it split
identical managers
- cover the flush derivation with testUnbufferedIoForcesImmediateFlush,
which fails if !bufferedIo || isImmediateFlush() regresses to
isImmediateFlush()
* Update src/changelog/.3.x.x/4338_console_buffer_size.xml
---------
Co-authored-by: Ramanathan <ra...@apache.org>
---
.../log4j/core/appender/ConsoleAppenderTest.java | 63 ++++++++++++++++++++++
.../log4j/core/appender/ConsoleAppender.java | 21 +++++---
src/changelog/.3.x.x/4338_console_buffer_size.xml | 13 +++++
.../modules/ROOT/pages/manual/appenders.adoc | 20 +++++++
4 files changed, 110 insertions(+), 7 deletions(-)
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java
index e9959b1c04..93d409af92 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java
@@ -19,6 +19,7 @@ package org.apache.logging.log4j.core.appender;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -33,6 +34,7 @@ import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.ConsoleAppender.Target;
import org.apache.logging.log4j.core.impl.Log4jLogEvent;
import org.apache.logging.log4j.core.layout.PatternLayout;
+import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.message.SimpleMessage;
import org.apache.logging.log4j.util.Strings;
import org.junit.jupiter.api.BeforeEach;
@@ -139,6 +141,67 @@ public class ConsoleAppenderTest {
}
}
+ @Test
+ public void testBufferSizeHonored() {
+ final ConsoleAppender app = ConsoleAppender.newBuilder()
+ .setName("testBufferSizeHonored")
+ .setBufferSize(16384)
+ .build();
+ try {
+ assertNotNull(app.getManager());
+ assertEquals(16384, app.getManager().getByteBuffer().capacity());
+ } finally {
+ app.stop();
+ }
+ }
+
+ @Test
+ public void testDefaultBufferSize() {
+ final ConsoleAppender app =
+ ConsoleAppender.newBuilder().setName("testDefaultBufferSize").build();
+ try {
+ assertEquals(
+ Constants.ENCODER_BYTE_BUFFER_SIZE,
+ app.getManager().getByteBuffer().capacity());
+ } finally {
+ app.stop();
+ }
+ }
+
+ @Test
+ public void testUnbufferedIoForcesImmediateFlush() {
+ final ConsoleAppender app = ConsoleAppender.newBuilder()
+ .setName("testUnbufferedIoForcesImmediateFlush")
+ .setBufferedIo(false)
+ .setImmediateFlush(false)
+ .build();
+ try {
+ assertTrue(app.getImmediateFlush());
+ } finally {
+ app.stop();
+ }
+ }
+
+ @Test
+ public void testDifferentBufferSizesUseDifferentManagers() {
+ final ConsoleAppender app1 = ConsoleAppender.newBuilder()
+ .setName("testBufferSizeManager1")
+ .setTarget(Target.SYSTEM_ERR)
+ .setBufferSize(8192)
+ .build();
+ final ConsoleAppender app2 = ConsoleAppender.newBuilder()
+ .setName("testBufferSizeManager2")
+ .setTarget(Target.SYSTEM_ERR)
+ .setBufferSize(16384)
+ .build();
+ try {
+ assertNotSame(app1.getManager(), app2.getManager());
+ } finally {
+ app1.stop();
+ app2.stop();
+ }
+ }
+
@Test
public void testFollowSystemErr() {
testFollowSystemPrintStream(System.err, Target.SYSTEM_ERR, SystemSetter.SYSTEM_ERR);
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
index 6d4216c9fd..f19943625a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java
@@ -28,6 +28,7 @@ import org.apache.logging.log4j.core.Filter;
import org.apache.logging.log4j.core.Layout;
import org.apache.logging.log4j.core.config.Property;
import org.apache.logging.log4j.core.util.CloseShieldOutputStream;
+import org.apache.logging.log4j.core.util.Constants;
import org.apache.logging.log4j.plugins.Configurable;
import org.apache.logging.log4j.plugins.Plugin;
import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
@@ -173,16 +174,18 @@ public final class ConsoleAppender extends AbstractOutputStreamAppender<OutputSt
? getDirectOutputStream(target)
: follow ? getFollowOutputStream(target) : getDefaultOutputStream(target);
- final String managerName = target.name() + '.' + follow + '.' + direct;
- final OutputStreamManager manager =
- OutputStreamManager.getManager(managerName, new FactoryData(stream, managerName, layout), factory);
+ final boolean bufferedIo = isBufferedIo();
+ final int bufferSize = getBufferSize();
+ final String managerName = target.name() + '.' + follow + '.' + direct + '.' + bufferSize;
+ final OutputStreamManager manager = OutputStreamManager.getManager(
+ managerName, new FactoryData(stream, managerName, layout, bufferSize), factory);
return new ConsoleAppender(
getName(),
layout,
getFilter(),
manager,
isIgnoreExceptions(),
- isImmediateFlush(),
+ !bufferedIo || isImmediateFlush(),
target,
getPropertyArray());
}
@@ -193,7 +196,8 @@ public final class ConsoleAppender extends AbstractOutputStreamAppender<OutputSt
ConsoleAppender.DEFAULT_TARGET == Target.SYSTEM_ERR ? System.err : System.out);
// LOG4J2-1176 DefaultConfiguration should not share OutputStreamManager instances to avoid memory leaks.
final String managerName = ConsoleAppender.DEFAULT_TARGET.name() + ".false.false-" + COUNT.get();
- return OutputStreamManager.getManager(managerName, new FactoryData(os, managerName, layout), factory);
+ return OutputStreamManager.getManager(
+ managerName, new FactoryData(os, managerName, layout, Constants.ENCODER_BYTE_BUFFER_SIZE), factory);
}
private static OutputStream getDefaultOutputStream(Target target) {
@@ -280,6 +284,7 @@ public final class ConsoleAppender extends AbstractOutputStreamAppender<OutputSt
private final OutputStream os;
private final String name;
private final Layout layout;
+ private final int bufferSize;
/**
* Constructor.
@@ -287,11 +292,13 @@ public final class ConsoleAppender extends AbstractOutputStreamAppender<OutputSt
* @param os The OutputStream.
* @param type The name of the target.
* @param layout A layout
+ * @param bufferSize The buffer size.
*/
- public FactoryData(final OutputStream os, final String type, final Layout layout) {
+ public FactoryData(final OutputStream os, final String type, final Layout layout, final int bufferSize) {
this.os = os;
this.name = type;
this.layout = layout;
+ this.bufferSize = bufferSize;
}
}
@@ -309,7 +316,7 @@ public final class ConsoleAppender extends AbstractOutputStreamAppender<OutputSt
*/
@Override
public OutputStreamManager createManager(final String name, final FactoryData data) {
- return new OutputStreamManager(data.os, data.name, data.layout, true);
+ return new OutputStreamManager(data.os, data.name, data.layout, true, data.bufferSize);
}
}
diff --git a/src/changelog/.3.x.x/4338_console_buffer_size.xml b/src/changelog/.3.x.x/4338_console_buffer_size.xml
new file mode 100644
index 0000000000..ac3fa6dfe4
--- /dev/null
+++ b/src/changelog/.3.x.x/4338_console_buffer_size.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-changelog-0.xsd"
+ type="fixed">
+ <issue id="4338" link="https://github.com/apache/logging-log4j2/issues/4338"/>
+ <issue id="4342" link="https://github.com/apache/logging-log4j2/pull/4342"/>
+ <description format="asciidoc">
+ Honor the `bufferSize` and `bufferedIo` settings in `ConsoleAppender`.
+ </description>
+</entry>
diff --git a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc
index c7cb659092..d3660c7387 100644
--- a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc
@@ -249,6 +249,26 @@ Some application servers modify `System.out` and `System.err` to always point to
4+h| Optional
+| [[ConsoleAppender-attr-bufferSize]]bufferSize
+| `int`
+| xref:manual/systemproperties.adoc#log4j2.encoderByteBufferSize[`8192`]
+a|
+The size of the
+https://docs.oracle.com/javase/{java-target-version}/docs/api/java/nio/ByteBuffer.html[`ByteBuffer`]
+internally used by the appender.
+
+Appenders with different `bufferSize` values do not share the same manager.
+
+See <<buffering,Buffering>> for more details.
+
+| [[ConsoleAppender-attr-bufferedIo]]bufferedIo
+| `boolean`
+| `true`
+|
+If set to `true`, Log4j Core will format each log event in an internal buffer, before sending it to the underlying resource.
+
+See <<buffering,Buffering>> for more details.
+
| [[ConsoleAppender-attr-direct]]direct
| `boolean`
| `false`