public static <T> T waitWithLogging(
        Logger log,
        String prefix,
        String action,
        CompletableFuture<T> future,
        Deadline deadline,
        Time time
    ) throws Throwable {
        log.info("{}Waiting for {}", prefix, action);
        try {
            T result = time.waitForFuture(future, deadline.nanoseconds());
            log.info("{}Finished waiting for {}", prefix, action);
            return result;
        } catch (TimeoutException t)  {
            log.error("{}Timed out while waiting for {}", prefix, action, t);
            TimeoutException timeout = new TimeoutException("Timed out while waiting for " + action);
            timeout.setStackTrace(t.getStackTrace());
            throw timeout;
        } catch (Throwable t)  {
            if (t instanceof ExecutionException) {
                ExecutionException executionException = (ExecutionException) t;
                t = executionException.getCause();
            }
            log.error("{}Received a fatal error while waiting for {}", prefix, action, t);
            throw new RuntimeException("Received a fatal error while waiting for " + action, t);
        }
    }
Wait for a future until a specific time in the future, with copious logging.

@param log           The slf4j object to use to log success and failure.
@param action        The action we are waiting for.
@param future        The future we are waiting for.
@param deadline      The deadline in the future we are waiting for.
@param time          The clock object.

@return              The result of the future.
@param <T>           The type of the future.

@throws java.util.concurrent.TimeoutException If the future times out.
@throws Throwable If the future fails. Note: we unwrap ExecutionException here.
server-common/src/main/java/org/apache/kafka/server/util/FutureUtils.java