Merge pull request #14486 from Michael McFadyen
* gh-14486: Polish "Add outcome tag to MVC and WebFlux HTTP request metrics" Add outcome tag to MVC and WebFlux HTTP request metrics
This commit is contained in:
@@ -35,7 +35,8 @@ public class DefaultWebFluxTagsProvider implements WebFluxTagsProvider {
|
||||
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange,
|
||||
Throwable exception) {
|
||||
return Arrays.asList(WebFluxTags.method(exchange), WebFluxTags.uri(exchange),
|
||||
WebFluxTags.exception(exception), WebFluxTags.status(exchange));
|
||||
WebFluxTags.exception(exception), WebFluxTags.status(exchange),
|
||||
WebFluxTags.outcome(exchange));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.web.util.pattern.PathPattern;
|
||||
*
|
||||
* @author Jon Schneider
|
||||
* @author Andy Wilkinson
|
||||
* @author Michael McFadyen
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class WebFluxTags {
|
||||
@@ -42,6 +43,18 @@ public final class WebFluxTags {
|
||||
|
||||
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None");
|
||||
|
||||
private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN");
|
||||
|
||||
private static final Tag OUTCOME_INFORMATIONAL = Tag.of("outcome", "INFORMATIONAL");
|
||||
|
||||
private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS");
|
||||
|
||||
private static final Tag OUTCOME_REDIRECTION = Tag.of("outcome", "REDIRECTION");
|
||||
|
||||
private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR");
|
||||
|
||||
private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR");
|
||||
|
||||
private WebFluxTags() {
|
||||
}
|
||||
|
||||
@@ -112,4 +125,30 @@ public final class WebFluxTags {
|
||||
return EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code outcome} tag based on the response status of the given
|
||||
* {@code exchange}.
|
||||
* @param exchange the exchange
|
||||
* @return the outcome tag derived from the response status
|
||||
*/
|
||||
public static Tag outcome(ServerWebExchange exchange) {
|
||||
HttpStatus status = exchange.getResponse().getStatusCode();
|
||||
if (status != null) {
|
||||
if (status.is1xxInformational()) {
|
||||
return OUTCOME_INFORMATIONAL;
|
||||
}
|
||||
if (status.is2xxSuccessful()) {
|
||||
return OUTCOME_SUCCESS;
|
||||
}
|
||||
if (status.is3xxRedirection()) {
|
||||
return OUTCOME_REDIRECTION;
|
||||
}
|
||||
if (status.is4xxClientError()) {
|
||||
return OUTCOME_CLIENT_ERROR;
|
||||
}
|
||||
return OUTCOME_SERVER_ERROR;
|
||||
}
|
||||
return OUTCOME_UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider {
|
||||
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Throwable exception) {
|
||||
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response),
|
||||
WebMvcTags.exception(exception), WebMvcTags.status(response));
|
||||
WebMvcTags.exception(exception), WebMvcTags.status(response),
|
||||
WebMvcTags.outcome(response));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
* @author Jon Schneider
|
||||
* @author Andy Wilkinson
|
||||
* @author Brian Clozel
|
||||
* @author Michael McFadyen
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public final class WebMvcTags {
|
||||
@@ -50,6 +51,18 @@ public final class WebMvcTags {
|
||||
|
||||
private static final Tag STATUS_UNKNOWN = Tag.of("status", "UNKNOWN");
|
||||
|
||||
private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN");
|
||||
|
||||
private static final Tag OUTCOME_INFORMATIONAL = Tag.of("outcome", "INFORMATIONAL");
|
||||
|
||||
private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS");
|
||||
|
||||
private static final Tag OUTCOME_REDIRECTION = Tag.of("outcome", "REDIRECTION");
|
||||
|
||||
private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR");
|
||||
|
||||
private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR");
|
||||
|
||||
private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN");
|
||||
|
||||
private static final Pattern TRAILING_SLASH_PATTERN = Pattern.compile("/$");
|
||||
@@ -149,4 +162,29 @@ public final class WebMvcTags {
|
||||
return EXCEPTION_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@code outcome} tag based on the status of the given {@code response}.
|
||||
* @param response the HTTP response
|
||||
* @return the outcome tag derived from the status of the response
|
||||
*/
|
||||
public static Tag outcome(HttpServletResponse response) {
|
||||
if (response != null) {
|
||||
int status = response.getStatus();
|
||||
if (status < 200) {
|
||||
return OUTCOME_INFORMATIONAL;
|
||||
}
|
||||
if (status < 300) {
|
||||
return OUTCOME_SUCCESS;
|
||||
}
|
||||
if (status < 400) {
|
||||
return OUTCOME_REDIRECTION;
|
||||
}
|
||||
else if (status < 500) {
|
||||
return OUTCOME_CLIENT_ERROR;
|
||||
}
|
||||
return OUTCOME_SERVER_ERROR;
|
||||
}
|
||||
return OUTCOME_UNKNOWN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Brian Clozel
|
||||
* @author Michael McFadyen
|
||||
*/
|
||||
public class WebMvcTagsTests {
|
||||
|
||||
@@ -91,4 +92,45 @@ public class WebMvcTagsTests {
|
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsUnknownWhenResponseIsNull() {
|
||||
Tag tag = WebMvcTags.outcome(null);
|
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsInformationalWhenResponseIs1xx() {
|
||||
this.response.setStatus(100);
|
||||
Tag tag = WebMvcTags.outcome(this.response);
|
||||
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsSuccessWhenResponseIs2xx() {
|
||||
this.response.setStatus(200);
|
||||
Tag tag = WebMvcTags.outcome(this.response);
|
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsRedirectionWhenResponseIs3xx() {
|
||||
this.response.setStatus(301);
|
||||
Tag tag = WebMvcTags.outcome(this.response);
|
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsClientErrorWhenResponseIs4xx() {
|
||||
this.response.setStatus(400);
|
||||
Tag tag = WebMvcTags.outcome(this.response);
|
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsServerErrorWhenResponseIs5xx() {
|
||||
this.response.setStatus(500);
|
||||
Tag tag = WebMvcTags.outcome(this.response);
|
||||
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import static org.mockito.Mockito.mock;
|
||||
* Tests for {@link WebFluxTags}.
|
||||
*
|
||||
* @author Brian Clozel
|
||||
* @author Michael McFadyen
|
||||
*/
|
||||
public class WebFluxTagsTests {
|
||||
|
||||
@@ -88,4 +89,46 @@ public class WebFluxTagsTests {
|
||||
assertThat(tag.getValue()).isEqualTo("CUSTOM");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsUnknownWhenResponseStatusIsNull() {
|
||||
this.exchange.getResponse().setStatusCode(null);
|
||||
Tag tag = WebFluxTags.outcome(this.exchange);
|
||||
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsInformationalWhenResponseIs1xx() {
|
||||
this.exchange.getResponse().setStatusCode(HttpStatus.CONTINUE);
|
||||
Tag tag = WebFluxTags.outcome(this.exchange);
|
||||
assertThat(tag.getValue()).isEqualTo("INFORMATIONAL");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsSuccessWhenResponseIs2xx() {
|
||||
this.exchange.getResponse().setStatusCode(HttpStatus.OK);
|
||||
Tag tag = WebFluxTags.outcome(this.exchange);
|
||||
assertThat(tag.getValue()).isEqualTo("SUCCESS");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsRedirectionWhenResponseIs3xx() {
|
||||
this.exchange.getResponse().setStatusCode(HttpStatus.MOVED_PERMANENTLY);
|
||||
Tag tag = WebFluxTags.outcome(this.exchange);
|
||||
assertThat(tag.getValue()).isEqualTo("REDIRECTION");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsClientErrorWhenResponseIs4xx() {
|
||||
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
Tag tag = WebFluxTags.outcome(this.exchange);
|
||||
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outcomeTagIsServerErrorWhenResponseIs5xx() {
|
||||
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY);
|
||||
Tag tag = WebFluxTags.outcome(this.exchange);
|
||||
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1723,12 +1723,28 @@ customized by setting the `management.metrics.web.server.requests-metric-name` p
|
||||
|
||||
By default, Spring MVC-related metrics are tagged with the following information:
|
||||
|
||||
* `method`, the request's method (for example, `GET` or `POST`).
|
||||
* `uri`, the request's URI template prior to variable substitution, if possible (for
|
||||
example, `/api/person/{id}`).
|
||||
* `status`, the response's HTTP status code (for example, `200` or `500`).
|
||||
* `exception`, the simple class name of any exception that was thrown while handling the
|
||||
request.
|
||||
|===
|
||||
|Tag |Description
|
||||
|
||||
|`exception`
|
||||
|Simple class name of any exception that was thrown while handling the request.
|
||||
|
||||
|`method`
|
||||
|Request's method (for example, `GET` or `POST`)
|
||||
|
||||
|`outcome`
|
||||
|Request's outcome based on the status code of the response. 1xx is
|
||||
`INFORMATIONAL`, 2xx is `SUCCESS`, 3xx is `REDIRECTION`, 4xx `CLIENT_ERROR`, and 5xx is
|
||||
`SERVER_ERROR`
|
||||
|
||||
|`status`
|
||||
|Response's HTTP status code (for example, `200` or `500`)
|
||||
|
||||
|`uri`
|
||||
|Request's URI template prior to variable substitution, if possible (for example,
|
||||
`/api/person/{id}`)
|
||||
|
||||
|===
|
||||
|
||||
To customize the tags, provide a `@Bean` that implements `WebMvcTagsProvider`.
|
||||
|
||||
@@ -1744,12 +1760,28 @@ the name by setting the `management.metrics.web.server.requests-metric-name` pro
|
||||
|
||||
By default, WebFlux-related metrics are tagged with the following information:
|
||||
|
||||
* `method`, the request's method (for example, `GET` or `POST`).
|
||||
* `uri`, the request's URI template prior to variable substitution, if possible (for
|
||||
example, `/api/person/{id}`).
|
||||
* `status`, the response's HTTP status code (for example, `200` or `500`).
|
||||
* `exception`, the simple class name of any exception that was thrown while handling the
|
||||
request.
|
||||
|===
|
||||
|Tag |Description
|
||||
|
||||
|`exception`
|
||||
|Simple class name of any exception that was thrown while handling the request.
|
||||
|
||||
|`method`
|
||||
|Request's method (for example, `GET` or `POST`)
|
||||
|
||||
|`outcome`
|
||||
|Request's outcome based on the status code of the response. 1xx is
|
||||
`INFORMATIONAL`, 2xx is `SUCCESS`, 3xx is `REDIRECTION`, 4xx `CLIENT_ERROR`, and 5xx is
|
||||
`SERVER_ERROR`
|
||||
|
||||
|`status`
|
||||
|Response's HTTP status code (for example, `200` or `500`)
|
||||
|
||||
|`uri`
|
||||
|Request's URI template prior to variable substitution, if possible (for example,
|
||||
`/api/person/{id}`)
|
||||
|
||||
|===
|
||||
|
||||
To customize the tags, provide a `@Bean` that implements `WebFluxTagsProvider`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user