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