Skip to content

Commit db79d1d

Browse files
committed
Set matching pattern in reactive server observation context
This commit fixes the observation instrumentation for the reactive HTTP server by setting the best matching pattern determined by the web framework into the `ServerRequestObservationContext`. This information is required by the observation convention for creating the expected `KeyValue` for the matching pattern. Prior to this commit, the information was missing and resulted in an UNKNOWN key value. Fixes gh-29422
1 parent 05c9978 commit db79d1d

File tree

5 files changed

+33
-1
lines changed

5 files changed

+33
-1
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.springframework.http.codec.ServerCodecConfigurer;
2929
import org.springframework.lang.Nullable;
3030
import org.springframework.util.CollectionUtils;
31+
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
3132
import org.springframework.web.reactive.function.server.HandlerFunction;
3233
import org.springframework.web.reactive.function.server.RouterFunction;
3334
import org.springframework.web.reactive.function.server.RouterFunctions;
@@ -170,6 +171,8 @@ private void setAttributes(
170171
PathPattern matchingPattern = (PathPattern) attributes.get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE);
171172
if (matchingPattern != null) {
172173
attributes.put(BEST_MATCHING_PATTERN_ATTRIBUTE, matchingPattern);
174+
ServerHttpObservationFilter.findObservationContext(serverRequest.exchange())
175+
.ifPresent(context -> context.setPathPattern(matchingPattern));
173176
}
174177
Map<String, String> uriVariables =
175178
(Map<String, String>) attributes.get(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractUrlHandlerMapping.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.springframework.lang.Nullable;
3131
import org.springframework.util.Assert;
3232
import org.springframework.util.StringUtils;
33+
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
3334
import org.springframework.web.server.ServerWebExchange;
3435
import org.springframework.web.util.pattern.PathPattern;
3536

@@ -165,6 +166,8 @@ protected Object lookupHandler(PathContainer lookupPath, ServerWebExchange excha
165166

166167
exchange.getAttributes().put(BEST_MATCHING_HANDLER_ATTRIBUTE, handler);
167168
exchange.getAttributes().put(BEST_MATCHING_PATTERN_ATTRIBUTE, pattern);
169+
ServerHttpObservationFilter.findObservationContext(exchange)
170+
.ifPresent(context -> context.setPathPattern(pattern));
168171
exchange.getAttributes().put(PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
169172
exchange.getAttributes().put(URI_TEMPLATE_VARIABLES_ATTRIBUTE, matchInfo.getUriVariables());
170173

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.springframework.util.Assert;
3939
import org.springframework.util.MultiValueMap;
4040
import org.springframework.web.bind.annotation.RequestMethod;
41+
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
4142
import org.springframework.web.method.HandlerMethod;
4243
import org.springframework.web.reactive.HandlerMapping;
4344
import org.springframework.web.reactive.result.condition.NameValueExpression;
@@ -139,6 +140,8 @@ protected void handleMatch(RequestMappingInfo info, HandlerMethod handlerMethod,
139140

140141
exchange.getAttributes().put(BEST_MATCHING_HANDLER_ATTRIBUTE, handlerMethod);
141142
exchange.getAttributes().put(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
143+
ServerHttpObservationFilter.findObservationContext(exchange)
144+
.ifPresent(context -> context.setPathPattern(bestPattern));
142145
exchange.getAttributes().put(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
143146
exchange.getAttributes().put(MATRIX_VARIABLES_ATTRIBUTE, matrixVariables);
144147

spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2424
import org.springframework.http.codec.ServerCodecConfigurer;
25+
import org.springframework.http.observation.reactive.ServerRequestObservationContext;
26+
import org.springframework.web.filter.reactive.ServerHttpObservationFilter;
2527
import org.springframework.web.reactive.HandlerMapping;
2628
import org.springframework.web.reactive.function.server.HandlerFunction;
2729
import org.springframework.web.reactive.function.server.RouterFunction;
@@ -34,8 +36,10 @@
3436
import org.springframework.web.util.pattern.PathPattern;
3537

3638
import static org.assertj.core.api.Assertions.assertThat;
39+
import static org.springframework.web.filter.reactive.ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE;
3740

3841
/**
42+
* Tests for {@link RouterFunctionMapping}.
3943
* @author Arjen Poutsma
4044
* @author Brian Clozel
4145
*/
@@ -132,6 +136,8 @@ void mappedRequestShouldHoldAttributes() {
132136
PathPattern matchingPattern = exchange.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
133137
assertThat(matchingPattern).isNotNull();
134138
assertThat(matchingPattern.getPatternString()).isEqualTo("/match");
139+
assertThat(ServerHttpObservationFilter.findObservationContext(exchange))
140+
.hasValueSatisfying(context -> assertThat(context.getPathPattern()).isEqualTo(matchingPattern));
135141

136142
ServerRequest serverRequest = exchange.getAttribute(RouterFunctions.REQUEST_ATTRIBUTE);
137143
assertThat(serverRequest).isNotNull();
@@ -141,7 +147,10 @@ void mappedRequestShouldHoldAttributes() {
141147
}
142148

143149
private ServerWebExchange createExchange(String urlTemplate) {
144-
return MockServerWebExchange.from(MockServerHttpRequest.get(urlTemplate));
150+
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(urlTemplate));
151+
ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange);
152+
exchange.getAttributes().put(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
153+
return exchange;
145154
}
146155

147156
}

spring-webflux/src/test/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMappingTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.springframework.http.HttpHeaders;
3737
import org.springframework.http.HttpMethod;
3838
import org.springframework.http.MediaType;
39+
import org.springframework.http.observation.reactive.ServerRequestObservationContext;
3940
import org.springframework.lang.Nullable;
4041
import org.springframework.stereotype.Controller;
4142
import org.springframework.util.ClassUtils;
@@ -63,6 +64,7 @@
6364
import static org.springframework.web.bind.annotation.RequestMethod.GET;
6465
import static org.springframework.web.bind.annotation.RequestMethod.HEAD;
6566
import static org.springframework.web.bind.annotation.RequestMethod.OPTIONS;
67+
import static org.springframework.web.filter.reactive.ServerHttpObservationFilter.CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE;
6668
import static org.springframework.web.reactive.HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE;
6769
import static org.springframework.web.reactive.HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE;
6870
import static org.springframework.web.reactive.result.method.RequestMappingInfo.paths;
@@ -257,6 +259,18 @@ public void handleMatchBestMatchingPatternAttribute() {
257259
assertThat(mapped).isSameAs(handlerMethod);
258260
}
259261

262+
@Test
263+
public void handleMatchBestMatchingPatternAttributeInObservationContext() {
264+
RequestMappingInfo key = paths("/{path1}/2", "/**").build();
265+
ServerWebExchange exchange = MockServerWebExchange.from(get("/1/2"));
266+
ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange);
267+
exchange.getAttributes().put(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
268+
this.handlerMapping.handleMatch(key, handlerMethod, exchange);
269+
270+
assertThat(observationContext.getPathPattern()).isNotNull();
271+
assertThat(observationContext.getPathPattern().toString()).isEqualTo("/{path1}/2");
272+
}
273+
260274
@Test // gh-22543
261275
public void handleMatchBestMatchingPatternAttributeNoPatternsDefined() {
262276
ServerWebExchange exchange = MockServerWebExchange.from(get(""));

0 commit comments

Comments
 (0)