Index: log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java =================================================================== --- log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java (revision 1564542) +++ log4j-core/src/test/java/org/apache/logging/log4j/core/appender/ConsoleAppenderTest.java (working copy) @@ -16,6 +16,17 @@ */ package org.apache.logging.log4j.core.appender; +import static org.easymock.EasyMock.anyInt; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.expect; +import static org.easymock.EasyMock.expectLastCall; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + import org.apache.logging.log4j.Level; import org.apache.logging.log4j.core.Layout; import org.apache.logging.log4j.core.LogEvent; @@ -23,20 +34,20 @@ import org.apache.logging.log4j.core.impl.Log4jLogEvent; import org.apache.logging.log4j.core.layout.PatternLayout; import org.apache.logging.log4j.message.SimpleMessage; +import org.easymock.EasyMockSupport; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; -import static org.junit.Assert.*; - /** * */ public class ConsoleAppenderTest { private final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + EasyMockSupport mocks = new EasyMockSupport(); + PrintStream psMock = mocks.createMock("psMock", PrintStream.class); @BeforeClass public static void before() { @@ -67,6 +78,30 @@ app.stop(); assertFalse("Appender did not stop", app.isStarted()); } + + @Test + public void testConsoleStreamManagerDoesNotClose() { + final PrintStream ps = System.out; + + psMock.write((byte[]) anyObject(), anyInt(), anyInt()); + expectLastCall().anyTimes(); + psMock.flush(); + + mocks.replayAll(); + System.setOut(psMock); + final Layout layout = PatternLayout.createLayout(null, null, null, null, null, null); + final ConsoleAppender app = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false", "false"); + app.start(); + assertTrue("Appender did not start", app.isStarted()); + final LogEvent event = new Log4jLogEvent("TestLogger", null, ConsoleAppenderTest.class.getName(), Level.INFO, + new SimpleMessage("Test"), null); + app.append(event); + + app.stop(); + assertFalse("Appender did not stop", app.isStarted()); + System.setOut(ps); + mocks.verifyAll(); + } } Index: log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java =================================================================== --- log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java (revision 1564542) +++ log4j-core/src/main/java/org/apache/logging/log4j/core/appender/OutputStreamManager.java (working copy) @@ -131,9 +131,6 @@ protected synchronized void close() { final OutputStream stream = os; // access volatile field only once per method - if (stream == System.out || stream == System.err) { - return; - } try { stream.close(); } catch (final IOException ex) { Index: log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java =================================================================== --- log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java (revision 1564551) +++ log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java (working copy) @@ -18,11 +18,8 @@ import java.io.IOException; import java.io.OutputStream; -import java.io.PrintStream; import java.io.Serializable; -import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; -import java.nio.charset.Charset; import org.apache.logging.log4j.core.Filter; import org.apache.logging.log4j.core.Layout; @@ -106,26 +103,23 @@ } private static OutputStream getOutputStream(final boolean follow, final Target target) { - final String enc = Charset.defaultCharset().name(); - PrintStream printStream = null; - try { - printStream = target == Target.SYSTEM_OUT ? - follow ? new PrintStream(new SystemOutStream(), true, enc) : System.out : - follow ? new PrintStream(new SystemErrStream(), true, enc) : System.err; - } catch (final UnsupportedEncodingException ex) { // should never happen - throw new IllegalStateException("Unsupported default encoding " + enc, ex); + final OutputStream stream; + if (target == Target.SYSTEM_OUT) { + stream = follow ? new SystemOutStream() : System.out; + } else { + stream = follow ? new SystemErrStream() : System.err; } final PropertiesUtil propsUtil = PropertiesUtil.getProperties(); if (!propsUtil.getStringProperty("os.name").startsWith("Windows") || propsUtil.getBooleanProperty("log4j.skipJansi")) { - return printStream; + return stream; } try { final ClassLoader loader = Loader.getClassLoader(); // We type the parameter as a wildcard to avoid a hard reference to Jansi. final Class clazz = loader.loadClass(JANSI_CLASS); final Constructor constructor = clazz.getConstructor(OutputStream.class); - return (OutputStream) constructor.newInstance(printStream); + return (OutputStream) constructor.newInstance(stream); } catch (final ClassNotFoundException cnfe) { LOGGER.debug("Jansi is not installed, cannot find {}", JANSI_CLASS); } catch (final NoSuchMethodException nsme) { @@ -133,7 +127,7 @@ } catch (final Exception ex) { LOGGER.warn("Unable to instantiate {}", JANSI_CLASS); } - return printStream; + return stream; } /** @@ -238,8 +232,23 @@ */ @Override public OutputStreamManager createManager(final String name, final FactoryData data) { - return new OutputStreamManager(data.os, data.type, data.layout); + return new ConsoleStreamManager(data.os, data.type, data.layout); } } + + /** + * Prevents the closing of system streams + */ + private static class ConsoleStreamManager extends OutputStreamManager { + protected ConsoleStreamManager(OutputStream os, String streamName, Layout layout) { + super(os, streamName, layout); + } + + @Override + protected synchronized void close() { + // do not close sys err or sys out + } + + } }