Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions docs/src/main/asciidoc/rest-client.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,30 @@ When setting up the client programmatically using the `QuarkusRestClientBuilder`
For declarative clients using `@RegisterRestClient`, simply providing a CDI bean that implements `ClientLogger` is enough for that logger to be used by said clients.
====

== Metrics

All declarative REST Client instances produce metrics using the `http.clients` prefix. Furthermore, the metrics contain a tag named `clientName` which corresponds to the config key of the client (as specified by the `configKey` property of the `@RegisterRestClient` annotation).

To enable metrics for programmatically created REST Clients, the following snippet can be used:

[source,java]
----
var builder = QuarkusRestClientBuilder.newBuilder();

// use the builder to configure the client

// now configure a customizer that sets the metrics name
builder.httpClientOptionsCustomizer(new Consumer<>() {
@Override
public void accept(HttpClientOptions httpClientOptions) {
String metricsName = httpClientOptions.getMetricsName();
if (metricsName == null || metricsName.isEmpty()) {
httpClientOptions.setMetricsName("rest-client|" + "someName"); // the 'rest-client|' prefix is absolutely necessary here
}
}
});
----

== Mocking the client for tests
If you use a client injected with the `@RestClient` annotation, you can easily mock it for tests.
You can do it with Mockito's `@InjectMock` or with `QuarkusMock`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.time.Duration;
import java.util.ServiceLoader;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -284,6 +285,12 @@ static QuarkusRestClientBuilder newBuilder() {
*/
QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOptions);

/**
* Specifies a callback which will be invoked after Quarkus has populated {@link HttpClientOptions} but before Vert.x uses
* it to create {@link io.vertx.core.http.HttpClient}
*/
QuarkusRestClientBuilder httpClientOptionsCustomizer(Consumer<HttpClientOptions> httpClientOptionsCustomizer);

/**
* Specifies the client logger to use.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -246,6 +247,13 @@ public QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOp
return this;
}

@Override
public QuarkusRestClientBuilder httpClientOptionsCustomizer(
Consumer<HttpClientOptions> httpClientOptionsCustomizer) {
delegate.clientOptionsCustomizer(httpClientOptionsCustomizer);
return this;
}

@Override
public QuarkusRestClientBuilder clientLogger(ClientLogger clientLogger) {
delegate.clientLogger(clientLogger);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -54,6 +55,7 @@
import io.quarkus.restclient.config.RestClientsConfig;
import io.quarkus.tls.TlsConfiguration;
import io.smallrye.config.SmallRyeConfig;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.net.KeyCertOptions;
import io.vertx.core.net.ProxyType;
import io.vertx.core.net.SSLOptions;
Expand Down Expand Up @@ -96,6 +98,7 @@ public class RestClientBuilderImpl implements RestClientBuilder {
private String userAgent;
private Boolean disableDefaultMapper;
private Boolean enableCompression;
private Consumer<HttpClientOptions> clientOptionsCustomizer;

@Override
public RestClientBuilderImpl baseUrl(URL url) {
Expand Down Expand Up @@ -301,6 +304,11 @@ public RestClientBuilderImpl enableCompression(boolean enableCompression) {
return this;
}

public RestClientBuilderImpl clientOptionsCustomizer(Consumer<HttpClientOptions> clientOptionsCustomizer) {
clientBuilder.clientOptionsCustomizer(clientOptionsCustomizer);
return this;
}

@Override
public RestClientBuilderImpl executorService(ExecutorService executor) {
throw new IllegalArgumentException("Specifying executor service is not supported. " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Optional;
import java.util.OptionalInt;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;

import javax.net.ssl.HostnameVerifier;
Expand All @@ -39,6 +40,7 @@
import io.quarkus.tls.TlsConfiguration;
import io.quarkus.tls.TlsConfigurationRegistry;
import io.smallrye.config.SmallRyeConfig;
import io.vertx.core.http.HttpClientOptions;

public class RestClientCDIDelegateBuilder<T> {

Expand Down Expand Up @@ -87,6 +89,7 @@ void configureBuilder(QuarkusRestClientBuilder builder) {
configureShared(builder);
configureLogging(builder);
configureCustomProperties(builder);
configureClientOptionsCustomizer(builder);
}

private void configureLogging(QuarkusRestClientBuilder builder) {
Expand Down Expand Up @@ -447,6 +450,18 @@ private void configureBaseUrl(QuarkusRestClientBuilder builder) {
}
}

private void configureClientOptionsCustomizer(QuarkusRestClientBuilder builder) {
builder.httpClientOptionsCustomizer(new Consumer<>() {
@Override
public void accept(HttpClientOptions httpClientOptions) {
String metricsName = httpClientOptions.getMetricsName();
if (metricsName == null || metricsName.isEmpty()) {
httpClientOptions.setMetricsName("rest-client|" + configKey);
}
}
});
}

@SafeVarargs
private static <T> Optional<T> oneOf(Optional<T>... optionals) {
for (Optional<T> o : optionals) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.regex.Pattern;

import javax.net.ssl.HostnameVerifier;
Expand Down Expand Up @@ -87,6 +89,7 @@ public class ClientBuilderImpl extends ClientBuilder {

private Boolean enableCompression;
private Integer http2UpgradeMaxContentLength;
private List<Consumer<HttpClientOptions>> clientOptionsCustomizers = new ArrayList<>();

public ClientBuilderImpl() {
configuration = new ConfigurationImpl(RuntimeType.CLIENT);
Expand Down Expand Up @@ -221,6 +224,11 @@ public ClientBuilder maxChunkSize(int maxChunkSize) {
return this;
}

public ClientBuilder clientOptionsCustomizer(Consumer<HttpClientOptions> clientOptionsCustomizer) {
this.clientOptionsCustomizers.add(clientOptionsCustomizer);
return this;
}

public TlsConfig getTlsConfig() {
return tlsConfig;
}
Expand Down Expand Up @@ -308,6 +316,11 @@ public ClientImpl build() {
clientLogger.setBodySize(loggingBodySize);

options.setMaxChunkSize(maxChunkSize);

for (Consumer<HttpClientOptions> clientOptionsCustomizer : clientOptionsCustomizers) {
clientOptionsCustomizer.accept(options);
}

return new ClientImpl(options,
new ConfigurationImpl(configuration),
CLIENT_CONTEXT_RESOLVER.resolve(Thread.currentThread().getContextClassLoader()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,16 @@ public Integer countServerRequests(@QueryParam("method") String method,
}
return search.timers().size();
}

@Path("/client/count")
@Produces(MediaType.APPLICATION_JSON)
@GET
public Integer countClientRequests(@QueryParam("clientName") String clientName) {
final Search search = registry
.find("http.client.requests");
if (clientName != null) {
search.tag("clientName", clientName);
}
return search.timers().size();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,12 @@ void testClientRequests() {
.when().get("/server-requests/count")
.body().as(Integer.class),
"Expected: http.server.requests, method=GET, status=500, uri=/client/status/{statusCode}");

assertEquals(5,
given()
.queryParam("clientName", "pingpong")
.when().get("/server-requests/client/count")
.body().as(Integer.class),
"Expected: http.client.requests, clientName=pingpong");
}
}
Loading