How to log request and response bodies in Spring WebFlux

Koguro :

I want to have centralised logging for requests and responses in my REST API on Spring WebFlux with Kotlin. So far I've tried this approaches

@Bean
fun apiRouter() = router {
    (accept(MediaType.APPLICATION_JSON) and "/api").nest {
        "/user".nest {
            GET("/", userHandler::listUsers)
            POST("/{userId}", userHandler::updateUser)
        }
    }
}.filter { request, next ->
    logger.info { "Processing request $request with body ${request.bodyToMono<String>()}" }
    next.handle(request).doOnSuccess { logger.info { "Handling with response $it" } }
}

Here request method and path log successfully but the body is Mono, so how should I log it? Should it be the other way around and I have to subscribe on request body Mono and log it in the callback? Another problem is that ServerResponse interface here doesn't have access to the response body. How can I get it here?


Another approach I've tried is using WebFilter

@Bean
fun loggingFilter(): WebFilter =
        WebFilter { exchange, chain ->
            val request = exchange.request
            logger.info { "Processing request method=${request.method} path=${request.path.pathWithinApplication()} params=[${request.queryParams}] body=[${request.body}]"  }

            val result = chain.filter(exchange)

            logger.info { "Handling with response ${exchange.response}" }

            return@WebFilter result
        }

Same problem here: request body is Flux and no response body.

Is there a way to access full request and response for logging from some filters? What don't I understand?

Brian Clozel :

This is more or less similar to the situation in Spring MVC.

In Spring MVC, you can use a AbstractRequestLoggingFilter filter and ContentCachingRequestWrapper and/or ContentCachingResponseWrapper. Many tradeoffs here:

  • if you'd like to access servlet request attributes, you need to actually read and parse the request body
  • logging the request body means buffering the request body, which can use a significant amount of memory
  • if you'd like to access the response body, you need to wrap the response and buffer the response body as it's being written, for later retrieval

ContentCaching*Wrapper classes don't exist in WebFlux but you could create similar ones. But keep in mind other points here:

  • buffering data in memory somehow goes against the reactive stack, since we're trying there to be very efficient with the available resources
  • you should not tamper with the actual flow of data and flush more/less often than expected, otherwise you'd risk breaking streaming uses cases
  • at that level, you only have access to DataBuffer instances, which are (roughly) memory-efficient byte arrays. Those belong to buffer pools and are recycled for other exchanges. If those aren't properly retained/released, memory leaks are created (and buffering data for later consumption certainly fits that scenario)
  • again at that level, it's only bytes and you don't have access to any codec to parse the HTTP body. I'd forget about buffering the content if it's not human-readable in the first place

Other answers to your question:

  • yes, the WebFilter is probably the best approach
  • no, you shouldn't subscribe to the request body otherwise you'd consume data that the handler won't be able to read; you can flatMap on the request and buffer data in doOn operators
  • wrapping the response should give you access to the response body as it's being written; don't forget about memory leaks, though

Este artigo é coletado da Internet.

Se houver alguma infração, entre em [email protected] Delete.

editar em
0

deixe-me dizer algumas palavras

0comentários
loginDepois de participar da revisão

Artigos relacionados

How to log soap request and response with custom messages to file in Spring Boot?

Spring Webflux Reactor Netty: HTTP Request / Response Hex Dump?

Capturing response in spring Webflux

Spring RestTemplate - Log on request sometimes hangs awaiting response

Spring webflux non-blocking response

spring-integration: Webflux inboundGateway not mapped to request

Spring WebFlux. How to get the request body in two different formats using @RequestBody annotation?

How to use Jaeger with Spring WebFlux?

Spring WebFlux - Why I have to wait for WebClient response?

Converter Flux <T> em Mono <Response <T>> no Spring Webflux

Spring WebFlux - Why I have to wait for WebClient response?

Combine request and response based on field in log - ELK

How to log request and response for 4XX Http status in Django Rest Framework?

How to return GZIP responses with Spring Webflux?

How to set a timeout in Spring 5 WebFlux WebClient

How to use Hystrix with Spring WebFlux WebClients?

How to send an Array by Response/Request?

How to continually consume from Kafka topic using spring webflux?

Spring webflux filter: How to get the reactor context after the query execution?

Using spring WebFlux, how can I get all the RequestHandlerMappings?

How to modify or update POJO models at instantiating Java Spring Webflux

How to register multiple RouterFunctions in Spring 5 webflux via RouterFunctionMapping?

How to handle a page refresh using html 5 mode & Spring webflux

How to log every response in laravel 5.2 framework

Spring Webflux - "scanAvailable": true

Teste Spring Webflux

Spring WebFlux с Kafka и Websockets

Spring WebFlux e WebSocket

Spring webflux - multi Mono

TOP lista

quentelabel

Arquivo