This is an automated email from the ASF dual-hosted git repository.

benedict pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/trunk by this push:
     new a43b651  Unit test stdout capture is malfunctioning in 4.0
a43b651 is described below

commit a43b651f8e35dd7081b8593057f118ed0c49cfd6
Author: Benedict Elliott Smith <bened...@apache.org>
AuthorDate: Thu Jan 10 12:32:16 2019 -0500

    Unit test stdout capture is malfunctioning in 4.0
    
    patch by Benedict; reviewed by Alex Petrov for CASSANDRA-14974
---
 test/conf/logback-dtest.xml                        |   2 +-
 test/conf/logback-test.xml                         |   2 +-
 .../cassandra/distributed/InstanceClassLoader.java |  14 +-
 .../apache/cassandra/distributed/TestCluster.java  |   9 +
 .../apache/cassandra/LogbackStatusListener.java    | 770 ++++++++++++---------
 .../config/DatabaseDescriptorRefTest.java          |  18 +-
 6 files changed, 465 insertions(+), 350 deletions(-)

diff --git a/test/conf/logback-dtest.xml b/test/conf/logback-dtest.xml
index b8019f6..7d3a8be 100644
--- a/test/conf/logback-dtest.xml
+++ b/test/conf/logback-dtest.xml
@@ -41,8 +41,8 @@
 
     <encoder>
       <pattern>%-5level [%thread] ${instance_id} %date{ISO8601} 
%msg%n</pattern>
-      <immediateFlush>false</immediateFlush>
     </encoder>
+    <immediateFlush>false</immediateFlush>
   </appender>
 
   <appender name="STDOUT" target="System.out" 
class="org.apache.cassandra.ConsoleAppender">
diff --git a/test/conf/logback-test.xml b/test/conf/logback-test.xml
index 4092050..3e3349f 100644
--- a/test/conf/logback-test.xml
+++ b/test/conf/logback-test.xml
@@ -39,8 +39,8 @@
 
     <encoder>
       <pattern>%-5level [%thread] %date{ISO8601} %msg%n</pattern>
-      <immediateFlush>false</immediateFlush>
     </encoder>
+    <immediateFlush>false</immediateFlush>
   </appender>
 
   <appender name="STDOUT" target="System.out" 
class="org.apache.cassandra.ConsoleAppender">
diff --git 
a/test/distributed/org/apache/cassandra/distributed/InstanceClassLoader.java 
b/test/distributed/org/apache/cassandra/distributed/InstanceClassLoader.java
index 6349d5a..c86728a 100644
--- a/test/distributed/org/apache/cassandra/distributed/InstanceClassLoader.java
+++ b/test/distributed/org/apache/cassandra/distributed/InstanceClassLoader.java
@@ -37,12 +37,12 @@ public class InstanceClassLoader extends URLClassLoader
                     InstanceConfig.class,
                     Message.class,
                     InetAddressAndPort.class,
+                    InvokableInstance.SerializableBiConsumer.class,
+                    InvokableInstance.SerializableBiFunction.class,
                     InvokableInstance.SerializableCallable.class,
-                    InvokableInstance.SerializableRunnable.class,
                     InvokableInstance.SerializableConsumer.class,
-                    InvokableInstance.SerializableBiConsumer.class,
                     InvokableInstance.SerializableFunction.class,
-                    InvokableInstance.SerializableBiFunction.class,
+                    InvokableInstance.SerializableRunnable.class,
                     InvokableInstance.SerializableTriFunction.class,
                     InvokableInstance.InstanceFunction.class
             };
@@ -98,4 +98,12 @@ public class InstanceClassLoader extends URLClassLoader
         return id -> new InstanceClassLoader(id, urls, 
commonClassNames::contains, contextClassLoader);
     }
 
+    /**
+     * @return true iff this class was loaded by an InstanceClassLoader, and 
as such is used by a dtest node
+     */
+    public static boolean wasLoadedByAnInstanceClassLoader(Class<?> clazz)
+    {
+        return 
clazz.getClassLoader().getClass().getName().equals(InstanceClassLoader.class.getName());
+    }
+
 }
