Skip to content

Commit 7157277

Browse files
authored
Merge pull request #33868 from mickroll/rest-reactive-custom-logger
REST reactive: use ClientLogger bean, if present
2 parents 8b04b43 + 09af39f commit 7157277

File tree

10 files changed

+170
-10
lines changed

10 files changed

+170
-10
lines changed

docs/src/main/asciidoc/rest-client-reactive.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,8 @@ quarkus.rest-client.logging.body-limit=50
13641364
quarkus.log.category."org.jboss.resteasy.reactive.client.logging".level=DEBUG
13651365
----
13661366

1367+
TIP: REST Client Reactive uses a default `ClientLogger` implementation. You can change it by providing a custom `ClientLogger` instance through CDI or when programmatically creating your client.
1368+
13671369
== Mocking the client for tests
13681370
If you use a client injected with the `@RestClient` annotation, you can easily mock it for tests.
13691371
You can do it with Mockito's `@InjectMock` or with `QuarkusMock`.

extensions/keycloak-admin-client-reactive/runtime/src/main/java/io/quarkus/keycloak/admin/client/reactive/runtime/ResteasyReactiveClientProvider.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import jakarta.ws.rs.core.MediaType;
1212

1313
import org.eclipse.microprofile.config.ConfigProvider;
14+
import org.jboss.resteasy.reactive.client.api.ClientLogger;
1415
import org.jboss.resteasy.reactive.client.impl.ClientBuilderImpl;
1516
import org.jboss.resteasy.reactive.client.impl.WebTargetImpl;
1617
import org.jboss.resteasy.reactive.server.jackson.JacksonBasicMessageBodyReader;
@@ -74,7 +75,10 @@ private ClientBuilderImpl registerJacksonProviders(ClientBuilderImpl clientBuild
7475
.registerMessageBodyWriter(new ClientJacksonMessageBodyWriter(newObjectMapper), Object.class,
7576
HANDLED_MEDIA_TYPES, true, PROVIDER_PRIORITY);
7677
}
77-
78+
InstanceHandle<ClientLogger> clientLogger = arcContainer.instance(ClientLogger.class);
79+
if (clientLogger.isAvailable()) {
80+
clientBuilder.clientLogger(clientLogger.get());
81+
}
7882
}
7983
return clientBuilder;
8084
}

extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/QuarkusRestClientBuilder.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
1717
import org.eclipse.microprofile.rest.client.ext.QueryParamStyle;
1818
import org.eclipse.microprofile.rest.client.spi.RestClientBuilderListener;
19+
import org.jboss.resteasy.reactive.client.api.ClientLogger;
1920

2021
import io.quarkus.rest.client.reactive.runtime.QuarkusRestClientBuilderImpl;
2122
import io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl;
@@ -250,6 +251,14 @@ static QuarkusRestClientBuilder newBuilder() {
250251
*/
251252
QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOptions);
252253

