From 0896da347c414e34dbe27adcbc60bcbdedaa3b8b Mon Sep 17 00:00:00 2001 From: Alexander Schwartz Date: Fri, 6 Feb 2026 16:41:08 +0100 Subject: [PATCH] Output lsof information on suspected leakage Closes #5944 --- .../core/FileDescriptorLeakDetectorRule.java | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/vertx-core/src/test/java/io/vertx/test/core/FileDescriptorLeakDetectorRule.java b/vertx-core/src/test/java/io/vertx/test/core/FileDescriptorLeakDetectorRule.java index 5c9cd3d0d76..bb449054cea 100644 --- a/vertx-core/src/test/java/io/vertx/test/core/FileDescriptorLeakDetectorRule.java +++ b/vertx-core/src/test/java/io/vertx/test/core/FileDescriptorLeakDetectorRule.java @@ -21,6 +21,9 @@ import javax.management.MBeanInfo; import javax.management.MBeanServer; import javax.management.ObjectName; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.lang.management.ManagementFactory; import java.util.ArrayList; import java.util.List; @@ -65,7 +68,7 @@ public Statement apply(Statement statement, Description description) { return new Statement() { @Override public void evaluate() throws Throwable { - + String lsofBefore = captureListOfOpenFiles(); //We do 40 runs. 20 to extract a baseline and 20 that will act as evaluation values //From baseline values we get the max and from evaluation values we get the average //If average is greater than max then we have a leak. @@ -99,7 +102,42 @@ public void evaluate() throws Throwable { openFd = openFd(); } - assertTrue("*** Open file descriptor open file descriptors average " + openFd + " > " + maxOpenFD, openFd <= maxOpenFD); + try { + assertTrue("*** Open file descriptor open file descriptors average " + openFd + " > " + maxOpenFD, openFd <= maxOpenFD); + } catch (AssertionError e) { + if (!lsofBefore.isBlank()) { + System.out.print("lsof before:\n" + lsofBefore); + System.out.print("\n\nlsof after:\n" + captureListOfOpenFiles()); + } + throw e; + } + } + + private String captureListOfOpenFiles() throws IOException, InterruptedException { + StringBuilder lsof = new StringBuilder(); + String[] pidAndHostname = ManagementFactory.getRuntimeMXBean().getName().split("@"); + if (pidAndHostname.length == 2) { + try { + Process exec = Runtime.getRuntime().exec(new String[]{"lsof", "-p", pidAndHostname[0]}); + String line; + try (BufferedReader stdout = new BufferedReader(new InputStreamReader(exec.getInputStream())); BufferedReader stderr = new BufferedReader(new InputStreamReader(exec.getInputStream()))) { + while ((line = stdout.readLine()) != null) { + lsof.append(line).append("\n"); + } + while ((line = stderr.readLine()) != null) { + System.err.println(line); + } + } catch (IOException ignored) { + } + int exitCode = exec.waitFor(); + if (exitCode != 0) { + System.err.println("lsof exited with " + exitCode); + } + } catch (IOException ignored) { + // lsof is not on the path + } + } + return lsof.toString(); } }; }