diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java index c50875a0b9..4cc950c83a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java @@ -19,6 +19,7 @@ package org.springframework.boot.actuate.metrics.web.reactive.server; import io.micrometer.core.instrument.Tag; import org.springframework.http.HttpStatus; +import org.springframework.util.StringUtils; import org.springframework.web.reactive.HandlerMapping; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.util.pattern.PathPattern; @@ -109,7 +110,9 @@ public final class WebFluxTags { */ public static Tag exception(Throwable exception) { if (exception != null) { - return Tag.of("exception", exception.getClass().getSimpleName()); + String simpleName = exception.getClass().getSimpleName(); + return Tag.of("exception", StringUtils.hasText(simpleName) ? simpleName + : exception.getClass().getName()); } return EXCEPTION_NONE; } diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java index f469b6ba72..c24fe63097 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java @@ -134,9 +134,12 @@ public final class WebMvcTags { * @return the exception tag derived from the exception */ public static Tag exception(Throwable exception) { - return (exception != null - ? Tag.of("exception", exception.getClass().getSimpleName()) - : EXCEPTION_NONE); + if (exception != null) { + String simpleName = exception.getClass().getSimpleName(); + return Tag.of("exception", StringUtils.hasText(simpleName) ? simpleName + : exception.getClass().getName()); + } + return EXCEPTION_NONE; } } diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/MetricsWebFilterTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/MetricsWebFilterTests.java index 45d9acbe3e..75d425686b 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/MetricsWebFilterTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/MetricsWebFilterTests.java @@ -77,6 +77,24 @@ public class MetricsWebFilterTests { }).block(); assertMetricsContainsTag("uri", "/projects/{project}"); assertMetricsContainsTag("status", "500"); + assertMetricsContainsTag("exception", "IllegalStateException"); + } + + @Test + public void filterAddsNonEmptyTagsToRegistryForAnonymousExceptions() { + final Exception anonymous = new Exception("test error") { + }; + + MockServerWebExchange exchange = createExchange("/projects/spring-boot", + "/projects/{project}"); + this.webFilter.filter(exchange, (serverWebExchange) -> Mono.error(anonymous)) + .onErrorResume((t) -> { + exchange.getResponse().setStatusCodeValue(500); + return exchange.getResponse().setComplete(); + }).block(); + assertMetricsContainsTag("uri", "/projects/{project}"); + assertMetricsContainsTag("status", "500"); + assertMetricsContainsTag("exception", anonymous.getClass().getName()); } @Test diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java index db6a9038dd..f86847881b 100644 --- a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcMetricsFilterTests.java @@ -188,6 +188,18 @@ public class WebMvcMetricsFilterTests { .tags("exception", "RuntimeException").timer().count()).isEqualTo(1L); } + @Test + public void anonymousError() { + try { + this.mvc.perform(get("/api/c1/anonymousError/10")); + } + catch (Throwable ignore) { + } + assertThat(this.registry.get("http.server.requests") + .tag("uri", "/api/c1/anonymousError/{id}").timer().getId() + .getTag("exception")).endsWith("$1"); + } + @Test public void asyncCallableRequest() throws Exception { AtomicReference result = new AtomicReference<>(); @@ -440,6 +452,14 @@ public class WebMvcMetricsFilterTests { throw new IllegalStateException("Boom on " + id + "!"); } + @Timed + @GetMapping("/anonymousError/{id}") + public String alwaysThrowsAnonymousException(@PathVariable Long id) + throws Exception { + throw new Exception("this exception won't have a simple class name") { + }; + } + @Timed @GetMapping("/unhandledError/{id}") public String alwaysThrowsUnhandledException(@PathVariable Long id) {