Skip to content

Commit 9e9dd40

Browse files
Michael McFadyenwilkinsona
authored andcommitted
Add outcome tag to MVC and WebFlux HTTP request metrics
See gh-14486
1 parent 6da483f commit 9e9dd40

File tree

6 files changed

+133
-2
lines changed

6 files changed

+133
-2
lines changed

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/DefaultWebFluxTagsProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public class DefaultWebFluxTagsProvider implements WebFluxTagsProvider {
3535
public Iterable<Tag> httpRequestTags(ServerWebExchange exchange,
3636
Throwable exception) {
3737
return Arrays.asList(WebFluxTags.method(exchange), WebFluxTags.uri(exchange),
38-
WebFluxTags.exception(exception), WebFluxTags.status(exchange));
38+
WebFluxTags.exception(exception), WebFluxTags.status(exchange),
39+
WebFluxTags.outcome(exchange));
3940
}
4041

4142
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTags.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
*
3131
* @author Jon Schneider
3232
* @author Andy Wilkinson
33+
* @author Michael McFadyen
3334
* @since 2.0.0
3435
*/
3536
public final class WebFluxTags {
@@ -42,6 +43,14 @@ public final class WebFluxTags {
4243

4344
private static final Tag EXCEPTION_NONE = Tag.of("exception", "None");
4445

46+
private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN");
47+
48+
private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS");
49+
50+
private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR");
51+
52+
private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR");
53+
4554
private WebFluxTags() {
4655
}
4756

@@ -112,4 +121,29 @@ public static Tag exception(Throwable exception) {
112121
return EXCEPTION_NONE;
113122
}
114123

124+
/**
125+
* Creates a {@code outcome} tag based on the response status of the given
126+
* {@code exchange}.
127+
* @param exchange the exchange
128+
* @return the "outcome" tag derived from the response status
129+
*/
130+
public static Tag outcome(ServerWebExchange exchange) {
131+
if (exchange != null && exchange.getResponse().getStatusCode() != null) {
132+
HttpStatus status = exchange.getResponse().getStatusCode();
133+
if (status.is1xxInformational() || status.is2xxSuccessful()
134+
|| status.is3xxRedirection()) {
135+
return OUTCOME_SUCCESS;
136+
}
137+
else if (status.is4xxClientError()) {
138+
return OUTCOME_CLIENT_ERROR;
139+
}
140+
else {
141+
return OUTCOME_SERVER_ERROR;
142+
}
143+
}
144+
else {
145+
return OUTCOME_UNKNOWN;
146+
}
147+
}
148+
115149
}

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/DefaultWebMvcTagsProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ public class DefaultWebMvcTagsProvider implements WebMvcTagsProvider {
3434
public Iterable<Tag> getTags(HttpServletRequest request, HttpServletResponse response,
3535
Object handler, Throwable exception) {
3636
return Tags.of(WebMvcTags.method(request), WebMvcTags.uri(request, response),
37-
WebMvcTags.exception(exception), WebMvcTags.status(response));
37+
WebMvcTags.exception(exception), WebMvcTags.status(response),
38+
WebMvcTags.outcome(response));
3839
}
3940

4041
@Override

spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/metrics/web/servlet/WebMvcTags.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* @author Jon Schneider
3535
* @author Andy Wilkinson
3636
* @author Brian Clozel
37+
* @author Michael McFadyen
3738
* @since 2.0.0
3839
*/
3940
public final class WebMvcTags {
@@ -50,6 +51,14 @@ public final class WebMvcTags {
5051

5152
private static final Tag STATUS_UNKNOWN = Tag.of("status", "UNKNOWN");
5253

54+
private static final Tag OUTCOME_UNKNOWN = Tag.of("outcome", "UNKNOWN");
55+
56+
private static final Tag OUTCOME_SUCCESS = Tag.of("outcome", "SUCCESS");
57+
58+
private static final Tag OUTCOME_CLIENT_ERROR = Tag.of("outcome", "CLIENT_ERROR");
59+
60+
private static final Tag OUTCOME_SERVER_ERROR = Tag.of("outcome", "SERVER_ERROR");
61+
5362
private static final Tag METHOD_UNKNOWN = Tag.of("method", "UNKNOWN");
5463

5564
private static final Pattern TRAILING_SLASH_PATTERN = Pattern.compile("/$");
@@ -149,4 +158,27 @@ public static Tag exception(Throwable exception) {
149158
return EXCEPTION_NONE;
150159
}
151160

161+
/**
162+
* Creates a {@code outcome} tag based on the status of the given {@code response}.
163+
* @param response the HTTP response
164+
* @return the outcome tag derived from the status of the response
165+
*/
166+
public static Tag outcome(HttpServletResponse response) {
167+
if (response != null) {
168+
int status = response.getStatus();
169+
if (status < 400) {
170+
return OUTCOME_SUCCESS;
171+
}
172+
else if (status < 500) {
173+
return OUTCOME_CLIENT_ERROR;
174+
}
175+
else {
176+
return OUTCOME_SERVER_ERROR;
177+
}
178+
}
179+
else {
180+
return OUTCOME_UNKNOWN;
181+
}
182+
}
183+
152184
}

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/web/servlet/WebMvcTagsTests.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
*
3232
* @author Andy Wilkinson
3333
* @author Brian Clozel
34+
* @author Michael McFadyen
3435
*/
3536
public class WebMvcTagsTests {
3637

@@ -91,4 +92,31 @@ public void uriTagIsUnknownWhenRequestIsNull() {
9192
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
9293
}
9394

95+
@Test
96+
public void outcomeTagIsUnknownWhenResponseIsNull() {
97+
Tag tag = WebMvcTags.outcome(null);
98+
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
99+
}
100+
101+
@Test
102+
public void outcomeTagIsSuccessWhenResponseIs2XX() {
103+
this.response.setStatus(200);
104+
Tag tag = WebMvcTags.outcome(this.response);
105+
assertThat(tag.getValue()).isEqualTo("SUCCESS");
106+
}
107+
108+
@Test
109+
public void outcomeTagIsClientErrorWhenResponseIs4XX() {
110+
this.response.setStatus(400);
111+
Tag tag = WebMvcTags.outcome(this.response);
112+
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
113+
}
114+
115+
@Test
116+
public void outcomeTagIsServerErrorWhenResponseIs5XX() {
117+
this.response.setStatus(500);
118+
Tag tag = WebMvcTags.outcome(this.response);
119+
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
120+
}
121+
94122
}

spring-boot-project/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/metrics/web/reactive/server/WebFluxTagsTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
* Tests for {@link WebFluxTags}.
3737
*
3838
* @author Brian Clozel
39+
* @author Michael McFadyen
3940
*/
4041
public class WebFluxTagsTests {
4142

@@ -88,4 +89,38 @@ public void methodTagToleratesNonStandardHttpMethods() {
8889
assertThat(tag.getValue()).isEqualTo("CUSTOM");
8990
}
9091

92+
@Test
93+
public void outcomeTagIsUnknownWhenResponseIsNull() {
94+
Tag tag = WebFluxTags.outcome(null);
95+
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
96+
}
97+
98+
@Test
99+
public void outcomeTagIsUnknownWhenResponseStatusIsNull() {
100+
this.exchange.getResponse().setStatusCode(null);
101+
Tag tag = WebFluxTags.outcome(this.exchange);
102+
assertThat(tag.getValue()).isEqualTo("UNKNOWN");
103+
}
104+
105+
@Test
106+
public void outcomeTagIsSuccessWhenResponseIs2XX() {
107+
this.exchange.getResponse().setStatusCode(HttpStatus.OK);
108+
Tag tag = WebFluxTags.outcome(this.exchange);
109+
assertThat(tag.getValue()).isEqualTo("SUCCESS");
110+
}
111+
112+
@Test
113+
public void outcomeTagIsClientErrorWhenResponseIs4XX() {
114+
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
115+
Tag tag = WebFluxTags.outcome(this.exchange);
116+
assertThat(tag.getValue()).isEqualTo("CLIENT_ERROR");
117+
}
118+
119+
@Test
120+
public void outcomeTagIsServerErrorWhenResponseIs5XX() {
121+
this.exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY);
122+
Tag tag = WebFluxTags.outcome(this.exchange);
123+
assertThat(tag.getValue()).isEqualTo("SERVER_ERROR");
124+
}
125+
91126
}

0 commit comments

Comments
 (0)