Skip to content

Commit 9cab6c9

Browse files
hpoettkerbclozel
authored andcommitted
Allow custom observation convention for RestClient
This commit allows to use a custom `ObservationConvention` in the `DefaultRestClient`, and to set it through the `RestClient.Builder`. Closes gh-31325
1 parent c356ce2 commit 9cab6c9

File tree

5 files changed

+55
-1
lines changed

5 files changed

+55
-1
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ final class DefaultRestClient implements RestClient {
107107

108108
private final ObservationRegistry observationRegistry;
109109

110+
@Nullable
111+
private final ClientRequestObservationConvention observationConvention;
112+
110113

111114
DefaultRestClient(ClientHttpRequestFactory clientRequestFactory,
112115
@Nullable List<ClientHttpRequestInterceptor> interceptors,
@@ -116,6 +119,7 @@ final class DefaultRestClient implements RestClient {
116119
@Nullable List<StatusHandler> statusHandlers,
117120
List<HttpMessageConverter<?>> messageConverters,
118121
ObservationRegistry observationRegistry,
122+
@Nullable ClientRequestObservationConvention observationConvention,
119123
DefaultRestClientBuilder builder) {
120124

121125
this.clientRequestFactory = clientRequestFactory;
@@ -126,6 +130,7 @@ final class DefaultRestClient implements RestClient {
126130
this.defaultStatusHandlers = (statusHandlers != null ? new ArrayList<>(statusHandlers) : new ArrayList<>());
127131
this.messageConverters = messageConverters;
128132
this.observationRegistry = observationRegistry;
133+
this.observationConvention = observationConvention;
129134
this.builder = builder;
130135
}
131136

@@ -393,7 +398,7 @@ private <T> T exchangeInternal(ExchangeFunction<T> exchangeFunction, boolean clo
393398
clientRequest.getHeaders().addAll(headers);
394399
ClientRequestObservationContext observationContext = new ClientRequestObservationContext(clientRequest);
395400
observationContext.setUriTemplate((String) this.attributes.get(URI_TEMPLATE_ATTRIBUTE));
396-
observation = ClientHttpObservationDocumentation.HTTP_CLIENT_EXCHANGES.observation(null,
401+
observation = ClientHttpObservationDocumentation.HTTP_CLIENT_EXCHANGES.observation(observationConvention,
397402
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry).start();
398403
if (this.body != null) {
399404
this.body.writeTo(clientRequest);

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.http.client.JdkClientHttpRequestFactory;
3636
import org.springframework.http.client.JettyClientHttpRequestFactory;
3737
import org.springframework.http.client.SimpleClientHttpRequestFactory;
38+
import org.springframework.http.client.observation.ClientRequestObservationConvention;
3839
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
3940
import org.springframework.http.converter.HttpMessageConverter;
4041
import org.springframework.http.converter.ResourceHttpMessageConverter;
@@ -132,6 +133,9 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
132133

133134
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
134135

136+
@Nullable
137+
private ClientRequestObservationConvention observationConvention;
138+
135139

136140
public DefaultRestClientBuilder() {
137141
}
@@ -161,6 +165,7 @@ public DefaultRestClientBuilder(DefaultRestClientBuilder other) {
161165
this.interceptors = (other.interceptors != null) ? new ArrayList<>(other.interceptors) : null;
162166
this.initializers = (other.initializers != null) ? new ArrayList<>(other.initializers) : null;
163167
this.observationRegistry = other.observationRegistry;
168+
this.observationConvention = other.observationConvention;
164169
}
165170

166171
public DefaultRestClientBuilder(RestTemplate restTemplate) {
@@ -182,6 +187,7 @@ public DefaultRestClientBuilder(RestTemplate restTemplate) {
182187
this.initializers = new ArrayList<>(restTemplate.getClientHttpRequestInitializers());
183188
}
184189
this.observationRegistry = restTemplate.getObservationRegistry();
190+
this.observationConvention = restTemplate.getObservationConvention();
185191
}
186192

187193

@@ -307,6 +313,12 @@ public RestClient.Builder observationRegistry(ObservationRegistry observationReg
307313
return this;
308314
}
309315

316+
@Override
317+
public RestClient.Builder observationConvention(ClientRequestObservationConvention observationConvention) {
318+
this.observationConvention = observationConvention;
319+
return this;
320+
}
321+
310322
@Override
311323
public RestClient.Builder apply(Consumer<RestClient.Builder> builderConsumer) {
312324
builderConsumer.accept(this);
@@ -362,6 +374,7 @@ public RestClient build() {
362374
this.statusHandlers,
363375
messageConverters,
364376
this.observationRegistry,
377+
this.observationConvention,
365378
new DefaultRestClientBuilder(this)
366379
);
367380
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.springframework.http.client.ClientHttpRequestInitializer;
4343
import org.springframework.http.client.ClientHttpRequestInterceptor;
4444
import org.springframework.http.client.ClientHttpResponse;
45+
import org.springframework.http.client.observation.ClientRequestObservationConvention;
4546
import org.springframework.http.converter.HttpMessageConverter;
4647
import org.springframework.lang.Nullable;
4748
import org.springframework.web.util.DefaultUriBuilderFactory;
@@ -374,6 +375,16 @@ Builder defaultStatusHandler(Predicate<HttpStatusCode> statusPredicate,
374375
*/
375376
Builder observationRegistry(ObservationRegistry observationRegistry);
376377

378+
/**
379+
* Configure the {@link io.micrometer.observation.ObservationConvention} to use
380+
* for collecting metadata for the request observation. Will use
381+
* {@link org.springframework.http.client.observation.DefaultClientRequestObservationConvention}
382+
* if none provided.
383+
* @param observationConvention the observation convention to use
384+
* @return this builder
385+
*/
386+
Builder observationConvention(ClientRequestObservationConvention observationConvention);
387+
377388
/**
378389
* Apply the given {@code Consumer} to this builder instance.
379390
* <p>This can be useful for applying pre-packaged customizations.

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,15 @@ public void setObservationConvention(ClientRequestObservationConvention observat
375375
this.observationConvention = observationConvention;
376376
}
377377

378+
/**
379+
* Return the configured {@link ClientRequestObservationConvention}, or {@code null} if not set.
380+
* @since 6.1
381+
*/
382+
@Nullable
383+
public ClientRequestObservationConvention getObservationConvention() {
384+
return this.observationConvention;
385+
}
386+
378387
// GET
379388

380389
@Override

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import org.springframework.http.client.ClientHttpRequestFactory;
3838
import org.springframework.http.client.ClientHttpResponse;
3939
import org.springframework.http.client.observation.ClientRequestObservationContext;
40+
import org.springframework.http.client.observation.ClientRequestObservationConvention;
41+
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
4042
import org.springframework.http.converter.HttpMessageConverter;
4143

4244
import static org.assertj.core.api.Assertions.assertThat;
@@ -159,6 +161,20 @@ void executeWithIoExceptionAddsUnknownOutcome() throws Exception {
159161
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN");
160162
}
161163

164+
@Test
165+
void executeWithCustomConventionUsesCustomObservationName() throws Exception {
166+
ClientRequestObservationConvention observationConvention =
167+
new DefaultClientRequestObservationConvention("custom.requests");
168+
RestClient restClient = this.client.mutate().observationConvention(observationConvention).build();
169+
mockSentRequest(GET, "https://example.org");
170+
mockResponseStatus(HttpStatus.OK);
171+
172+
restClient.get().uri("https://example.org").retrieve().toBodilessEntity();
173+
174+
TestObservationRegistryAssert.assertThat(this.observationRegistry)
175+
.hasObservationWithNameEqualTo("custom.requests");
176+
}
177+
162178

163179
private void mockSentRequest(HttpMethod method, String uri) throws Exception {
164180
mockSentRequest(method, uri, new HttpHeaders());

0 commit comments

Comments
 (0)