Skip to content

Commit 96573ee

Browse files
committed
Merge branch '6.1.x'
2 parents 107ae61 + 50be084 commit 96573ee

File tree

2 files changed

+77
-6
lines changed

2 files changed

+77
-6
lines changed

spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,7 @@ private <T> T exchangeInternal(ExchangeFunction<T> exchangeFunction, boolean clo
520520

521521
ClientHttpResponse clientResponse = null;
522522
Observation observation = null;
523+
Observation.Scope observationScope = null;
523524
URI uri = null;
524525
try {
525526
uri = initUri();
@@ -532,6 +533,7 @@ private <T> T exchangeInternal(ExchangeFunction<T> exchangeFunction, boolean clo
532533
observationContext.setUriTemplate((String) attributes.get(URI_TEMPLATE_ATTRIBUTE));
533534
observation = ClientHttpObservationDocumentation.HTTP_CLIENT_EXCHANGES.observation(observationConvention,
534535
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry).start();
536+
observationScope = observation.openScope();
535537
if (this.body != null) {
536538
this.body.writeTo(clientRequest);
537539
}
@@ -540,18 +542,24 @@ private <T> T exchangeInternal(ExchangeFunction<T> exchangeFunction, boolean clo
540542
}
541543
clientResponse = clientRequest.execute();
542544
observationContext.setResponse(clientResponse);
543-
ConvertibleClientHttpResponse convertibleWrapper = new DefaultConvertibleClientHttpResponse(clientResponse, observation);
545+
ConvertibleClientHttpResponse convertibleWrapper = new DefaultConvertibleClientHttpResponse(clientResponse, observation, observationScope);
544546
return exchangeFunction.exchange(clientRequest, convertibleWrapper);
545547
}
546548
catch (IOException ex) {
547549
ResourceAccessException resourceAccessException = createResourceAccessException(uri, this.httpMethod, ex);
550+
if (observationScope != null) {
551+
observationScope.close();
552+
}
548553
if (observation != null) {
549554
observation.error(resourceAccessException);
550555
observation.stop();
551556
}
552557
throw resourceAccessException;
553558
}
554559
catch (Throwable error) {
560+
if (observationScope != null) {
561+
observationScope.close();
562+
}
555563
if (observation != null) {
556564
observation.error(error);
557565
observation.stop();
@@ -561,6 +569,9 @@ private <T> T exchangeInternal(ExchangeFunction<T> exchangeFunction, boolean clo
561569
finally {
562570
if (close && clientResponse != null) {
563571
clientResponse.close();
572+
if (observationScope != null) {
573+
observationScope.close();
574+
}
564575
if (observation != null) {
565576
observation.stop();
566577
}
@@ -771,10 +782,12 @@ private class DefaultConvertibleClientHttpResponse implements RequestHeadersSpec
771782

772783
private final Observation observation;
773784

785+
private final Observation.Scope observationScope;
774786

775-
public DefaultConvertibleClientHttpResponse(ClientHttpResponse delegate, Observation observation) {
787+
public DefaultConvertibleClientHttpResponse(ClientHttpResponse delegate, Observation observation, Observation.Scope observationScope) {
776788
this.delegate = delegate;
777789
this.observation = observation;
790+
this.observationScope = observationScope;
778791
}
779792

780793

@@ -815,6 +828,7 @@ public String getStatusText() throws IOException {
815828
@Override
816829
public void close() {
817830
this.delegate.close();
831+
this.observationScope.close();
818832
this.observation.stop();
819833
}
820834

spring-web/src/test/java/org/springframework/web/client/RestClientObservationTests.java

+61-4
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,19 @@
2727
import io.micrometer.observation.ObservationHandler;
2828
import io.micrometer.observation.tck.TestObservationRegistry;
2929
import io.micrometer.observation.tck.TestObservationRegistryAssert;
30+
import org.junit.jupiter.api.AfterEach;
3031
import org.junit.jupiter.api.BeforeEach;
3132
import org.junit.jupiter.api.Test;
3233

3334
import org.springframework.http.HttpHeaders;
3435
import org.springframework.http.HttpMethod;
36+
import org.springframework.http.HttpRequest;
3537
import org.springframework.http.HttpStatus;
3638
import org.springframework.http.MediaType;
3739
import org.springframework.http.client.ClientHttpRequest;
40+
import org.springframework.http.client.ClientHttpRequestExecution;
3841
import org.springframework.http.client.ClientHttpRequestFactory;
42+
import org.springframework.http.client.ClientHttpRequestInterceptor;
3943
import org.springframework.http.client.ClientHttpResponse;
4044
import org.springframework.http.client.observation.ClientRequestObservationContext;
4145
import org.springframework.http.client.observation.ClientRequestObservationConvention;
@@ -73,12 +77,15 @@ class RestClientObservationTests {
7377

7478
@BeforeEach
7579
void setupEach() {
76-
this.client = RestClient.builder()
80+
this.client = createBuilder().build();
81+
this.observationRegistry.observationConfig().observationHandler(new ContextAssertionObservationHandler());
82+
}
83+
84+
RestClient.Builder createBuilder() {
85+
return RestClient.builder()
7786
.messageConverters(converters -> converters.add(0, this.converter))
7887
.requestFactory(this.requestFactory)
79-
.observationRegistry(this.observationRegistry)
80-
.build();
81-
this.observationRegistry.observationConfig().observationHandler(new ContextAssertionObservationHandler());
88+
.observationRegistry(this.observationRegistry);
8289
}
8390

8491
@Test
@@ -238,6 +245,22 @@ void registerObservationWhenReadingStream() throws Exception {
238245
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS");
239246
}
240247

248+
@Test
249+
void openScopeWithObservation() throws Exception {
250+
this.client = createBuilder().requestInterceptor(new ObservationContextInterceptor(this.observationRegistry))
251+
.defaultStatusHandler(new ObservationErrorHandler(this.observationRegistry)).build();
252+
mockSentRequest(GET, "https://example.org");
253+
mockResponseStatus(HttpStatus.OK);
254+
mockResponseBody("Hello World", MediaType.TEXT_PLAIN);
255+
256+
client.get().uri("https://example.org").retrieve().toBodilessEntity();
257+
}
258+
259+
@AfterEach
260+
void checkAfter() {
261+
assertThat(this.observationRegistry.getCurrentObservationScope()).isNull();
262+
}
263+
241264

242265
private void mockSentRequest(HttpMethod method, String uri) throws Exception {
243266
mockSentRequest(method, uri, new HttpHeaders());
@@ -288,4 +311,38 @@ record User(String name) {
288311

289312
}
290313

314+
static class ObservationContextInterceptor implements ClientHttpRequestInterceptor {
315+
316+
private final TestObservationRegistry observationRegistry;
317+
318+
public ObservationContextInterceptor(TestObservationRegistry observationRegistry) {
319+
this.observationRegistry = observationRegistry;
320+
}
321+
322+
@Override
323+
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
324+
assertThat(this.observationRegistry.getCurrentObservationScope()).isNotNull();
325+
return execution.execute(request, body);
326+
}
327+
}
328+
329+
static class ObservationErrorHandler implements ResponseErrorHandler {
330+
331+
final TestObservationRegistry observationRegistry;
332+
333+
ObservationErrorHandler(TestObservationRegistry observationRegistry) {
334+
this.observationRegistry = observationRegistry;
335+
}
336+
337+
@Override
338+
public boolean hasError(ClientHttpResponse response) throws IOException {
339+
return true;
340+
}
341+
342+
@Override
343+
public void handleError(ClientHttpResponse response) throws IOException {
344+
assertThat(this.observationRegistry.getCurrentObservationScope()).isNotNull();
345+
}
346+
}
347+
291348
}

0 commit comments

Comments
 (0)