package org.zalando.riptide;
import org.springframework.http.client.ClientHttpResponse;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
import static com.google.common.collect.ObjectArrays.concat;
import static org.zalando.fauxpas.FauxPas.throwingFunction;
public final class OriginalStackTracePlugin implements Plugin {
@Override
public RequestExecution prepare(final RequestArguments arguments, final RequestExecution execution) {
return () -> {
final CompletableFuture<ClientHttpResponse> future = execution.execute();
// let's do the "heavy" stack trace work while the request is already on its way
final Supplier<StackTraceElement[]> original = keepOriginalStackTrace();
return future.exceptionally(throwingFunction(cause -> {
cause.setStackTrace(concat(cause.getStackTrace(), original.get(), StackTraceElement.class));
throw cause;
}));
};
}
/**
* A good way to store a stacktrace away efficiently is to simply construct an exception. Later, if you
* want to inspect the stacktrace call exception.getStackTrace() which will do the slow work of
* resolving the stack frames to methods.
* <p>
* <a href="http://stackoverflow.com/a/4377609/232539>What is the proper way to keep track of the original stack trace in a newly created Thread?</a>
*/
@SuppressWarnings("ThrowableInstanceNeverThrown")
private Supplier<StackTraceElement[]> keepOriginalStackTrace() {
return new Exception()::getStackTrace;
}
}