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
This commit is contained in:
parent
c356ce2637
commit
9cab6c90a9
|
@ -107,6 +107,9 @@ final class DefaultRestClient implements RestClient {
|
||||||
|
|
||||||
private final ObservationRegistry observationRegistry;
|
private final ObservationRegistry observationRegistry;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final ClientRequestObservationConvention observationConvention;
|
||||||
|
|
||||||
|
|
||||||
DefaultRestClient(ClientHttpRequestFactory clientRequestFactory,
|
DefaultRestClient(ClientHttpRequestFactory clientRequestFactory,
|
||||||
@Nullable List<ClientHttpRequestInterceptor> interceptors,
|
@Nullable List<ClientHttpRequestInterceptor> interceptors,
|
||||||
|
@ -116,6 +119,7 @@ final class DefaultRestClient implements RestClient {
|
||||||
@Nullable List<StatusHandler> statusHandlers,
|
@Nullable List<StatusHandler> statusHandlers,
|
||||||
List<HttpMessageConverter<?>> messageConverters,
|
List<HttpMessageConverter<?>> messageConverters,
|
||||||
ObservationRegistry observationRegistry,
|
ObservationRegistry observationRegistry,
|
||||||
|
@Nullable ClientRequestObservationConvention observationConvention,
|
||||||
DefaultRestClientBuilder builder) {
|
DefaultRestClientBuilder builder) {
|
||||||
|
|
||||||
this.clientRequestFactory = clientRequestFactory;
|
this.clientRequestFactory = clientRequestFactory;
|
||||||
|
@ -126,6 +130,7 @@ final class DefaultRestClient implements RestClient {
|
||||||
this.defaultStatusHandlers = (statusHandlers != null ? new ArrayList<>(statusHandlers) : new ArrayList<>());
|
this.defaultStatusHandlers = (statusHandlers != null ? new ArrayList<>(statusHandlers) : new ArrayList<>());
|
||||||
this.messageConverters = messageConverters;
|
this.messageConverters = messageConverters;
|
||||||
this.observationRegistry = observationRegistry;
|
this.observationRegistry = observationRegistry;
|
||||||
|
this.observationConvention = observationConvention;
|
||||||
this.builder = builder;
|
this.builder = builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +398,7 @@ final class DefaultRestClient implements RestClient {
|
||||||
clientRequest.getHeaders().addAll(headers);
|
clientRequest.getHeaders().addAll(headers);
|
||||||
ClientRequestObservationContext observationContext = new ClientRequestObservationContext(clientRequest);
|
ClientRequestObservationContext observationContext = new ClientRequestObservationContext(clientRequest);
|
||||||
observationContext.setUriTemplate((String) this.attributes.get(URI_TEMPLATE_ATTRIBUTE));
|
observationContext.setUriTemplate((String) this.attributes.get(URI_TEMPLATE_ATTRIBUTE));
|
||||||
observation = ClientHttpObservationDocumentation.HTTP_CLIENT_EXCHANGES.observation(null,
|
observation = ClientHttpObservationDocumentation.HTTP_CLIENT_EXCHANGES.observation(observationConvention,
|
||||||
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry).start();
|
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry).start();
|
||||||
if (this.body != null) {
|
if (this.body != null) {
|
||||||
this.body.writeTo(clientRequest);
|
this.body.writeTo(clientRequest);
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.JdkClientHttpRequestFactory;
|
import org.springframework.http.client.JdkClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.JettyClientHttpRequestFactory;
|
import org.springframework.http.client.JettyClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||||
|
import org.springframework.http.client.observation.ClientRequestObservationConvention;
|
||||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
import org.springframework.http.converter.ResourceHttpMessageConverter;
|
||||||
|
@ -132,6 +133,9 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||||
|
|
||||||
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
private ObservationRegistry observationRegistry = ObservationRegistry.NOOP;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private ClientRequestObservationConvention observationConvention;
|
||||||
|
|
||||||
|
|
||||||
public DefaultRestClientBuilder() {
|
public DefaultRestClientBuilder() {
|
||||||
}
|
}
|
||||||
|
@ -161,6 +165,7 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||||
this.interceptors = (other.interceptors != null) ? new ArrayList<>(other.interceptors) : null;
|
this.interceptors = (other.interceptors != null) ? new ArrayList<>(other.interceptors) : null;
|
||||||
this.initializers = (other.initializers != null) ? new ArrayList<>(other.initializers) : null;
|
this.initializers = (other.initializers != null) ? new ArrayList<>(other.initializers) : null;
|
||||||
this.observationRegistry = other.observationRegistry;
|
this.observationRegistry = other.observationRegistry;
|
||||||
|
this.observationConvention = other.observationConvention;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DefaultRestClientBuilder(RestTemplate restTemplate) {
|
public DefaultRestClientBuilder(RestTemplate restTemplate) {
|
||||||
|
@ -182,6 +187,7 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||||
this.initializers = new ArrayList<>(restTemplate.getClientHttpRequestInitializers());
|
this.initializers = new ArrayList<>(restTemplate.getClientHttpRequestInitializers());
|
||||||
}
|
}
|
||||||
this.observationRegistry = restTemplate.getObservationRegistry();
|
this.observationRegistry = restTemplate.getObservationRegistry();
|
||||||
|
this.observationConvention = restTemplate.getObservationConvention();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -307,6 +313,12 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RestClient.Builder observationConvention(ClientRequestObservationConvention observationConvention) {
|
||||||
|
this.observationConvention = observationConvention;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RestClient.Builder apply(Consumer<RestClient.Builder> builderConsumer) {
|
public RestClient.Builder apply(Consumer<RestClient.Builder> builderConsumer) {
|
||||||
builderConsumer.accept(this);
|
builderConsumer.accept(this);
|
||||||
|
@ -362,6 +374,7 @@ final class DefaultRestClientBuilder implements RestClient.Builder {
|
||||||
this.statusHandlers,
|
this.statusHandlers,
|
||||||
messageConverters,
|
messageConverters,
|
||||||
this.observationRegistry,
|
this.observationRegistry,
|
||||||
|
this.observationConvention,
|
||||||
new DefaultRestClientBuilder(this)
|
new DefaultRestClientBuilder(this)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.ClientHttpRequestInitializer;
|
import org.springframework.http.client.ClientHttpRequestInitializer;
|
||||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
|
import org.springframework.http.client.observation.ClientRequestObservationConvention;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.web.util.DefaultUriBuilderFactory;
|
import org.springframework.web.util.DefaultUriBuilderFactory;
|
||||||
|
@ -374,6 +375,16 @@ public interface RestClient {
|
||||||
*/
|
*/
|
||||||
Builder observationRegistry(ObservationRegistry observationRegistry);
|
Builder observationRegistry(ObservationRegistry observationRegistry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the {@link io.micrometer.observation.ObservationConvention} to use
|
||||||
|
* for collecting metadata for the request observation. Will use
|
||||||
|
* {@link org.springframework.http.client.observation.DefaultClientRequestObservationConvention}
|
||||||
|
* if none provided.
|
||||||
|
* @param observationConvention the observation convention to use
|
||||||
|
* @return this builder
|
||||||
|
*/
|
||||||
|
Builder observationConvention(ClientRequestObservationConvention observationConvention);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply the given {@code Consumer} to this builder instance.
|
* Apply the given {@code Consumer} to this builder instance.
|
||||||
* <p>This can be useful for applying pre-packaged customizations.
|
* <p>This can be useful for applying pre-packaged customizations.
|
||||||
|
|
|
@ -375,6 +375,15 @@ public class RestTemplate extends InterceptingHttpAccessor implements RestOperat
|
||||||
this.observationConvention = observationConvention;
|
this.observationConvention = observationConvention;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the configured {@link ClientRequestObservationConvention}, or {@code null} if not set.
|
||||||
|
* @since 6.1
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ClientRequestObservationConvention getObservationConvention() {
|
||||||
|
return this.observationConvention;
|
||||||
|
}
|
||||||
|
|
||||||
// GET
|
// GET
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -37,6 +37,8 @@ import org.springframework.http.client.ClientHttpRequest;
|
||||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||||
import org.springframework.http.client.ClientHttpResponse;
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
import org.springframework.http.client.observation.ClientRequestObservationContext;
|
import org.springframework.http.client.observation.ClientRequestObservationContext;
|
||||||
|
import org.springframework.http.client.observation.ClientRequestObservationConvention;
|
||||||
|
import org.springframework.http.client.observation.DefaultClientRequestObservationConvention;
|
||||||
import org.springframework.http.converter.HttpMessageConverter;
|
import org.springframework.http.converter.HttpMessageConverter;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -159,6 +161,20 @@ class RestClientObservationTests {
|
||||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN");
|
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "UNKNOWN");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void executeWithCustomConventionUsesCustomObservationName() throws Exception {
|
||||||
|
ClientRequestObservationConvention observationConvention =
|
||||||
|
new DefaultClientRequestObservationConvention("custom.requests");
|
||||||
|
RestClient restClient = this.client.mutate().observationConvention(observationConvention).build();
|
||||||
|
mockSentRequest(GET, "https://example.org");
|
||||||
|
mockResponseStatus(HttpStatus.OK);
|
||||||
|
|
||||||
|
restClient.get().uri("https://example.org").retrieve().toBodilessEntity();
|
||||||
|
|
||||||
|
TestObservationRegistryAssert.assertThat(this.observationRegistry)
|
||||||
|
.hasObservationWithNameEqualTo("custom.requests");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void mockSentRequest(HttpMethod method, String uri) throws Exception {
|
private void mockSentRequest(HttpMethod method, String uri) throws Exception {
|
||||||
mockSentRequest(method, uri, new HttpHeaders());
|
mockSentRequest(method, uri, new HttpHeaders());
|
||||||
|
|
Loading…
Reference in New Issue