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 0ebc3e1561..df807f919c 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,7 +19,6 @@ 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; @@ -34,6 +33,10 @@ import org.springframework.web.util.pattern.PathPattern; */ public final class WebFluxTags { + private static final Tag URI_NOT_FOUND = Tag.of("uri", "NOT_FOUND"); + + private static final Tag URI_REDIRECTION = Tag.of("uri", "REDIRECTION"); + private WebFluxTags() { } @@ -70,14 +73,25 @@ public final class WebFluxTags { * @return the uri tag derived from the exchange */ public static Tag uri(ServerWebExchange exchange) { - PathPattern pathPattern = exchange.getAttributeOrDefault( - HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, null); - String uri = pathPattern == null ? exchange.getRequest().getURI().toString() - : pathPattern.getPatternString(); - if (!StringUtils.hasText(uri)) { - uri = "/"; + if (exchange != null) { + PathPattern pathPattern = exchange.getAttribute( + HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); + if (pathPattern != null) { + return Tag.of("uri", pathPattern.getPatternString()); + } + else { + HttpStatus status = exchange.getResponse().getStatusCode(); + if (status != null && status.is3xxRedirection()) { + return URI_REDIRECTION; + } + if (status != null && status.equals(HttpStatus.NOT_FOUND)) { + return URI_NOT_FOUND; + } + } + String path = exchange.getRequest().getPath().value(); + return Tag.of("uri", path.isEmpty() ? "root" : path); } - return Tag.of("uri", uri.isEmpty() ? "root" : uri); + return Tag.of("uri", "UNKNOWN"); } /** diff --git a/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java new file mode 100644 index 0000000000..bd910bc60f --- /dev/null +++ b/spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.actuate.metrics.web.reactive.server; + +import io.micrometer.core.instrument.Tag; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.http.HttpStatus; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.reactive.HandlerMapping; +import org.springframework.web.util.pattern.PathPatternParser; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link WebFluxTags}. + * @author Brian Clozel + */ +public class WebFluxTagsTests { + + private MockServerWebExchange exchange; + + private PathPatternParser parser = new PathPatternParser(); + + @Before + public void setup() { + this.exchange = MockServerWebExchange + .from(MockServerHttpRequest.get("")); + } + + @Test + public void uriTagValueIsBestMatchingPatternWhenAvailable() { + this.exchange.getAttributes().put( + HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, this.parser.parse("/spring")); + this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); + Tag tag = WebFluxTags.uri(this.exchange); + assertThat(tag.getValue()).isEqualTo("/spring"); + } + + @Test + public void uriTagValueIsRedirectionWhenResponseStatusIs3xx() { + this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY); + Tag tag = WebFluxTags.uri(this.exchange); + assertThat(tag.getValue()).isEqualTo("REDIRECTION"); + } + + @Test + public void uriTagValueIsNotFoundWhenResponseStatusIs404() { + this.exchange.getResponse().setStatusCode(HttpStatus.NOT_FOUND); + Tag tag = WebFluxTags.uri(this.exchange); + assertThat(tag.getValue()).isEqualTo("NOT_FOUND"); + } + + @Test + public void uriTagToleratesCustomResponseStatus() { + this.exchange.getResponse().setStatusCodeValue(601); + Tag tag = WebFluxTags.uri(this.exchange); + assertThat(tag.getValue()).isEqualTo("root"); + } + + @Test + public void uriTagIsUnknownWhenRequestIsNull() { + Tag tag = WebFluxTags.uri(null); + assertThat(tag.getValue()).isEqualTo("UNKNOWN"); + } + +}