diff --git a/test/distributed/org/apache/cassandra/distributed/TestCluster.java 
b/test/distributed/org/apache/cassandra/distributed/TestCluster.java
index 5056661..9f95a86 100644
--- a/test/distributed/org/apache/cassandra/distributed/TestCluster.java
+++ b/test/distributed/org/apache/cassandra/distributed/TestCluster.java
@@ -39,6 +39,10 @@ import java.util.stream.Collectors;
 
 import com.google.common.collect.Sets;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.cassandra.concurrent.NamedThreadFactory;
 import org.apache.cassandra.db.ColumnFamilyStore;
 import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.db.Keyspace;
@@ -76,6 +80,11 @@ import org.apache.cassandra.utils.concurrent.SimpleCondition;
  */
 public class TestCluster implements AutoCloseable
 {
+    // WARNING: we have this logger not (necessarily) for logging, but
+    // to ensure we have instantiated the main classloader's LoggerFactory 
(and any LogbackStatusListener)
+    // before we instantiate any for a new instance
+    private static final Logger logger = 
LoggerFactory.getLogger(TestCluster.class);
+
     private final File root;
     private final List<Instance> instances;
     private final Coordinator coordinator;
diff --git a/test/unit/org/apache/cassandra/LogbackStatusListener.java 
b/test/unit/org/apache/cassandra/LogbackStatusListener.java
index 756f7eb..0ec73d9 100644
--- a/test/unit/org/apache/cassandra/LogbackStatusListener.java
+++ b/test/unit/org/apache/cassandra/LogbackStatusListener.java
@@ -21,434 +21,518 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
 import java.util.Locale;
 
+import org.slf4j.ILoggerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.LoggerContextListener;
 import ch.qos.logback.core.status.Status;
 import ch.qos.logback.core.status.StatusListener;
+import org.apache.cassandra.distributed.InstanceClassLoader;
 
 /*
  * Listen for logback readiness and then redirect stdout/stderr to logback
  */
-public class LogbackStatusListener implements StatusListener
+public class LogbackStatusListener implements StatusListener, 
LoggerContextListener
 {
 
     public static final PrintStream originalOut = System.out;
-
     public static final PrintStream originalErr = System.err;
 
-    private boolean hadError = false;
+    private volatile boolean hadPreInstallError = false;
+    private volatile boolean haveInstalled = false;
+    private volatile boolean haveRegisteredListener = false;
 
     private PrintStream replacementOut;
-
     private PrintStream replacementErr;
 
     @Override
     public void addStatusEvent(Status s)
     {
-        if (s.getLevel() != 0 || s.getEffectiveLevel() != 0)
-            hadError = true;
+        if (!haveInstalled && (s.getLevel() != 0 || s.getEffectiveLevel() != 
0))
+        {
+            // if we encounter an error during setup, we're not sure what 
state we're in, so we just don't switch
+            // we should log this fact, though, so that we know that we're not 
necessarily capturing stdout
+            LoggerFactory.getLogger(LogbackStatusListener.class)
+                         .warn("Encountered non-info status in logger setup; 
aborting stdout capture: '" + s.getMessage() + '\'');
+            hadPreInstallError = true;
+        }
 
-        if (!hadError && s.getMessage().equals("Registering current 
configuration as safe fallback point"))
+        if (hadPreInstallError)
+            return;
+
+        if (s.getMessage().startsWith("Registering current configuration as 
safe fallback point"))
         {
-            try
-            {
-                installReplacementStreams();
-            }
-            catch (Exception e)
-            {
-                throw new RuntimeException(e);
-            }
+            onStart(null);
+        }
+
+        if (haveInstalled && !haveRegisteredListener)
+        {
+            // we register ourselves as a listener after the fact, because we 
enable ourselves before the LoggerFactory
+            // is properly initialised, hence before it can accept any 
LoggerContextListener registrations
+            tryRegisterListener();
         }
 
         if (s.getMessage().equals("Logback context being closed via shutdown 
hook"))
         {
-            if (replacementOut != null) replacementOut.flush();
-            if (replacementErr != null) replacementErr.flush();
-            System.setErr(originalErr);
-            System.setOut(originalOut);
+            onStop(null);
         }
     }
 
-    private void installReplacementStreams() throws Exception
+    private static PrintStream wrapLogger(Logger logger, PrintStream original, 
String encodingProperty, boolean error) throws Exception
     {
-        Logger stdoutLogger = LoggerFactory.getLogger("stdout");
-        Logger stderrLogger = LoggerFactory.getLogger("stderr");
-
-        replacementOut = wrapLogger(stdoutLogger, originalOut, 
"sun.stdout.encoding", false);
-        System.setOut(replacementOut);
-        replacementErr = wrapLogger(stderrLogger, originalErr, 
"sun.stderr.encoding", true);
-        System.setErr(replacementErr);
+        final String encoding = System.getProperty(encodingProperty);
+        OutputStream os = new ToLoggerOutputStream(logger, encoding, error);
+        return encoding != null ? new WrappedPrintStream(os, true, encoding, 
original)
+                                : new WrappedPrintStream(os, true, original);
     }
 
-    private static PrintStream wrapLogger(final Logger logger, final 
PrintStream original, String encodingProperty, boolean error) throws Exception
+    private static class ToLoggerOutputStream extends ByteArrayOutputStream
     {
-        final String encoding = System.getProperty(encodingProperty);
-        OutputStream os = new OutputStream()
-        {
+        final Logger logger;
+        final String encoding;
+        final boolean error;
 
-            ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
-            @Override
-            public void write(int b) throws IOException
-            {
-                baos.write(b);
-            }
-
-            @Override
-            public void write(byte[] b, int offset, int length)
-            {
-                baos.write(b,  offset, length);
-            }
+        private ToLoggerOutputStream(Logger logger, String encoding, boolean 
error)
+        {
+            this.logger = logger;
+            this.encoding = encoding;
+            this.error = error;
+        }
 
-            @Override
-            public void write(byte[] b)
+        @Override
+        public void flush() throws IOException
+        {
+            try
             {
-                write(b, 0, b.length);
-            }
+                //Filter out stupid PrintStream empty flushes
+                if (size() == 0) return;
 
-            @Override
-            public void flush() throws IOException
-            {
-                try
+                //Filter out newlines, log framework provides its own
+                if (size() == 1)
                 {
-                    //Filter out stupid PrintStream empty flushes
-                    if (baos.size() == 0) return;
-
-                    //Filter out newlines, log framework provides its own
-                    if (baos.size() == 1)
-                    {
-                        byte[] bytes = baos.toByteArray();
-                        if (bytes[0] == 0xA)
-                            return;
-                    }
-
-                    //Filter out Windows newline
-                    if (baos.size() == 2)
-                    {
-                        byte[] bytes = baos.toByteArray();
-                        if (bytes[0] == 0xD && bytes[1] == 0xA)
-                            return;
-                    }
-
-                    String statement;
-                    if (encoding != null)
-                        statement = new String(baos.toByteArray(), encoding);
-                    else
-                        statement = new String(baos.toByteArray());
-
-                    if (error)
-                        logger.error(statement);
-                    else
-                        logger.info(statement);
+                    byte[] bytes = toByteArray();
+                    if (bytes[0] == 0xA)
+                        return;
                 }
-                finally
+
+                //Filter out Windows newline
+                if (size() == 2)
                 {
-                    baos.reset();
+                    byte[] bytes = toByteArray();
+                    if (bytes[0] == 0xD && bytes[1] == 0xA)
+                        return;
                 }
-            }
-        };
-
-        if (encoding != null)
-            return new PrintStream(os, true, encoding);
-        return new PrintStream(os, true)
-        {
-
-            private long asyncAppenderThreadId = Long.MIN_VALUE;
-
-            /*
-             * Long and the short of it is that we don't want to serve logback 
a fake System.out/err.
-             * ConsoleAppender is replaced so it always goes to the real 
System.out/err, but logback itself
-             * will at times try to log to System.out/err when it has issues.
-             *
-             * Now here is the problem. There is a deadlock if a thread logs 
to System.out, blocks on the async
-             * appender queue, and the async appender thread tries to log to 
System.out directly as part of some
-             * internal logback issue.
-             *
-             * So to prevent this we have to exhaustively check before locking 
in the PrintStream and forward
-             * to real System.out/err if it is the async appender
-             */
-            private boolean isAsyncAppender()
-            {
-                //Set the thread id based on the name
-                if (asyncAppenderThreadId == Long.MIN_VALUE)
-                        asyncAppenderThreadId = 
Thread.currentThread().getName().equals("AsyncAppender-Worker-ASYNC") ? 
Thread.currentThread().getId() : asyncAppenderThreadId;
-                if (Thread.currentThread().getId() == asyncAppenderThreadId)
-                    original.println("Was in async appender");
-                return Thread.currentThread().getId() == asyncAppenderThreadId;
-            }
 
-            @Override
-            public void flush()
-            {
-                if (isAsyncAppender())
-                    original.flush();
+                String statement;
+                if (encoding != null)
+                    statement = new String(toByteArray(), encoding);
                 else
-                    super.flush();
-            }
+                    statement = new String(toByteArray());
 
-            @Override
-            public void close()
-            {
-                if (isAsyncAppender())
-                    original.close();
+                if (error)
+                    logger.error(statement);
                 else
-                    super.flush();
+                    logger.info(statement);
             }
-
-            @Override
-            public void write(int b)
+            finally
             {
-                if (isAsyncAppender())
-                    original.write(b);
-                else
-                    super.write(b);
+                reset();
             }
+        }
+    };
 
-            @Override
-            public void write(byte[] buf, int off, int len)
-            {
-                if (isAsyncAppender())
-                    original.write(buf, off, len);
-                else
-                    super.write(buf, off, len);
-            }
+    private static class WrappedPrintStream extends PrintStream
+    {
+        private long asyncAppenderThreadId = Long.MIN_VALUE;
+        private final PrintStream original;
 
-            @Override
-            public void print(boolean b)
-            {
-                if (isAsyncAppender())
-                    original.print(b);
-                else
-                    super.print(b);
-            }
+        public WrappedPrintStream(OutputStream out, boolean autoFlush, 
PrintStream original)
+        {
+            super(out, autoFlush);
+            this.original = original;
+        }
 
-            @Override
-            public void print(char c)
-            {
-                if (isAsyncAppender())
-                    original.print(c);
-                else
-                    super.print(c);
-            }
+        public WrappedPrintStream(OutputStream out, boolean autoFlush, String 
encoding, PrintStream original) throws UnsupportedEncodingException
+        {
+            super(out, autoFlush, encoding);
+            this.original = original;
+        }
 
-            @Override
-            public void print(int i)
-            {
-                if (isAsyncAppender())
-                    original.print(i);
-                else
-                    super.print(i);
-            }
+        /*
+         * Long and the short of it is that we don't want to serve logback a 
fake System.out/err.
+         * ConsoleAppender is replaced so it always goes to the real 
System.out/err, but logback itself
+         * will at times try to log to System.out/err when it has issues.
+         *
+         * Now here is the problem. There is a deadlock if a thread logs to 
System.out, blocks on the async
+         * appender queue, and the async appender thread tries to log to 
System.out directly as part of some
+         * internal logback issue.
+         *
+         * So to prevent this we have to exhaustively check before locking in 
the PrintStream and forward
+         * to real System.out/err if it is the async appender
+         */
+        private boolean isAsyncAppender()
+        {
+            //Set the thread id based on the name
+            Thread currentThread = Thread.currentThread();
+            long currentThreadId = currentThread.getId();
+            if (asyncAppenderThreadId == Long.MIN_VALUE &&
+                currentThread.getName().equals("AsyncAppender-Worker-ASYNC") &&
+                
!InstanceClassLoader.wasLoadedByAnInstanceClassLoader(currentThread.getClass()))
+            {
+                asyncAppenderThreadId = currentThreadId;
+            }
+            if (currentThreadId == asyncAppenderThreadId)
+                original.println("Was in async appender");
+            return currentThreadId == asyncAppenderThreadId;
+        }
 
-            @Override
-            public void print(long l)
-            {
-                if (isAsyncAppender())
-                    original.print(l);
-                else
-                    super.print(l);
-            }
+        @Override
+        public void flush()
+        {
+            if (isAsyncAppender())
+                original.flush();
+            else
+                super.flush();
+        }
 
-            @Override
-            public void print(float f)
-            {
-                if (isAsyncAppender())
-                    original.print(f);
-                else
-                    super.print(f);
-            }
+        @Override
+        public void close()
+        {
+            if (isAsyncAppender())
+                original.close();
+            else
+                super.flush();
+        }
 
-            @Override
-            public void print(double d)
-            {
-                if (isAsyncAppender())
-                    original.print(d);
-                else
-                    super.print(d);
-            }
+        @Override
+        public void write(int b)
+        {
+            if (isAsyncAppender())
+                original.write(b);
+            else
+                super.write(b);
+        }
 
-            @Override
-            public void print(char[] s)
-            {
-                if(isAsyncAppender())
-                    original.println(s);
-                else
-                    super.print(s);
-            }
+        @Override
+        public void write(byte[] buf, int off, int len)
+        {
+            if (isAsyncAppender())
+                original.write(buf, off, len);
+            else
+                super.write(buf, off, len);
+        }
 
-            @Override
-            public void print(String s)
-            {
-                if (isAsyncAppender())
-                    original.print(s);
-                else
-                    super.print(s);
-            }
+        @Override
+        public void print(boolean b)
+        {
+            if (isAsyncAppender())
+                original.print(b);
+            else
+                super.print(b);
+        }
 
-            @Override
-            public void print(Object obj)
-            {
-                if (isAsyncAppender())
-                    original.print(obj);
-                else
-                    super.print(obj);
-            }
+        @Override
+        public void print(char c)
+        {
+            if (isAsyncAppender())
+                original.print(c);
+            else
+                super.print(c);
+        }
 
-            @Override
-            public void println()
-            {
-                if (isAsyncAppender())
-                    original.println();
-                else
-                    super.println();
-            }
+        @Override
+        public void print(int i)
+        {
+            if (isAsyncAppender())
+                original.print(i);
+            else
+                super.print(i);
+        }
 
-            @Override
-            public void println(boolean v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void print(long l)
+        {
+            if (isAsyncAppender())
+                original.print(l);
+            else
+                super.print(l);
+        }
 
-            @Override
-            public void println(char v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void print(float f)
+        {
+            if (isAsyncAppender())
+                original.print(f);
+            else
+                super.print(f);
+        }
 
-            @Override
-            public void println(int v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void print(double d)
+        {
+            if (isAsyncAppender())
+                original.print(d);
+            else
+                super.print(d);
+        }
 
-            @Override
-            public void println(long v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void print(char[] s)
+        {
+            if(isAsyncAppender())
+                original.println(s);
+            else
+                super.print(s);
+        }
 
-            @Override
-            public void println(float v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void print(String s)
+        {
+            if (isAsyncAppender())
+                original.print(s);
+            else
+                super.print(s);
+        }
 
-            @Override
-            public void println(double v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void print(Object obj)
+        {
+            if (isAsyncAppender())
+                original.print(obj);
+            else
+                super.print(obj);
+        }
 
-            @Override
-            public void println(char[] v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void println()
+        {
+            if (isAsyncAppender())
+                original.println();
+            else
+                super.println();
+        }
 
-            @Override
-            public void println(String v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void println(boolean v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
 
-            @Override
-            public void println(Object v)
-            {
-                if (isAsyncAppender())
-                    original.println(v);
-                else
-                    super.println(v);
-            }
+        @Override
+        public void println(char v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
 
-            @Override
-            public PrintStream printf(String format, Object... args)
-            {
-                if (isAsyncAppender())
-                    return original.printf(format, args);
-                else
-                    return super.printf(format, args);
-            }
+        @Override
+        public void println(int v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
 
-            @Override
-            public PrintStream printf(Locale l, String format, Object... args)
-            {
-                if (isAsyncAppender())
-                    return original.printf(l, format, args);
-                else
-                    return super.printf(l, format, args);
-            }
+        @Override
+        public void println(long v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
 
-            @Override
-            public PrintStream format(String format, Object... args)
-            {
-                if (isAsyncAppender())
-                    return original.format(format, args);
-                else
-                    return super.format(format, args);
-            }
+        @Override
+        public void println(float v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
+
+        @Override
+        public void println(double v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
+
+        @Override
+        public void println(char[] v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
+
+        @Override
+        public void println(String v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
 
-            @Override
-            public PrintStream format(Locale l, String format, Object... args)
+        @Override
+        public void println(Object v)
+        {
+            if (isAsyncAppender())
+                original.println(v);
+            else
+                super.println(v);
+        }
+
+        @Override
+        public PrintStream printf(String format, Object... args)
+        {
+            if (isAsyncAppender())
+                return original.printf(format, args);
+            else
+                return super.printf(format, args);
+        }
+
+        @Override
+        public PrintStream printf(Locale l, String format, Object... args)
+        {
+            if (isAsyncAppender())
+                return original.printf(l, format, args);
+            else
+                return super.printf(l, format, args);
+        }
+
+        @Override
+        public PrintStream format(String format, Object... args)
+        {
+            if (isAsyncAppender())
+                return original.format(format, args);
+            else
+                return super.format(format, args);
+        }
+
+        @Override
+        public PrintStream format(Locale l, String format, Object... args)
+        {
+            if (isAsyncAppender())
+                return original.format(l, format, args);
+            else
+                return super.format(l, format, args);
+        }
+
+        @Override
+        public PrintStream append(CharSequence csq)
+        {
+            if (isAsyncAppender())
+                return original.append(csq);
+            else
+                return super.append(csq);
+        }
+
+        @Override
+        public PrintStream append(CharSequence csq, int start, int end)
+        {
+            if (isAsyncAppender())
+                return original.append(csq, start, end);
+            else
+                return super.append(csq, start, end);
+        }
+
+        @Override
+        public PrintStream append(char c)
+        {
+            if (isAsyncAppender())
+                return original.append(c);
+            else
+                return super.append(c);
+        }    }
+
+    public boolean isResetResistant()
+    {
+        return false;
+    }
+
+    public synchronized void onStart(LoggerContext loggerContext)
+    {
+        if (!hadPreInstallError && !haveInstalled)
+        {
+            if 
(InstanceClassLoader.wasLoadedByAnInstanceClassLoader(getClass())
+                || 
System.out.getClass().getName().contains("LogbackStatusListener"))
             {
-                if (isAsyncAppender())
-                    return original.format(l, format, args);
-                else
-                    return super.format(l, format, args);
+                // don't operate if we're a dtest node, or if we're not the 
first to swap System.out for some other reason
+                hadPreInstallError = true;
+                return;
             }
+            try
+            {
+                Logger stdoutLogger = LoggerFactory.getLogger("stdout");
+                Logger stderrLogger = LoggerFactory.getLogger("stderr");
 
-            @Override
-            public PrintStream append(CharSequence csq)
+                replacementOut = wrapLogger(stdoutLogger, originalOut, 
"sun.stdout.encoding", false);
+                System.setOut(replacementOut);
+                replacementErr = wrapLogger(stderrLogger, originalErr, 
"sun.stderr.encoding", true);
+                System.setErr(replacementErr);
+            }
+            catch (Exception e)
             {
-                if (isAsyncAppender())
-                    return original.append(csq);
-                else
-                    return super.append(csq);
+                throw new RuntimeException(e);
             }
+            haveInstalled = true;
+        }
+    }
 
-            @Override
-            public PrintStream append(CharSequence csq, int start, int end)
+    public synchronized void onReset(LoggerContext loggerContext)
+    {
+        onStop(loggerContext);
+    }
+
+    public synchronized void onStop(LoggerContext loggerContext)
+    {
+        if (haveInstalled)
+        {
+            if (replacementOut != null) replacementOut.flush();
+            if (replacementErr != null) replacementErr.flush();
+            System.setErr(originalErr);
+            System.setOut(originalOut);
+            hadPreInstallError = false;
+            haveInstalled = false;
+            haveRegisteredListener = false;
+            if (haveRegisteredListener)
             {
-                if (isAsyncAppender())
-                    return original.append(csq, start, end);
-                else
-                    return super.append(csq, start, end);
+                
((LoggerContext)LoggerFactory.getILoggerFactory()).removeListener(this);
             }
+        }
+    }
 
-            @Override
-            public PrintStream append(char c)
+    public void onLevelChange(ch.qos.logback.classic.Logger logger, Level 
level)
+    {
+    }
+
+    private synchronized void tryRegisterListener()
+    {
+        if (haveInstalled && !haveRegisteredListener)
+        {
+            ILoggerFactory factory = LoggerFactory.getILoggerFactory();
+            if (factory instanceof LoggerContext)
             {
-                if (isAsyncAppender())
-                    return original.append(c);
-                else
-                    return super.append(c);
+                ((LoggerContext) factory).addListener(this);
+                haveRegisteredListener = true;
             }
-        };
+        }
     }
 }
diff --git 
a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java 
b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
index f23e909..4a11f1d 100644
--- a/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
+++ b/test/unit/org/apache/cassandra/config/DatabaseDescriptorRefTest.java
@@ -87,6 +87,20 @@ public class DatabaseDescriptorRefTest
     "org.apache.cassandra.config.TransparentDataEncryptionOptions",
     "org.apache.cassandra.db.ConsistencyLevel",
     "org.apache.cassandra.dht.IPartitioner",
+    "org.apache.cassandra.distributed.InstanceClassLoader",
+    "org.apache.cassandra.distributed.InstanceConfig",
+    "org.apache.cassandra.distributed.InvokableInstance",
+    "org.apache.cassandra.distributed.InvokableInstance$CallableNoExcept",
+    "org.apache.cassandra.distributed.InvokableInstance$InstanceFunction",
+    
"org.apache.cassandra.distributed.InvokableInstance$SerializableBiConsumer",
+    
"org.apache.cassandra.distributed.InvokableInstance$SerializableBiFunction",
+    "org.apache.cassandra.distributed.InvokableInstance$SerializableCallable",
+    "org.apache.cassandra.distributed.InvokableInstance$SerializableConsumer",
+    "org.apache.cassandra.distributed.InvokableInstance$SerializableFunction",
+    "org.apache.cassandra.distributed.InvokableInstance$SerializableRunnable",
+    
"org.apache.cassandra.distributed.InvokableInstance$SerializableTriFunction",
+    "org.apache.cassandra.distributed.InvokableInstance$TriFunction",
+    "org.apache.cassandra.distributed.Message",
     "org.apache.cassandra.exceptions.ConfigurationException",
     "org.apache.cassandra.exceptions.RequestValidationException",
     "org.apache.cassandra.exceptions.CassandraException",
@@ -118,8 +132,8 @@ public class DatabaseDescriptorRefTest
     "org.apache.cassandra.ConsoleAppender",
     "org.apache.cassandra.ConsoleAppender$1",
     "org.apache.cassandra.LogbackStatusListener",
-    "org.apache.cassandra.LogbackStatusListener$1",
-    "org.apache.cassandra.LogbackStatusListener$2",
+    "org.apache.cassandra.LogbackStatusListener$ToLoggerOutputStream",
+    "org.apache.cassandra.LogbackStatusListener$WrappedPrintStream",
     "org.apache.cassandra.TeeingAppender",
     "org.apache.cassandra.audit.IAuditLogger",
     "org.apache.cassandra.audit.BinAuditLogger",


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to