254+
/**
255+
* Specifies the client logger to use.
256+
*
257+
* @param clientLogger the client logger to use.
258+
* @return the current builder
259+
*/
260+
QuarkusRestClientBuilder clientLogger(ClientLogger clientLogger);
261+
253262
/**
254263
* Based on the configured QuarkusRestClientBuilder, creates a new instance of the given REST interface to invoke API calls
255264
* against.

extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/QuarkusRestClientBuilderImpl.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
1515
import org.eclipse.microprofile.rest.client.ext.ClientHeadersFactory;
1616
import org.eclipse.microprofile.rest.client.ext.QueryParamStyle;
17+
import org.jboss.resteasy.reactive.client.api.ClientLogger;
1718

1819
import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder;
1920
import io.quarkus.rest.client.reactive.runtime.context.ClientHeadersFactoryContextResolver;
@@ -217,6 +218,12 @@ public QuarkusRestClientBuilder httpClientOptions(HttpClientOptions httpClientOp
217218
return this;
218219
}
219220

221+
@Override
222+
public QuarkusRestClientBuilder clientLogger(ClientLogger clientLogger) {
223+
proxy.clientLogger(clientLogger);
224+
return this;
225+
}
226+
220227
@Override
221228
public <T> T build(Class<T> clazz) throws IllegalStateException, RestClientDefinitionException {
222229
return proxy.build(clazz);

extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/RestClientBuilderImpl.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.microprofile.rest.client.RestClientDefinitionException;
2525
import org.eclipse.microprofile.rest.client.ext.QueryParamStyle;
2626
import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
27+
import org.jboss.resteasy.reactive.client.api.ClientLogger;
2728
import org.jboss.resteasy.reactive.client.api.InvalidRestClientDefinitionException;
2829
import org.jboss.resteasy.reactive.client.api.LoggingScope;
2930
import org.jboss.resteasy.reactive.client.api.QuarkusRestClientProperties;
@@ -65,6 +66,8 @@ public class RestClientBuilderImpl implements RestClientBuilder {
6566
private String proxyPassword;
6667
private String nonProxyHosts;
6768

69+
private ClientLogger clientLogger;
70+
6871
@Override
6972
public RestClientBuilderImpl baseUrl(URL url) {
7073
try {
@@ -156,6 +159,11 @@ public RestClientBuilderImpl nonProxyHosts(String nonProxyHosts) {
156159
return this;
157160
}
158161

162+
public RestClientBuilderImpl clientLogger(ClientLogger clientLogger) {
163+
this.clientLogger = clientLogger;
164+
return this;
165+
}
166+
159167
@Override
160168
public RestClientBuilderImpl executorService(ExecutorService executor) {
161169
throw new IllegalArgumentException("Specifying executor service is not supported. " +
@@ -322,6 +330,14 @@ public <T> T build(Class<T> aClass) throws IllegalStateException, RestClientDefi
322330
Integer loggingBodySize = logging != null ? logging.bodyLimit : 100;
323331
clientBuilder.loggingScope(loggingScope);
324332
clientBuilder.loggingBodySize(loggingBodySize);
333+
if (clientLogger != null) {
334+
clientBuilder.clientLogger(clientLogger);
335+
} else {
336+
InstanceHandle<ClientLogger> clientLoggerInstance = Arc.container().instance(ClientLogger.class);
337+
if (clientLoggerInstance.isAvailable()) {
338+
clientBuilder.clientLogger(clientLoggerInstance.get());
339+
}
340+
}
325341

326342
clientBuilder.multiQueryParamMode(toMultiQueryParamMode(queryParamStyle));
327343

integration-tests/rest-client-reactive/src/main/java/io/quarkus/it/rest/client/main/ClientCallingResource.java

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ public class ClientCallingResource {
3838
private static final String[] RESPONSES = { "cortland", "lobo", "golden delicious" };
3939
private final AtomicInteger count = new AtomicInteger(0);
4040

41+
@RestClient
42+
ClientWithClientLogger clientWithClientLogger;
43+
4144
@RestClient
4245
ClientWithExceptionMapper clientWithExceptionMapper;
4346

@@ -59,13 +62,57 @@ public class ClientCallingResource {
5962
@Inject
6063
InMemorySpanExporter inMemorySpanExporter;
6164

65+
@Inject
66+
MyClientLogger globalClientLogger;
67+
6268
void init(@Observes Router router) {
6369
router.post().handler(BodyHandler.create());
6470

6571
router.get("/unprocessable").handler(rc -> rc.response().setStatusCode(422).end("the entity was unprocessable"));
6672

73+
router.get("/client-logger").handler(rc -> {
74+
rc.response().end("Hello World!");
75+
});
76+
77+
router.post("/call-client-with-global-client-logger").blockingHandler(rc -> {
78+
String url = rc.body().asString();
79+
ClientWithClientLogger client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
80+
.build(ClientWithClientLogger.class);
81+
globalClientLogger.reset();
82+
client.call();
83+
if (globalClientLogger.wasUsed()) {
84+
success(rc, "global client logger was used");
85+
} else {
86+
fail(rc, "global client logger was not used");
87+
}
88+
});
89+
90+
router.post("/call-client-with-explicit-client-logger").blockingHandler(rc -> {
91+
String url = rc.body().asString();
92+
MyClientLogger explicitClientLogger = new MyClientLogger();
93+
ClientWithClientLogger client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
94+
.clientLogger(explicitClientLogger)
95+
.build(ClientWithClientLogger.class);
96+
client.call();
97+
if (explicitClientLogger.wasUsed()) {
98+
success(rc, "explicit client logger was used");
99+
} else {
100+
fail(rc, "explicit client logger was not used");
101+
}
102+
});
103+
104+
router.post("/call-cdi-client-with-global-client-logger").blockingHandler(rc -> {
105+
globalClientLogger.reset();
106+
clientWithClientLogger.call();
107+
if (globalClientLogger.wasUsed()) {
108+
success(rc, "global client logger was used");
109+
} else {
110+
fail(rc, "global client logger was not used");
111+
}
112+
});
113+
67114
router.post("/call-client-with-exception-mapper").blockingHandler(rc -> {
68-
String url = rc.getBody().toString();
115+
String url = rc.body().asString();
69116
ClientWithExceptionMapper client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
70117
.register(MyResponseExceptionMapper.class)
71118
.build(ClientWithExceptionMapper.class);
@@ -81,7 +128,7 @@ void init(@Observes Router router) {
81128
});
82129

83130
router.route("/call-client").blockingHandler(rc -> {
84-
String url = rc.getBody().toString();
131+
String url = rc.body().asString();
85132
AppleClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
86133
.build(AppleClient.class);
87134
Uni<Apple> apple1 = Uni.createFrom().item(client.swapApple(new Apple("lobo")));
@@ -110,7 +157,7 @@ void init(@Observes Router router) {
110157
});
111158

112159
router.route("/call-client-retry").blockingHandler(rc -> {
113-
String url = rc.getBody().toString();
160+
String url = rc.body().asString();
114161
AppleClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url + "/does-not-exist"))
115162
.build(AppleClient.class);
116163
AtomicInteger count = new AtomicInteger(0);
@@ -120,29 +167,29 @@ void init(@Observes Router router) {
120167
});
121168

122169
router.post("/hello").handler(rc -> rc.response().putHeader("content-type", MediaType.TEXT_PLAIN)
123-
.end("Hello, " + (rc.getBodyAsString()).repeat(getCount(rc))));
170+
.end("Hello, " + (rc.body().asString()).repeat(getCount(rc))));
124171

125172
router.post("/hello/fromMessage").handler(rc -> rc.response().putHeader("content-type", MediaType.TEXT_PLAIN)
126173
.end(rc.body().asJsonObject().getString("message")));
127174

128175
router.route("/call-hello-client").blockingHandler(rc -> {
129-
String url = rc.getBody().toString();
176+
String url = rc.body().asString();
130177
HelloClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
131178
.build(HelloClient.class);
132179
String greeting = client.greeting("John", 2);
133180
rc.response().end(greeting);
134181
});
135182

136183
router.route("/call-hello-client-trace").blockingHandler(rc -> {
137-
String url = rc.getBody().toString();
184+
String url = rc.body().asString();
138185
HelloClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
139186
.build(HelloClient.class);
140187
String greeting = client.greeting("Mary", 3);
141188
rc.response().end(greeting);
142189
});
143190

144191
router.route("/call-helloFromMessage-client").blockingHandler(rc -> {
145-
String url = rc.getBody().toString();
192+
String url = rc.body().asString();
146193
HelloClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
147194
.build(HelloClient.class);
148195
String greeting = client.fromMessage(new HelloClient.Message("Hello world"));
@@ -153,15 +200,15 @@ void init(@Observes Router router) {
153200
.end(getParam(rc)));
154201

155202
router.route("/call-params-client-with-param-first").blockingHandler(rc -> {
156-
String url = rc.getBody().toString();
203+
String url = rc.body().asString();
157204
ParamClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
158205
.build(ParamClient.class);
159206
String result = client.getParam(Param.FIRST);
160207
rc.response().end(result);
161208
});
162209

163210
router.route("/rest-response").blockingHandler(rc -> {
164-
String url = rc.getBody().toString();
211+
String url = rc.body().asString();
165212
RestResponseClient client = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(url))
166213
.property("microprofile.rest.client.disable.default.mapper", true)
167214
.build(RestResponseClient.class);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package io.quarkus.it.rest.client.main;
2+
3+
import jakarta.ws.rs.GET;
4+
import jakarta.ws.rs.Path;
5+
6+
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
7+
8+
@Path("/client-logger")
9+
@RegisterRestClient(configKey = "w-client-logger")
10+
public interface ClientWithClientLogger {
11+
@GET
12+
String call();
13+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.quarkus.it.rest.client.main;
2+
3+
import java.util.concurrent.atomic.AtomicBoolean;
4+
5+
import jakarta.enterprise.context.ApplicationScoped;
6+
7+
import org.jboss.resteasy.reactive.client.api.ClientLogger;
8+
9+
import io.vertx.core.buffer.Buffer;
10+
import io.vertx.core.http.HttpClientRequest;
11+
import io.vertx.core.http.HttpClientResponse;
12+
13+
@ApplicationScoped
14+
public class MyClientLogger implements ClientLogger {
15+
public final AtomicBoolean used = new AtomicBoolean(false);
16+
17+
@Override
18+
public void setBodySize(int bodySize) {
19+
}
20+
21+
@Override
22+
public void logResponse(HttpClientResponse response, boolean redirect) {
23+
used.set(true);
24+
}
25+
26+
@Override
27+
public void logRequest(HttpClientRequest request, Buffer body, boolean omitBody) {
28+
used.set(true);
29+
}
30+
31+
public void reset() {
32+
used.set(false);
33+
}
34+
35+
public boolean wasUsed() {
36+
return used.get();
37+
}
38+
}

integration-tests/rest-client-reactive/src/main/resources/application.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
w-client-logger/mp-rest/url=${test.url}
12
w-exception-mapper/mp-rest/url=${test.url}
23
w-fault-tolerance/mp-rest/url=${test.url}
34
io.quarkus.it.rest.client.main.ParamClient/mp-rest/url=${test.url}
45
io.quarkus.it.rest.client.multipart.MultipartClient/mp-rest/url=${test.url}
6+
# global client logging scope
7+
quarkus.rest-client.logging.scope=request-response
58
# Self-Signed client
69
quarkus.rest-client.self-signed.trust-store=${self-signed.trust-store}
710
quarkus.rest-client.self-signed.trust-store-password=${self-signed.trust-store-password}

integration-tests/rest-client-reactive/src/test/java/io/quarkus/it/rest/client/BasicTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,27 @@ void shouldRetryOnFailure() {
7777
.body(equalTo("4"));
7878
}
7979

80+
@Test
81+
void shouldLogWithExplicitLogger() {
82+
RestAssured.with().body(baseUrl).post("/call-client-with-explicit-client-logger")
83+
.then()
84+
.statusCode(200);
85+
}
86+
87+
@Test
88+
void shouldLogWithGlobalLogger() {
89+
RestAssured.with().body(baseUrl).post("/call-client-with-global-client-logger")
90+
.then()
91+
.statusCode(200);
92+
}
93+
94+
@Test
95+
void shouldLogCdiWithGlobalLogger() {
96+
RestAssured.with().body(baseUrl).post("/call-cdi-client-with-global-client-logger")
97+
.then()
98+
.statusCode(200);
99+
}
100+
80101
@Test
81102
void shouldMapException() {
82103
RestAssured.with().body(baseUrl).post("/call-client-with-exception-mapper")

0 commit comments

Comments
 (0)