Skip to content

Commit e9fcb21

Browse files
committed
Refine status KeyValue for HTTP server observations
Prior to this commit, a cancelled exchange would always result in an `"status":"UNKNOWN"` KeyValue. This only applied to reactive variants, as cancelled exchanges are not currently detected for Servlet implementations. In some cases, exchanges can be cancelled by clients before they are completed, but the response was actually received by the client. The response status information has been set by the application and the response has been committed. For those cases, we shouldn't assume an "UNKNOWN" value. This commit assumes that committed responses have a response status set by the application and that the observations should reflect that. From now on, we only assume an "UNKNOWN" status if the response has not been commited. Fixes gh-31388
1 parent ee9dff3 commit e9fcb21

File tree

2 files changed

+17
-2
lines changed

2 files changed

+17
-2
lines changed

spring-web/src/main/java/org/springframework/http/server/reactive/observation/DefaultServerRequestObservationConvention.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ protected KeyValue method(ServerRequestObservationContext context) {
108108
}
109109

110110
protected KeyValue status(ServerRequestObservationContext context) {
111-
if (context.isConnectionAborted()) {
111+
if (context.isConnectionAborted() && (context.getResponse() == null || !context.getResponse().isCommitted())) {
112112
return STATUS_UNKNOWN;
113113
}
114114
return (context.getResponse() != null && context.getResponse().getStatusCode() != null) ?

spring-web/src/test/java/org/springframework/http/server/reactive/observation/DefaultServerRequestObservationConventionTests.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -147,6 +147,21 @@ void addsKeyValuesForCancelledExchange() {
147147
.contains(KeyValue.of("http.url", "/test/resource"));
148148
}
149149

150+
@Test
151+
void addsKeyValuesForCancelledExchangeWhenResponseCommitted() {
152+
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));
153+
ServerRequestObservationContext context = new ServerRequestObservationContext(exchange.getRequest(), exchange.getResponse(), exchange.getAttributes());
154+
context.setConnectionAborted(true);
155+
exchange.getResponse().setRawStatusCode(404);
156+
exchange.getResponse().setComplete().block();
157+
158+
assertThat(this.convention.getLowCardinalityKeyValues(context)).hasSize(5)
159+
.contains(KeyValue.of("method", "GET"), KeyValue.of("uri", "NOT_FOUND"), KeyValue.of("status", "404"),
160+
KeyValue.of("exception", "none"), KeyValue.of("outcome", "UNKNOWN"));
161+
assertThat(this.convention.getHighCardinalityKeyValues(context)).hasSize(1)
162+
.contains(KeyValue.of("http.url", "/test/resource"));
163+
}
164+
150165
@Test
151166
void supportsNullStatusCode() {
152167
ServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test/resource"));

0 commit comments

Comments
 (0)