From 89471e688be22f5f8e44e51eb82924e747ec8696 Mon Sep 17 00:00:00 2001 From: Simone Conte Date: Sat, 11 Oct 2025 09:43:18 +0100 Subject: [PATCH] Introduce queryParamPredicate in AbstractRequestLoggingFilter Signed-off-by: Simone Conte --- .../filter/AbstractRequestLoggingFilter.java | 47 +++++++++++++++++++ .../web/filter/RequestLoggingFilterTests.java | 7 +-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java b/spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java index 37194341fabd..4d4552edcd6e 100644 --- a/spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java +++ b/spring-web/src/main/java/org/springframework/web/filter/AbstractRequestLoggingFilter.java @@ -31,8 +31,11 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; import org.springframework.web.util.ContentCachingRequestWrapper; +import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.WebUtils; /** @@ -99,6 +102,8 @@ public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter private boolean includePayload = false; + private @Nullable Predicate queryParamPredicate; + private @Nullable Predicate headerPredicate; private int maxPayloadLength = DEFAULT_MAX_PAYLOAD_LENGTH; @@ -182,6 +187,30 @@ protected boolean isIncludePayload() { return this.includePayload; } + /** + * Configure a predicate for selecting which query params should be logged if + * {@link #setIncludeQueryString(boolean)} is set to {@code true}. + *

By default this is not set in which case all query params are logged + * + *

If there are multiple values for the same query param, + * the predicate will be applied once per query param name. + * As a result, the use of this predicate may result in a different query string + * than the one returned by {@link HttpServletRequest#getQueryString()}. + * @param queryParamPredicate the predicate to use + * @since 7.0 + */ + public void setQueryParamPredicate(@Nullable Predicate queryParamPredicate) { + this.queryParamPredicate = queryParamPredicate; + } + + /** + * The configured {@link #setQueryParamPredicate(Predicate) queryParamPredicate}. + * @since 7.0 + */ + protected @Nullable Predicate getQueryParamPredicate() { + return this.queryParamPredicate; + } + /** * Configure a predicate for selecting which headers should be logged if * {@link #setIncludeHeaders(boolean)} is set to {@code true}. @@ -326,6 +355,24 @@ protected String createMessage(HttpServletRequest request, String prefix, String if (isIncludeQueryString()) { String queryString = request.getQueryString(); if (queryString != null) { + if (getQueryParamPredicate() != null) { + MultiValueMap queryParams = UriComponentsBuilder.fromUriString("?" + queryString) + .build() + .getQueryParams(); + + MultiValueMap updatedQueryParams = new LinkedMultiValueMap<>(queryParams); + for (String name : queryParams.keySet()) { + if (!getQueryParamPredicate().test(name)) { + updatedQueryParams.set(name, "masked"); + break; + } + } + + queryString = UriComponentsBuilder.newInstance() + .queryParams(updatedQueryParams) + .build() + .getQuery(); + } msg.append('?').append(queryString); } } diff --git a/spring-web/src/test/java/org/springframework/web/filter/RequestLoggingFilterTests.java b/spring-web/src/test/java/org/springframework/web/filter/RequestLoggingFilterTests.java index b754072b1f16..0fdf256a05fc 100644 --- a/spring-web/src/test/java/org/springframework/web/filter/RequestLoggingFilterTests.java +++ b/spring-web/src/test/java/org/springframework/web/filter/RequestLoggingFilterTests.java @@ -108,13 +108,14 @@ void uri() throws Exception { @Test void queryStringIncluded() throws Exception { - request.setQueryString("booking=42"); + request.setQueryString("booking=42&code=73&category=hotel&code=37&category=resort"); filter.setIncludeQueryString(true); + filter.setQueryParamPredicate(name -> !name.equals("code") && !name.equals("ignore")); applyFilter(); - assertThat(filter.beforeRequestMessage).contains("/hotels?booking=42"); - assertThat(filter.afterRequestMessage).contains("/hotels?booking=42"); + assertThat(filter.beforeRequestMessage).contains("/hotels?booking=42&code=masked&category=hotel&category=resort"); + assertThat(filter.afterRequestMessage).contains("/hotels?booking=42&code=masked&category=hotel&category=resort"); } @Test