diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java index 8a5465f671650..2e581bcb613d9 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/HttpConfiguration.java @@ -289,6 +289,12 @@ public class HttpConfiguration { @ConfigItem public Map filter; + /** + * This will decorate the stacktrace in dev mode to show the line in the code that cause the exception + */ + @ConfigItem(defaultValue = "true") + public Boolean decorateStacktraces; + public ProxyConfig proxy; public int determinePort(LaunchMode launchMode) { diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java index 939578d216584..20c10be2eb202 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandler.java @@ -41,10 +41,13 @@ public class QuarkusErrorHandler implements Handler { private static final AtomicLong ERROR_COUNT = new AtomicLong(); private final boolean showStack; + private final boolean decorateStack; private final Optional contentTypeDefault; - public QuarkusErrorHandler(boolean showStack, Optional contentTypeDefault) { + public QuarkusErrorHandler(boolean showStack, boolean decorateStack, + Optional contentTypeDefault) { this.showStack = showStack; + this.decorateStack = decorateStack; this.contentTypeDefault = contentTypeDefault; } @@ -129,7 +132,9 @@ public void accept(Throwable throwable) { exception.addSuppressed(e); } if (showStack && exception != null) { - exception = new DecoratedAssertionError(exception); + if (decorateStack) { + exception = new DecoratedAssertionError(exception); + } details = generateHeaderMessage(exception, uuid); stack = generateStackTrace(exception); } else { diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java index 0b91740c6100b..0a221237122a8 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java @@ -414,7 +414,8 @@ public void finalizeRouter(BeanContainer container, Consumer defaultRoute applyCompression(httpBuildTimeConfig.enableCompression, httpRouteRouter); httpRouteRouter.route().last().failureHandler( - new QuarkusErrorHandler(launchMode.isDevOrTest(), httpConfiguration.unhandledErrorContentTypeDefault)); + new QuarkusErrorHandler(launchMode.isDevOrTest(), decorateStacktrace(launchMode, httpConfiguration), + httpConfiguration.unhandledErrorContentTypeDefault)); for (BooleanSupplier requireBodyHandlerCondition : requireBodyHandlerConditions) { if (requireBodyHandlerCondition.getAsBoolean()) { @@ -533,7 +534,8 @@ public void handle(RoutingContext event) { addHotReplacementHandlerIfNeeded(mr); mr.route().last().failureHandler( - new QuarkusErrorHandler(launchMode.isDevOrTest(), httpConfiguration.unhandledErrorContentTypeDefault)); + new QuarkusErrorHandler(launchMode.isDevOrTest(), decorateStacktrace(launchMode, httpConfiguration), + httpConfiguration.unhandledErrorContentTypeDefault)); mr.route().order(RouteConstants.ROUTE_ORDER_BODY_HANDLER_MANAGEMENT) .handler(createBodyHandlerForManagementInterface()); @@ -574,6 +576,10 @@ public void handle(HttpServerRequest event) { } } + private boolean decorateStacktrace(LaunchMode launchMode, HttpConfiguration httpConfiguration) { + return httpConfiguration.decorateStacktraces && launchMode.equals(LaunchMode.DEVELOPMENT); + } + private void addHotReplacementHandlerIfNeeded(Router router) { if (hotReplacementHandler != null) { //recorders are always executed in the current CL diff --git a/extensions/vertx-http/runtime/src/test/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandlerTest.java b/extensions/vertx-http/runtime/src/test/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandlerTest.java index f1634fee29f5f..53de4ac0c9723 100644 --- a/extensions/vertx-http/runtime/src/test/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandlerTest.java +++ b/extensions/vertx-http/runtime/src/test/java/io/quarkus/vertx/http/runtime/QuarkusErrorHandlerTest.java @@ -51,7 +51,8 @@ public void string_with_quotes_should_be_correctly_escaped() { @Test public void json_content_type_hint_should_be_respected_if_not_accepted() { - QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, Optional.of(HttpConfiguration.PayloadHint.JSON)); + QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, false, + Optional.of(HttpConfiguration.PayloadHint.JSON)); Mockito.when(routingContext.failure()).thenReturn(testError); Mockito.when(routingContext.parsedHeaders().findBestUserAcceptedIn(any(), any())) .thenReturn(new ParsableMIMEValue("application/foo+json").forceParse()); @@ -62,7 +63,8 @@ public void json_content_type_hint_should_be_respected_if_not_accepted() { @Test public void json_content_type_hint_should_be_ignored_if_accepted() { - QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, Optional.of(HttpConfiguration.PayloadHint.JSON)); + QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, false, + Optional.of(HttpConfiguration.PayloadHint.JSON)); Mockito.when(routingContext.failure()).thenReturn(testError); Mockito.when(routingContext.parsedHeaders().findBestUserAcceptedIn(any(), any())) .thenReturn(new ParsableMIMEValue("text/html").forceParse()); @@ -73,7 +75,7 @@ public void json_content_type_hint_should_be_ignored_if_accepted() { @Test public void content_type_should_default_to_json_if_accepted() { - QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, Optional.empty()); + QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, false, Optional.empty()); Mockito.when(routingContext.failure()).thenReturn(testError); Mockito.when(routingContext.parsedHeaders().findBestUserAcceptedIn(any(), any())) .thenReturn(new ParsableMIMEValue("application/json").forceParse()); @@ -84,7 +86,8 @@ public void content_type_should_default_to_json_if_accepted() { @Test public void html_content_type_hint_should_be_respected_if_not_accepted() { - QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, Optional.of(HttpConfiguration.PayloadHint.HTML)); + QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, false, + Optional.of(HttpConfiguration.PayloadHint.HTML)); Mockito.when(routingContext.failure()).thenReturn(testError); Mockito.when(routingContext.parsedHeaders().findBestUserAcceptedIn(any(), any())) .thenReturn(new ParsableMIMEValue("application/foo+json").forceParse()); @@ -94,7 +97,8 @@ public void html_content_type_hint_should_be_respected_if_not_accepted() { @Test public void html_content_type_hint_should_be_ignored_if_accepted() { - QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, Optional.of(HttpConfiguration.PayloadHint.HTML)); + QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, false, + Optional.of(HttpConfiguration.PayloadHint.HTML)); Mockito.when(routingContext.failure()).thenReturn(testError); Mockito.when(routingContext.parsedHeaders().findBestUserAcceptedIn(any(), any())) .thenReturn(new ParsableMIMEValue("application/json").forceParse()); @@ -105,7 +109,7 @@ public void html_content_type_hint_should_be_ignored_if_accepted() { @Test public void content_type_should_default_to_html_if_accepted() { - QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, Optional.empty()); + QuarkusErrorHandler errorHandler = new QuarkusErrorHandler(false, false, Optional.empty()); Mockito.when(routingContext.failure()).thenReturn(testError); Mockito.when(routingContext.parsedHeaders().findBestUserAcceptedIn(any(), any())) .thenReturn(new ParsableMIMEValue("text/html").forceParse());