diff --git a/zuul-core/src/main/java/com/netflix/zuul/niws/RequestAttempt.java b/zuul-core/src/main/java/com/netflix/zuul/niws/RequestAttempt.java index 6b1b2e9850..82e45dea65 100644 --- a/zuul-core/src/main/java/com/netflix/zuul/niws/RequestAttempt.java +++ b/zuul-core/src/main/java/com/netflix/zuul/niws/RequestAttempt.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.base.Throwables; import com.netflix.appinfo.AmazonInfo; import com.netflix.appinfo.InstanceInfo; import com.netflix.client.config.IClientConfig; @@ -340,7 +339,13 @@ public void setException(Throwable t) { } else { error = t.getMessage(); exceptionType = t.getClass().getSimpleName(); - cause = Throwables.getStackTraceAsString(t); + + // for unexpected exceptions, just capture the first line of the stacktrace + // otherwise we risk large stacktraces in memory and metrics systems + StackTraceElement[] stackTraceElements = t.getStackTrace(); + if (stackTraceElements.length > 0) { + cause = stackTraceElements[0].toString(); + } } } } diff --git a/zuul-core/src/test/java/com/netflix/zuul/niws/RequestAttemptTest.java b/zuul-core/src/test/java/com/netflix/zuul/niws/RequestAttemptTest.java index df9e305f04..0306206fc4 100644 --- a/zuul-core/src/test/java/com/netflix/zuul/niws/RequestAttemptTest.java +++ b/zuul-core/src/test/java/com/netflix/zuul/niws/RequestAttemptTest.java @@ -18,6 +18,9 @@ import com.netflix.zuul.exception.OutboundErrorType; import com.netflix.zuul.netty.connectionpool.OriginConnectException; +import io.netty.handler.codec.http2.DefaultHttp2Connection; +import io.netty.handler.codec.http2.Http2Error; +import io.netty.handler.codec.http2.Http2Exception; import org.junit.jupiter.api.Test; import javax.net.ssl.SSLHandshakeException; @@ -26,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; public class RequestAttemptTest { @@ -77,4 +81,30 @@ void originConnectExceptionWithCauseNotUnwrapped() { assertEquals("ORIGIN_CONNECT_ERROR", attempt.getError()); assertEquals("java.lang.RuntimeException: socket failure", attempt.getCause()); } + + @Test + void h2ExceptionCauseHandled() { + // mock out a real-ish h2 stream exception + Exception h2Exception = spy(Http2Exception.streamError( + 100, + Http2Error.REFUSED_STREAM, + "Cannot create stream 100 greater than Last-Stream-ID 99 from GOAWAY.", + new Object[] {100, 99})); + + // mock a stacktrace to ensure we don't actually capture it completely + when(h2Exception.getStackTrace()).thenReturn(new StackTraceElement[] { + new StackTraceElement( + DefaultHttp2Connection.class.getCanonicalName(), "createStream", "DefaultHttp2Connection.java", 772) + }); + + RequestAttempt attempt = new RequestAttempt(1, null, null, "target", "chosen", 200, null, null, 0, 0, 0); + attempt.setException(h2Exception); + + assertEquals("Cannot create stream 100 greater than Last-Stream-ID 99 from GOAWAY.", attempt.getError()); + assertEquals("StreamException", attempt.getExceptionType()); + + assertEquals( + "io.netty.handler.codec.http2.DefaultHttp2Connection.createStream(DefaultHttp2Connection.java:772)", + attempt.getCause()); + } } \ No newline at end of file