diff --git a/spring-web/src/main/java/org/springframework/http/server/reactive/observation/ServerRequestObservationContext.java b/spring-web/src/main/java/org/springframework/http/server/reactive/observation/ServerRequestObservationContext.java
index 3ef6c39e13..fa7454afac 100644
--- a/spring-web/src/main/java/org/springframework/http/server/reactive/observation/ServerRequestObservationContext.java
+++ b/spring-web/src/main/java/org/springframework/http/server/reactive/observation/ServerRequestObservationContext.java
@@ -25,11 +25,12 @@ import io.micrometer.observation.transport.RequestReplyReceiverContext;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.lang.Nullable;
-import org.springframework.web.server.ServerWebExchange;
/**
* Context that holds information for metadata collection regarding
- * {@link ServerHttpObservationDocumentation#HTTP_REACTIVE_SERVER_REQUESTS reactive HTTP requests} observations.
+ * {@link ServerHttpObservationDocumentation#HTTP_REACTIVE_SERVER_REQUESTS reactive HTTP requests}
+ * observations.
+ *
*
This context also extends {@link RequestReplyReceiverContext} for propagating
* tracing information during HTTP request processing.
*
@@ -39,10 +40,11 @@ import org.springframework.web.server.ServerWebExchange;
public class ServerRequestObservationContext extends RequestReplyReceiverContext {
/**
- * Name of the request attribute holding the {@link ServerRequestObservationContext context} for the current observation.
+ * Name of the request attribute holding the {@link ServerRequestObservationContext context}
+ * for the current observation.
* @since 6.1
*/
- public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerRequestObservationContext.class.getName() + ".context";
+ public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerRequestObservationContext.class.getName();
private final Map attributes;
@@ -53,7 +55,15 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
private boolean connectionAborted;
- public ServerRequestObservationContext(ServerHttpRequest request, ServerHttpResponse response, Map attributes) {
+ /**
+ * Create a new {@code ServerRequestObservationContext} instance.
+ * @param request the current request
+ * @param response the current response
+ * @param attributes the current attributes
+ */
+ public ServerRequestObservationContext(
+ ServerHttpRequest request, ServerHttpResponse response, Map attributes) {
+
super((req, key) -> req.getHeaders().getFirst(key));
setCarrier(request);
setResponse(response);
@@ -89,8 +99,8 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
}
/**
- * Whether the current connection was aborted by the client, resulting
- * in a {@link reactor.core.publisher.SignalType#CANCEL cancel signal} on the reactive chain,
+ * Whether the current connection was aborted by the client, resulting in a
+ * {@link reactor.core.publisher.SignalType#CANCEL cancel signal} on the reactive chain,
* or an {@code AbortedException} when reading the request.
* @return if the connection has been aborted
*/
@@ -99,8 +109,8 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
}
/**
- * Set whether the current connection was aborted by the client, resulting
- * in a {@link reactor.core.publisher.SignalType#CANCEL cancel signal} on the reactive chain,
+ * Set whether the current connection was aborted by the client, resulting in a
+ * {@link reactor.core.publisher.SignalType#CANCEL cancel signal} on the reactive chain,
* or an {@code AbortedException} when reading the request.
* @param connectionAborted if the connection has been aborted
*/
@@ -110,13 +120,15 @@ public class ServerRequestObservationContext extends RequestReplyReceiverContext
/**
- * Get the current {@link ServerRequestObservationContext observation context} from the given exchange, if available.
- * @param exchange the current exchange
+ * Get the current {@link ServerRequestObservationContext observation context}
+ * from the given attributes, if available.
+ * @param attributes the current exchange attributes
* @return the current observation context
* @since 6.1
*/
- public static Optional findCurrent(ServerWebExchange exchange) {
- return Optional.ofNullable(exchange.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
+ public static Optional findCurrent(Map attributes) {
+ return Optional.ofNullable(
+ (ServerRequestObservationContext) attributes.get(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java b/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java
index 2072a25da7..fca440fc1f 100644
--- a/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java
+++ b/spring-web/src/main/java/org/springframework/web/server/adapter/HttpWebHandlerAdapter.java
@@ -296,9 +296,10 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
exchange.getLogPrefix() + formatRequest(exchange.getRequest()) +
(traceOn ? ", headers=" + formatHeaders(exchange.getRequest().getHeaders()) : ""));
- ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange.getRequest(),
- exchange.getResponse(), exchange.getAttributes());
- exchange.getAttributes().put(ServerRequestObservationContext.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
+ ServerRequestObservationContext observationContext = new ServerRequestObservationContext(
+ exchange.getRequest(), exchange.getResponse(), exchange.getAttributes());
+ exchange.getAttributes().put(
+ ServerRequestObservationContext.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
return getDelegate().handle(exchange)
.transformDeferred(call -> transform(exchange, observationContext, call))
diff --git a/spring-web/src/test/java/org/springframework/web/server/adapter/HttpWebHandlerAdapterObservabilityTests.java b/spring-web/src/test/java/org/springframework/web/server/adapter/HttpWebHandlerAdapterObservabilityTests.java
index 94d8c8b46d..f79956d567 100644
--- a/spring-web/src/test/java/org/springframework/web/server/adapter/HttpWebHandlerAdapterObservabilityTests.java
+++ b/spring-web/src/test/java/org/springframework/web/server/adapter/HttpWebHandlerAdapterObservabilityTests.java
@@ -51,6 +51,7 @@ class HttpWebHandlerAdapterObservabilityTests {
private final MockServerHttpResponse response = new MockServerHttpResponse();
+
@Test
void handlerShouldSetObservationContextOnExchange() {
HttpStatusSuccessStubWebHandler targetHandler = new HttpStatusSuccessStubWebHandler(HttpStatus.OK);
@@ -97,6 +98,7 @@ class HttpWebHandlerAdapterObservabilityTests {
.hasObservationWithNameEqualTo("http.server.requests").that();
}
+
private static class HttpStatusSuccessStubWebHandler implements WebHandler {
private final HttpStatus responseStatus;
@@ -109,12 +111,13 @@ class HttpWebHandlerAdapterObservabilityTests {
@Override
public Mono handle(ServerWebExchange exchange) {
- this.observationContext = ServerRequestObservationContext.findCurrent(exchange);
+ this.observationContext = ServerRequestObservationContext.findCurrent(exchange.getAttributes());
exchange.getResponse().setStatusCode(this.responseStatus);
return Mono.empty();
}
}
+
private static class ReactorContextWebHandler implements WebHandler {
ContextView contextView;
@@ -129,6 +132,7 @@ class HttpWebHandlerAdapterObservabilityTests {
}
}
+
private static class ThrowingExceptionWebHandler implements WebHandler {
private final Throwable exception;
@@ -141,11 +145,12 @@ class HttpWebHandlerAdapterObservabilityTests {
@Override
public Mono handle(ServerWebExchange exchange) {
- this.observationContext = ServerRequestObservationContext.findCurrent(exchange);
+ this.observationContext = ServerRequestObservationContext.findCurrent(exchange.getAttributes());
return Mono.error(this.exception);
}
}
+
private static class BadRequestExceptionHandler implements WebExceptionHandler {
@Override
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java
index 723173a649..e36e1af898 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java
@@ -174,7 +174,7 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini
org.springframework.web.filter.reactive.ServerHttpObservationFilter
.findObservationContext(serverRequest.exchange())
.ifPresent(context -> context.setPathPattern(matchingPattern.toString()));
- ServerRequestObservationContext.findCurrent(serverRequest.exchange())
+ ServerRequestObservationContext.findCurrent(serverRequest.exchange().getAttributes())
.ifPresent(context -> context.setPathPattern(matchingPattern.toString()));
}
Map uriVariables =
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
index 604caf088a..5eccca3494 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java
@@ -170,7 +170,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
org.springframework.web.filter.reactive.ServerHttpObservationFilter
.findObservationContext(exchange)
.ifPresent(context -> context.setPathPattern(pattern.toString()));
- ServerRequestObservationContext.findCurrent(exchange)
+ ServerRequestObservationContext.findCurrent(exchange.getAttributes())
.ifPresent(context -> context.setPathPattern(pattern.toString()));
exchange.getAttributes().put(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
exchange.getAttributes().put(URI_TEMPLATE_VARIABLES_ATTRIBUTE, matchInfo.getUriVariables());
diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java
index 31164f291a..99fc0518e7 100644
--- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java
+++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java
@@ -145,7 +145,7 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
org.springframework.web.filter.reactive.ServerHttpObservationFilter
.findObservationContext(exchange)
.ifPresent(context -> context.setPathPattern(bestPattern.toString()));
- ServerRequestObservationContext.findCurrent(exchange)
+ ServerRequestObservationContext.findCurrent(exchange.getAttributes())
.ifPresent(context -> context.setPathPattern(bestPattern.toString()));
exchange.getAttributes().put(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
exchange.getAttributes().put(MATRIX_VARIABLES_ATTRIBUTE, matrixVariables);
diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java
index 8f347d3a97..b979e13302 100644
--- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java
+++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java
@@ -137,7 +137,7 @@ class RouterFunctionMappingTests {
assertThat(matchingPattern.getPatternString()).isEqualTo("/match");
assertThat(org.springframework.web.filter.reactive.ServerHttpObservationFilter.findObservationContext(exchange))
.hasValueSatisfying(context -> assertThat(context.getPathPattern()).isEqualTo(matchingPattern.getPatternString()));
- assertThat(ServerRequestObservationContext.findCurrent(exchange))
+ assertThat(ServerRequestObservationContext.findCurrent(exchange.getAttributes()))
.hasValueSatisfying(context -> assertThat(context.getPathPattern()).isEqualTo(matchingPattern.getPatternString()));
ServerRequest serverRequest = exchange.getAttribute(RouterFunctions.REQUEST_ATTRIBUTE);