This is an automated email from the ASF dual-hosted git repository.
dsmiley pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 8498273a9b9 SOLR-18218: Improve ExecutorUtil error logging (#4399)
8498273a9b9 is described below
commit 8498273a9b9577b45e3a6394af1b180c2e863494
Author: Nazerke Seidan <[email protected]>
AuthorDate: Sat May 9 08:17:53 2026 +0500
SOLR-18218: Improve ExecutorUtil error logging (#4399)
---
.../manager/consumer/KafkaCrossDcConsumer.java | 3 ++-
.../org/apache/solr/common/util/ExecutorUtil.java | 31 ++++++++++++++++++++--
.../solr/common/util/SolrNamedThreadFactory.java | 7 +++++
.../apache/solr/common/util/ExecutorUtilTest.java | 13 +++++++++
4 files changed, 51 insertions(+), 3 deletions(-)
diff --git
a/solr/cross-dc-manager/src/java/org/apache/solr/crossdc/manager/consumer/KafkaCrossDcConsumer.java
b/solr/cross-dc-manager/src/java/org/apache/solr/crossdc/manager/consumer/KafkaCrossDcConsumer.java
index d368151c6af..31c2615e77f 100644
---
a/solr/cross-dc-manager/src/java/org/apache/solr/crossdc/manager/consumer/KafkaCrossDcConsumer.java
+++
b/solr/cross-dc-manager/src/java/org/apache/solr/crossdc/manager/consumer/KafkaCrossDcConsumer.java
@@ -51,6 +51,7 @@ import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.common.util.IOUtils;
+import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.crossdc.common.CrossDcConf;
import org.apache.solr.crossdc.common.IQueueHandler;
import org.apache.solr.crossdc.common.KafkaCrossDcConf;
@@ -96,7 +97,7 @@ public class KafkaCrossDcConsumer extends
Consumer.CrossDcConsumer {
private final ThreadPoolExecutor executor;
private final ExecutorService offsetCheckExecutor =
- ExecutorUtil.newMDCAwareCachedThreadPool(r -> new Thread(r,
"offset-check-thread"));
+ ExecutorUtil.newMDCAwareCachedThreadPool(new
SolrNamedThreadFactory("offset-check-thread"));
private final PartitionManager partitionManager;
private final BlockingQueue<Runnable> queue = new BlockingQueue<>(10);
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/ExecutorUtil.java
b/solr/solrj/src/java/org/apache/solr/common/util/ExecutorUtil.java
index e6e1cd44941..48ac61f55d8 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/ExecutorUtil.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/ExecutorUtil.java
@@ -162,8 +162,9 @@ public class ExecutorUtil {
pool.shutdownNow();
// Wait again for forced threads to stop.
if (!pool.awaitTermination(timeout, unit)) {
- log.error("Threads from pool {} did not forcefully stop.", pool);
- throw new RuntimeException("Timeout waiting for pool " + pool + " to
shutdown.");
+ String executorDetails = describeExecutorForLogging(pool);
+ log.error("Threads from pool did not forcefully stop. {}",
executorDetails);
+ throw new RuntimeException("Timeout waiting for pool to shutdown. "
+ executorDetails);
}
}
} catch (InterruptedException ie) {
@@ -174,6 +175,20 @@ public class ExecutorUtil {
}
}
+ /** Executor logging details which include pool name when executor fails to
terminate. */
+ public static String describeExecutorForLogging(ExecutorService pool) {
+ if (pool == null) return "";
+ if (pool instanceof ThreadPoolExecutor poolExecutor) {
+ ThreadFactory threadFactory = poolExecutor.getThreadFactory();
+ String poolName =
+ threadFactory instanceof SolrNamedThreadFactory
solrNamedThreadFactory
+ ? solrNamedThreadFactory.getPoolName()
+ : "";
+ return "[" + "poolName=" + poolName + "]" + poolExecutor;
+ }
+ return "";
+ }
+
/**
* Await the termination of an {@link ExecutorService} until all threads are
complete, or until we
* are interrupted, at which point the {@link ExecutorService} will be
interrupted as well.
@@ -322,6 +337,18 @@ public class ExecutorUtil {
this.enableSubmitterStackTrace = true;
}
+ /** When the thread factory is a {@link SolrNamedThreadFactory}, prefixes
the pool name. */
+ @Override
+ public String toString() {
+ ThreadFactory threadFactory = getThreadFactory();
+ String base = super.toString();
+ if (threadFactory instanceof SolrNamedThreadFactory
solrNamedThreadFactory) {
+ String poolName = solrNamedThreadFactory.getPoolName();
+ return "[" + "poolName=" + poolName + "] " + base;
+ }
+ return base;
+ }
+
@Override
public void execute(final Runnable command) {
final Map<String, String> submitterContext = MDC.getCopyOfContextMap();
diff --git
a/solr/solrj/src/java/org/apache/solr/common/util/SolrNamedThreadFactory.java
b/solr/solrj/src/java/org/apache/solr/common/util/SolrNamedThreadFactory.java
index 32950971cc7..e36bb54db5a 100644
---
a/solr/solrj/src/java/org/apache/solr/common/util/SolrNamedThreadFactory.java
+++
b/solr/solrj/src/java/org/apache/solr/common/util/SolrNamedThreadFactory.java
@@ -25,10 +25,17 @@ public class SolrNamedThreadFactory implements
ThreadFactory {
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String prefix;
+ private final String poolName;
public SolrNamedThreadFactory(String namePrefix) {
group = getThreadGroup();
prefix = namePrefix + "-" + poolNumber.getAndIncrement() + "-thread-";
+ poolName = namePrefix;
+ }
+
+ /** Returns the name prefix passed to the constructor as a pool name. */
+ public String getPoolName() {
+ return poolName;
}
@SuppressWarnings("removal")
diff --git
a/solr/solrj/src/test/org/apache/solr/common/util/ExecutorUtilTest.java
b/solr/solrj/src/test/org/apache/solr/common/util/ExecutorUtilTest.java
index f9d6026edd0..ed739632e84 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/ExecutorUtilTest.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/ExecutorUtilTest.java
@@ -275,4 +275,17 @@ public class ExecutorUtilTest extends SolrTestCase {
ExecutorUtil.shutdownNowAndAwaitTermination(service);
}
}
+
+ @Test
+ public void mdcAwarePoolToStringIncludesPoolName() {
+ ExecutorService service =
ExecutorUtil.newMDCAwareCachedThreadPool("test-async-task");
+ try {
+ assertTrue(service.toString(),
service.toString().contains("[poolName=test-async-task]"));
+
+ String executorForLogging =
ExecutorUtil.describeExecutorForLogging(service);
+ assertTrue(executorForLogging,
executorForLogging.contains("[poolName=test-async-task]"));
+ } finally {
+ ExecutorUtil.shutdownNowAndAwaitTermination(service);
+ }
+ }
}