An ExchangeFilterFunction can record outbound method and approved route metadata; logging the complete URL, headers or body can leak credentials and tenant data.
Spring WebClient request audit: log route identity without payload leakage
Record a bounded event
For a receipt gateway, an outbound audit event may need the operation name, method, result category and duration. The request URL can include a token or personal identifier in its query, so omit the query and use an approved route label when paths contain IDs. Do not dump Authorization or Cookie headers. A request attribute] can carry an internal operation label for this single exchange.
Keep the response body owned
A filter that forwards next.exchange(request) can observe status without consuming the body. If it instead reads the body to print it, the caller may no longer be able to decode it and pooled buffers may remain unreleased. Capture timing around the publisher and pass the same response onward. Response ownership] explains how a filter must release a body when it terminates an exchange.
Verify safe failure paths
Use a mock HTTP server to return a success, a non-2xx response, and a connection failure. Assert one bounded event per subscription and check that secrets and query parameters never enter captured logs. Also verify the caller can still decode the body. A filter runs on subscription, so constructing a Mono alone should emit no audit event.
Implementation contract
ExchangeFilterFunction requestAudit = (request, next) -> {
String operation = request.attribute("operation")
.map(String::valueOf).orElse("unclassified");
long started = System.nanoTime();
return next.exchange(request)
.doOnNext(response -> auditLog.info("outbound={} method={} status={} elapsedMs={}",
operation, request.method(), response.statusCode().value(),
Duration.ofNanos(System.nanoTime() - started).toMillis()))
.doOnError(failure -> auditLog.warn("outbound={} method={} failed",
operation, request.method()));
};Cost and verification
One event per subscribed request adds log volume and formatting work. Sampling or aggregation may be needed at high request rates; logging bodies creates far greater memory, latency and privacy cost.
Common Mistakes
- Do not log full URLs with query strings, credentials or personal IDs.
- Do not consume the response body in an audit filter and then hand the empty response to the caller.
- Do not assume a constructed but unsubscribed Mono sent a request.
Read next
Spring WebClient exchangeToMono: decode the response inside its callback, Spring WebClient attributes versus Reactor Context: choose the right request scope, Spring WebClient status-specific decoding: consume one branch and close the rest, Spring Filter versus HandlerInterceptor: choose the right request boundary, Spring behind a proxy: trust forwarded headers only after the edge strips them.
