web-dev-qa-db-fra.com

comment enregistrer l'appel Spring 5 WebClient

J'essaie de consigner une demande à l'aide de Spring 5 WebClient. Avez-vous une idée de comment pourrais-je atteindre cet objectif?

(J'utilise Spring 5 et Spring Boot 2)

Le code ressemble à ceci pour le moment:

try {
    return webClient.get().uri(url, urlParams).exchange().flatMap(response -> response.bodyToMono(Test.class))
            .map(test -> xxx.set(test));
} catch (RestClientException e) {
    log.error("Cannot get counter from opus", e);
    throw e;
}
23
Seb

Vous pouvez facilement le faire en utilisant ExchangeFilterFunction

Ajoutez simplement le filtre personnalisé logRequest lorsque vous créez votre WebClient en utilisant WebClient.Builder.

Voici l'exemple d'un tel filtre et comment l'ajouter au WebClient.

@Slf4j
@Component
public class MyClient {

    private final WebClient webClient;

    // Create WebClient instance using builder.
    // If you use spring-boot 2.0, the builder will be autoconfigured for you
    // with the "prototype" scope, meaning each injection point will receive
    // a newly cloned instance of the builder.
    public MyClient(WebClient.Builder webClientBuilder) {
        webClient = webClientBuilder // you can also just use WebClient.builder()
                .baseUrl("https://httpbin.org")
                .filter(logRequest()) // here is the magic
                .build();
    }

    // Just example of sending request
    public void send(String path) {
        ClientResponse clientResponse = webClient
                .get().uri(uriBuilder -> uriBuilder.path(path)
                        .queryParam("param", "value")
                        .build())
                .exchange()
                .block();
        log.info("Response: {}", clientResponse.toEntity(String.class).block());
    }

    // This method returns filter function which will log request data
    private static ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            log.info("Request: {} {}", clientRequest.method(), clientRequest.url());
            clientRequest.headers().forEach((name, values) -> values.forEach(value -> log.info("{}={}", name, value)));
            return Mono.just(clientRequest);
        });
    }

}

Ensuite, appelez simplement myClient.send("get"); et les messages de journalisation devraient être là.

Exemple de sortie:

Request: GET https://httpbin.org/get?param=value
header1=value1
header2=value2
20

Vous n'avez pas nécessairement besoin de lancer votre propre enregistreur, reactor.ipc.netty.channel.ChannelOperationsHandler le fait pour vous. Configurez simplement votre système de journalisation pour que cette classe se connecte au niveau DEBUG:

2017-11-23 12:52:04.562 DEBUG 41449 --- [ctor-http-nio-5] r.i.n.channel.ChannelOperationsHandler   : [id: 0x9183d6da, L:/127.0.0.1:57681 - R:localhost/127.0.0.1:8000] Writing object DefaultFullHttpRequest(decodeResult: success, version: HTTP/1.1, content: UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 0, cap: 0))
GET /api/v1/watch/namespaces/default/events HTTP/1.1
user-agent: ReactorNetty/0.7.1.RELEASE
Host: localhost:8000
accept-encoding: gzip
Accept: application/json
content-length: 0

Une façon d’avoir moins de bogues est de ne pas écrire de code quand cela est possible.

Nov 2018 :

Avec spring-webflux:5.1.2.RELEASE, ce qui précède ne fonctionne plus. Utilisez les éléments suivants à la place:

logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions=DEBUG
...
2018-11-06 20:58:58.181 DEBUG 20300 --- [           main] o.s.w.r.f.client.ExchangeFunctions       : [2026fbff] HTTP GET http://localhost:8080/stocks/search?symbol=AAPL
2018-11-06 20:58:58.451 DEBUG 20300 --- [ctor-http-nio-4] o.s.w.r.f.client.ExchangeFunctions       : [2026fbff] Response 400 BAD_REQUEST

Pour consigner les en-têtes ou le corps du formulaire, définissez la valeur ci-dessus sur TRACE level; Cependant, cela ne suffit pas:

ExchangeStrategies exchangeStrategies = ExchangeStrategies.withDefaults();
exchangeStrategies
    .messageWriters().stream()
    .filter(LoggingCodecSupport.class::isInstance)
    .forEach(writer -> ((LoggingCodecSupport)writer).setEnableLoggingRequestDetails(true));

client = WebClient.builder()
    .exchangeStrategies(exchangeStrategies)

mars 2019 :

En réponse à une question du commentaire qui demandait comment consigner le corps de la demande et du corps de la réponse, je ne sais pas si Spring a un tel enregistreur, mais WebClient est construit sur Netty, permettant ainsi la journalisation du débogage pour le paquet reactor.ipc.netty devrait fonctionner, avec this answer.

22
Abhijit Sarkar

Si vous ne voulez pas connecter le corps, c'est très simple.

Botte à ressort> = 2.1.0

Ajoutez les éléments suivants au fichier application.properties:

logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions=TRACE
spring.http.log-request-details=true

La deuxième ligne entraîne l’inclusion des en-têtes dans le journal.

Botte de printemps <2.1.0

Ajoutez les éléments suivants au fichier application.properties:

logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions=TRACE

Au lieu de la deuxième ligne ci-dessus, vous devez déclarer une classe comme celle-ci:

@Configuration
static class LoggingCodecConfig {

    @Bean
    @Order(0)
    public CodecCustomizer loggingCodecCustomizer() {
        return (configurer) -> configurer.defaultCodecs()
                .enableLoggingRequestDetails(true);
    }

}

Gracieuseté de cette réponse de Brian Clozel

9
Fletch

Vous pouvez demander à netty de consigner la demande/les réponses en lui demandant de procéder à une écoute électronique. Si vous créez votre WebClient Spring comme ceci, il active l’option d’écoute électronique.

        WebClient webClient = WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                HttpClient.create().wiretap(true)
            ))
            .build()

et puis avoir votre configuration de journalisation:

logging.level.reactor.netty.http.client.HttpClient: DEBUG

cela enregistrera tout pour la demande/réponse (y compris les corps), mais le format n'est pas spécifique à HTTP, donc pas très lisible.

8
Matthew Buckett