TESTS: Check for Netty resource leaks (#31861)
* Enabled advanced leak detection when loading `EsTestCase` * Added custom `Appender` to collect leak logs and check for logged errors in a way similar to what is done for the `StatusLogger` * Fixes #20398
This commit is contained in:
parent
a9a9598e02
commit
24068a773d
|
@ -32,8 +32,12 @@ import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter;
|
||||||
import org.apache.logging.log4j.Level;
|
import org.apache.logging.log4j.Level;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.apache.logging.log4j.core.Appender;
|
||||||
|
import org.apache.logging.log4j.core.LogEvent;
|
||||||
import org.apache.logging.log4j.core.LoggerContext;
|
import org.apache.logging.log4j.core.LoggerContext;
|
||||||
|
import org.apache.logging.log4j.core.appender.AbstractAppender;
|
||||||
import org.apache.logging.log4j.core.config.Configurator;
|
import org.apache.logging.log4j.core.config.Configurator;
|
||||||
|
import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||||
import org.apache.logging.log4j.status.StatusConsoleListener;
|
import org.apache.logging.log4j.status.StatusConsoleListener;
|
||||||
import org.apache.logging.log4j.status.StatusData;
|
import org.apache.logging.log4j.status.StatusData;
|
||||||
import org.apache.logging.log4j.status.StatusLogger;
|
import org.apache.logging.log4j.status.StatusLogger;
|
||||||
|
@ -183,6 +187,8 @@ public abstract class ESTestCase extends LuceneTestCase {
|
||||||
|
|
||||||
private static final AtomicInteger portGenerator = new AtomicInteger();
|
private static final AtomicInteger portGenerator = new AtomicInteger();
|
||||||
|
|
||||||
|
private static final Collection<String> nettyLoggedLeaks = new ArrayList<>();
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void resetPortCounter() {
|
public static void resetPortCounter() {
|
||||||
portGenerator.set(0);
|
portGenerator.set(0);
|
||||||
|
@ -192,8 +198,28 @@ public abstract class ESTestCase extends LuceneTestCase {
|
||||||
System.setProperty("log4j.shutdownHookEnabled", "false");
|
System.setProperty("log4j.shutdownHookEnabled", "false");
|
||||||
System.setProperty("log4j2.disable.jmx", "true");
|
System.setProperty("log4j2.disable.jmx", "true");
|
||||||
|
|
||||||
|
// Enable Netty leak detection and monitor logger for logged leak errors
|
||||||
|
System.setProperty("io.netty.leakDetection.level", "advanced");
|
||||||
|
String leakLoggerName = "io.netty.util.ResourceLeakDetector";
|
||||||
|
Logger leakLogger = LogManager.getLogger(leakLoggerName);
|
||||||
|
Appender leakAppender = new AbstractAppender(leakLoggerName, null,
|
||||||
|
PatternLayout.newBuilder().withPattern("%m").build()) {
|
||||||
|
@Override
|
||||||
|
public void append(LogEvent event) {
|
||||||
|
String message = event.getMessage().getFormattedMessage();
|
||||||
|
if (Level.ERROR.equals(event.getLevel()) && message.contains("LEAK:")) {
|
||||||
|
synchronized (nettyLoggedLeaks) {
|
||||||
|
nettyLoggedLeaks.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
leakAppender.start();
|
||||||
|
Loggers.addAppender(leakLogger, leakAppender);
|
||||||
|
|
||||||
// shutdown hook so that when the test JVM exits, logging is shutdown too
|
// shutdown hook so that when the test JVM exits, logging is shutdown too
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
|
||||||
|
leakAppender.stop();
|
||||||
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
||||||
Configurator.shutdown(context);
|
Configurator.shutdown(context);
|
||||||
}));
|
}));
|
||||||
|
@ -440,6 +466,13 @@ public abstract class ESTestCase extends LuceneTestCase {
|
||||||
statusData.clear();
|
statusData.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
synchronized (nettyLoggedLeaks) {
|
||||||
|
try {
|
||||||
|
assertThat(nettyLoggedLeaks, empty());
|
||||||
|
} finally {
|
||||||
|
nettyLoggedLeaks.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this must be a separate method from other ensure checks above so suite scoped integ tests can call...TODO: fix that
|
// this must be a separate method from other ensure checks above so suite scoped integ tests can call...TODO: fix that
|
||||||
|
|
Loading…
Reference in New Issue