Switch defaults and model for logging sensitive data

Issue: SPR-17029
This commit is contained in:
Rossen Stoyanchev
2018-07-10 16:18:31 -04:00
parent a40d25a760
commit 1b1bc7f5b5
34 changed files with 241 additions and 229 deletions

View File

@@ -111,19 +111,13 @@ public interface CodecConfigurer {
void jackson2JsonEncoder(Encoder<?> encoder);
/**
* Whether to disable logging of request details for form and multipart
* requests at any log level. By default such data is logged under
* {@code "org.springframework.http.codec"} but may contain sensitive
* information. Typically that's not an issue since DEBUG is used in
* development, but this option may be used to explicitly disable any
* logging of form and multipart data at any log level.
* <p>By default this is set to {@code false} in which case form and
* multipart data is logged at DEBUG or TRACE. When set to {@code true}
* values will not be logged at any level.
* @param disableLoggingRequestDetails whether to disable loggins
* Whether to log form data at DEBUG level, and headers at TRACE level.
* Both may contain sensitive information.
* <p>By default set to {@code false} so that request details are not shown.
* @param enable whether to enable or not
* @since 5.1
*/
void disableLoggingRequestDetails(boolean disableLoggingRequestDetails);
void enableLoggingRequestDetails(boolean enable);
}

View File

@@ -108,8 +108,10 @@ public class FormHttpMessageReader extends LoggingCodecSupport
String body = charBuffer.toString();
DataBufferUtils.release(buffer);
MultiValueMap<String, String> formData = parseFormData(charset, body);
if (shouldLogRequestDetails()) {
logger.debug(Hints.getLogPrefix(hints) + "Decoded " + formData);
if (logger.isDebugEnabled()) {
String details = isEnableLoggingRequestDetails() ?
formData.toString() : "form fields " + formData.keySet() + " (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Read " + details);
}
return formData;
});

View File

@@ -131,8 +131,10 @@ public class FormHttpMessageWriter extends LoggingCodecSupport
Assert.notNull(charset, "No charset"); // should never occur
return Mono.from(inputStream).flatMap(form -> {
if (shouldLogRequestDetails()) {
logger.debug(Hints.getLogPrefix(hints) + "Encoding " + form);
if (logger.isDebugEnabled()) {
String details = isEnableLoggingRequestDetails() ?
form.toString() : "form fields " + form.keySet() + " (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Writing " + details);
}
String value = serializeForm(form, charset);
ByteBuffer byteBuffer = charset.encode(value);

View File

@@ -33,41 +33,26 @@ public class LoggingCodecSupport {
protected final Log logger = HttpLog.create(LogFactory.getLog(getClass()));
/** Do not log potentially sensitive information (params at DEBUG and headers at TRACE). */
private boolean disableLoggingRequestDetails = false;
/** Whether to log potentially sensitive info (form data at DEBUG and headers at TRACE). */
private boolean enableLoggingRequestDetails = false;
/**
* Whether to disable any logging of request details by this codec.
* By default values being encoded or decoded are logged at DEBUG and TRACE
* level under {@code "org.springframework.http.codec"} which may show
* sensitive data for form and multipart data. Typically that's not an issue
* since DEBUG and TRACE are intended for development, but this property may
* be used to explicitly disable any logging of such information regardless
* of the log level.
* <p>By default this is set to {@code false} in which case values encoded
* or decoded are logged at DEBUG level. When set to {@code true} values
* will not be logged at any level.
* @param disableLoggingRequestDetails whether to disable
* Whether to log form data at DEBUG level, and headers at TRACE level.
* Both may contain sensitive information.
* <p>By default set to {@code false} so that request details are not shown.
* @param enable whether to enable or not
*/
public void setDisableLoggingRequestDetails(boolean disableLoggingRequestDetails) {
this.disableLoggingRequestDetails = disableLoggingRequestDetails;
public void setEnableLoggingRequestDetails(boolean enable) {
this.enableLoggingRequestDetails = enable;
}
/**
* Whether any logging of values being encoded or decoded is explicitly
* disabled regardless of log level.
*/
public boolean isDisableLoggingRequestDetails() {
return this.disableLoggingRequestDetails;
}
/**
* Returns "true" if logger is at DEBUG level and the logging of values
* being encoded or decoded is not explicitly disabled.
*/
protected boolean shouldLogRequestDetails() {
return !this.disableLoggingRequestDetails && logger.isDebugEnabled();
public boolean isEnableLoggingRequestDetails() {
return this.enableLoggingRequestDetails;
}
}

View File

@@ -145,7 +145,7 @@ public class ResourceHttpMessageWriter implements HttpMessageWriter<Resource> {
return mediaType;
}
mediaType = MediaTypeFactory.getMediaType(resource).orElse(MediaType.APPLICATION_OCTET_STREAM);
if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Resource associated with '" + mediaType + "'");
}
return mediaType;

View File

@@ -112,7 +112,7 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
return tokens.map(tokenBuffer -> {
try {
Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper()));
if (logger.isDebugEnabled()) {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) +"Decoded [" + value + "]");
}
return value;

View File

@@ -141,7 +141,7 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
private DataBuffer encodeValue(Object value, @Nullable MimeType mimeType, DataBufferFactory bufferFactory,
ResolvableType elementType, @Nullable Map<String, Object> hints, JsonEncoding encoding) {
if (logger.isDebugEnabled() && !Hints.suppressLogging(hints)) {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Encoding [" + value + "]");
}

View File

@@ -27,9 +27,11 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Hints;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.LoggingCodecSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
@@ -46,7 +48,8 @@ import org.springframework.util.MultiValueMap;
* @author Rossen Stoyanchev
* @since 5.0
*/
public class MultipartHttpMessageReader implements HttpMessageReader<MultiValueMap<String, Part>> {
public class MultipartHttpMessageReader extends LoggingCodecSupport
implements HttpMessageReader<MultiValueMap<String, Part>> {
private static final ResolvableType MULTIPART_VALUE_TYPE = ResolvableType.forClassWithGenerics(
MultiValueMap.class, String.class, Part.class);
@@ -85,8 +88,19 @@ public class MultipartHttpMessageReader implements HttpMessageReader<MultiValueM
public Mono<MultiValueMap<String, Part>> readMono(ResolvableType elementType,
ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
return this.partReader.read(elementType, inputMessage, hints)
.collectMultimap(Part::name).map(this::toMultiValueMap);
Map<String, Object> allHints = Hints.merge(hints, Hints.SUPPRESS_LOGGING_HINT, true);
return this.partReader.read(elementType, inputMessage, allHints)
.collectMultimap(Part::name)
.doOnNext(map -> {
if (logger.isDebugEnabled()) {
String details = isEnableLoggingRequestDetails() ?
map.toString() : "parts " + map.keySet() + " (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Parsed " + details);
}
})
.map(this::toMultiValueMap);
}
private LinkedMultiValueMap<String, Part> toMultiValueMap(Map<String, Collection<Part>> map) {

View File

@@ -225,8 +225,10 @@ public class MultipartHttpMessageWriter extends LoggingCodecSupport
outputMessage.getHeaders().setContentType(new MediaType(MediaType.MULTIPART_FORM_DATA, params));
if (shouldLogRequestDetails()) {
logger.debug(Hints.getLogPrefix(hints) + "Encoding " + map);
if (logger.isDebugEnabled()) {
String details = isEnableLoggingRequestDetails() ?
map.toString() : "parts " + map.keySet() + " (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Encoding " + details);
}
Flux<DataBuffer> body = Flux.fromIterable(map.entrySet())

View File

@@ -95,8 +95,10 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
public Flux<Part> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints) {
return Flux.create(new SynchronossPartGenerator(message, this.bufferFactory, this.streamStorageFactory))
.doOnNext(part -> {
if (shouldLogRequestDetails()) {
logger.debug(Hints.getLogPrefix(hints) + "Decoded [" + part + "]");
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
String details = isEnableLoggingRequestDetails() ?
part.toString() : "parts '" + part.name() + "' (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Parsed " + details);
}
});
}

View File

@@ -74,7 +74,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
@Nullable
private Encoder<?> jackson2JsonEncoder;
private boolean disableLoggingRequestDetails = false;
private boolean enableLoggingRequestDetails = false;
private boolean registerDefaults = true;
@@ -90,12 +90,12 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
}
@Override
public void disableLoggingRequestDetails(boolean disableLoggingRequestDetails) {
this.disableLoggingRequestDetails = disableLoggingRequestDetails;
public void enableLoggingRequestDetails(boolean enable) {
this.enableLoggingRequestDetails = enable;
}
protected boolean isDisableLoggingRequestDetails() {
return this.disableLoggingRequestDetails;
protected boolean isEnableLoggingRequestDetails() {
return this.enableLoggingRequestDetails;
}
/**
@@ -121,7 +121,7 @@ class BaseDefaultCodecs implements CodecConfigurer.DefaultCodecs {
readers.add(new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly()));
FormHttpMessageReader formReader = new FormHttpMessageReader();
formReader.setDisableLoggingRequestDetails(this.disableLoggingRequestDetails);
formReader.setEnableLoggingRequestDetails(this.enableLoggingRequestDetails);
readers.add(formReader);
extendTypedReaders(readers);

View File

@@ -88,10 +88,10 @@ class ClientDefaultCodecsImpl extends BaseDefaultCodecs implements ClientCodecCo
protected void extendTypedWriters(List<HttpMessageWriter<?>> typedWriters) {
FormHttpMessageWriter formWriter = new FormHttpMessageWriter();
formWriter.setDisableLoggingRequestDetails(isDisableLoggingRequestDetails());
formWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails());
MultipartHttpMessageWriter multipartWriter = new MultipartHttpMessageWriter(getPartWriters(), formWriter);
multipartWriter.setDisableLoggingRequestDetails(isDisableLoggingRequestDetails());
multipartWriter.setEnableLoggingRequestDetails(isEnableLoggingRequestDetails());
typedWriters.add(multipartWriter);
}

View File

@@ -52,10 +52,15 @@ class ServerDefaultCodecsImpl extends BaseDefaultCodecs implements ServerCodecCo
@Override
protected void extendTypedReaders(List<HttpMessageReader<?>> typedReaders) {
if (synchronossMultipartPresent) {
boolean enable = isEnableLoggingRequestDetails();
SynchronossPartHttpMessageReader partReader = new SynchronossPartHttpMessageReader();
partReader.setDisableLoggingRequestDetails(isDisableLoggingRequestDetails());
partReader.setEnableLoggingRequestDetails(enable);
typedReaders.add(partReader);
typedReaders.add(new MultipartHttpMessageReader(partReader));
MultipartHttpMessageReader reader = new MultipartHttpMessageReader(partReader);
reader.setEnableLoggingRequestDetails(enable);
typedReaders.add(reader);
}
}

View File

@@ -74,7 +74,7 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
protected Flux<DataBuffer> encode(Object value, DataBufferFactory dataBufferFactory,
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
try {
if (logger.isDebugEnabled() && !Hints.suppressLogging(hints)) {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Encoding [" + value + "]");
}
DataBuffer buffer = dataBufferFactory.allocateBuffer(1024);

View File

@@ -57,7 +57,7 @@ public class ReactorHttpHandlerAdapter implements BiFunction<HttpServerRequest,
NettyDataBufferFactory bufferFactory = new NettyDataBufferFactory(reactorResponse.alloc());
try {
ReactorServerHttpRequest request = new ReactorServerHttpRequest(reactorRequest, bufferFactory);
ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory, request);
ServerHttpResponse response = new ReactorServerHttpResponse(reactorResponse, bufferFactory);
if (request.getMethod() == HttpMethod.HEAD) {
response = new HttpHeadResponseDecorator(response);

View File

@@ -165,13 +165,7 @@ class ReactorServerHttpRequest extends AbstractServerHttpRequest {
@Override
public Flux<DataBuffer> getBody() {
return this.request.receive().retain()
.doOnNext(buffer -> {
if (logger.isTraceEnabled()) {
logger.trace(getLogPrefix() + "Read " + buffer.readableBytes() + " bytes");
}
})
.map(this.bufferFactory::wrap);
return this.request.receive().retain().map(this.bufferFactory::wrap);
}
@SuppressWarnings("unchecked")

View File

@@ -45,16 +45,11 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
private final HttpServerResponse response;
private final ReactorServerHttpRequest request;
public ReactorServerHttpResponse(HttpServerResponse response, DataBufferFactory bufferFactory,
ReactorServerHttpRequest request) {
public ReactorServerHttpResponse(HttpServerResponse response, DataBufferFactory bufferFactory) {
super(bufferFactory);
Assert.notNull(response, "HttpServerResponse must not be null");
this.response = response;
this.request = request;
}
@@ -119,12 +114,7 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
}
private Publisher<ByteBuf> toByteBufs(Publisher<? extends DataBuffer> dataBuffers) {
return Flux.from(dataBuffers).map(NettyDataBufferFactory::toByteBuf)
.doOnNext(byteBuf -> {
if (logger.isTraceEnabled()) {
logger.trace("Writing " + byteBuf.readableBytes() + " bytes");
}
});
return Flux.from(dataBuffers).map(NettyDataBufferFactory::toByteBuf);
}
}

View File

@@ -199,15 +199,7 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
@Nullable
DataBuffer readFromInputStream() throws IOException {
int read = this.request.getInputStream().read(this.buffer);
if (logger.isTraceEnabled()) {
logger.trace(getLogPrefix() + "Read " + read + (read != -1 ? " bytes" : ""));
}
else {
Log rsReadLogger = AbstractListenerReadPublisher.rsReadLogger;
if (rsReadLogger.isTraceEnabled()) {
rsReadLogger.trace(getLogPrefix() + "Read " + read + (read != -1 ? " bytes" : ""));
}
}
logBytesRead(read);
if (read > 0) {
DataBuffer dataBuffer = this.bufferFactory.allocateBuffer(read);
@@ -222,6 +214,13 @@ class ServletServerHttpRequest extends AbstractServerHttpRequest {
return null;
}
protected final void logBytesRead(int read) {
Log rsReadLogger = AbstractListenerReadPublisher.rsReadLogger;
if (rsReadLogger.isTraceEnabled()) {
rsReadLogger.trace(getLogPrefix() + "Read " + read + (read != -1 ? " bytes" : ""));
}
}
@SuppressWarnings("unchecked")
@Override
public <T> T getNativeRequest() {

View File

@@ -86,9 +86,7 @@ public class TomcatHttpHandlerAdapter extends ServletHttpHandlerAdapter {
ServletRequest request = getNativeRequest();
int read = ((CoyoteInputStream) request.getInputStream()).read(byteBuffer);
if (logger.isTraceEnabled()) {
logger.trace(getLogPrefix() + "read:" + read);
}
logBytesRead(read);
if (read > 0) {
dataBuffer.writePosition(read);

View File

@@ -31,7 +31,6 @@ import io.undertow.connector.PooledByteBuffer;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.handlers.Cookie;
import io.undertow.util.HeaderValues;
import org.apache.commons.logging.Log;
import org.xnio.channels.StreamSourceChannel;
import reactor.core.publisher.Flux;
@@ -182,11 +181,7 @@ class UndertowServerHttpRequest extends AbstractServerHttpRequest {
ByteBuffer byteBuffer = pooledByteBuffer.getBuffer();
int read = this.channel.read(byteBuffer);
Log logger = UndertowServerHttpRequest.this.logger;
if (logger.isTraceEnabled()) {
logger.trace(getLogPrefix() + "Read " + read + (read != -1 ? " bytes" : ""));
}
else if (rsReadLogger.isTraceEnabled()) {
if (rsReadLogger.isTraceEnabled()) {
rsReadLogger.trace(getLogPrefix() + "Read " + read + (read != -1 ? " bytes" : ""));
}

View File

@@ -121,18 +121,21 @@ public class DefaultServerWebExchange implements ServerWebExchange {
Assert.notNull(codecConfigurer, "'codecConfigurer' is required");
Assert.notNull(localeContextResolver, "'localeContextResolver' is required");
// Initialize before first call to getLogPrefix()
this.attributes.put(ServerWebExchange.LOG_ID_ATTRIBUTE, request.getId());
this.request = request;
this.response = response;
this.sessionMono = sessionManager.getSession(this).cache();
this.localeContextResolver = localeContextResolver;
this.formDataMono = initFormData(request, codecConfigurer);
this.multipartDataMono = initMultipartData(request, codecConfigurer);
this.formDataMono = initFormData(request, codecConfigurer, getLogPrefix());
this.multipartDataMono = initMultipartData(request, codecConfigurer, getLogPrefix());
this.applicationContext = applicationContext;
}
@SuppressWarnings("unchecked")
private static Mono<MultiValueMap<String, String>> initFormData(ServerHttpRequest request,
ServerCodecConfigurer configurer) {
ServerCodecConfigurer configurer, String logPrefix) {
try {
MediaType contentType = request.getHeaders().getContentType();
@@ -141,7 +144,7 @@ public class DefaultServerWebExchange implements ServerWebExchange {
.filter(reader -> reader.canRead(FORM_DATA_TYPE, MediaType.APPLICATION_FORM_URLENCODED))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No form data HttpMessageReader.")))
.readMono(FORM_DATA_TYPE, request, Hints.none())
.readMono(FORM_DATA_TYPE, request, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix))
.switchIfEmpty(EMPTY_FORM_DATA)
.cache();
}
@@ -154,7 +157,7 @@ public class DefaultServerWebExchange implements ServerWebExchange {
@SuppressWarnings("unchecked")
private static Mono<MultiValueMap<String, Part>> initMultipartData(ServerHttpRequest request,
ServerCodecConfigurer configurer) {
ServerCodecConfigurer configurer, String logPrefix) {
try {
MediaType contentType = request.getHeaders().getContentType();
@@ -163,7 +166,7 @@ public class DefaultServerWebExchange implements ServerWebExchange {
.filter(reader -> reader.canRead(MULTIPART_DATA_TYPE, MediaType.MULTIPART_FORM_DATA))
.findFirst()
.orElseThrow(() -> new IllegalStateException("No multipart HttpMessageReader.")))
.readMono(MULTIPART_DATA_TYPE, request, Hints.none())
.readMono(MULTIPART_DATA_TYPE, request, Hints.from(Hints.LOG_PREFIX_HINT, logPrefix))
.switchIfEmpty(EMPTY_MULTIPART_DATA)
.cache();
}

View File

@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
import org.springframework.context.ApplicationContext;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.LoggingCodecSupport;
import org.springframework.http.codec.ServerCodecConfigurer;
@@ -94,8 +95,8 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
@Nullable
private ApplicationContext applicationContext;
/** Do not log potentially sensitive data (query/form at DEBUG, headers at TRACE). */
private boolean disableLoggingRequestDetails = false;
/** Whether to log potentially sensitive info (form data at DEBUG, headers at TRACE). */
private boolean enableLoggingRequestDetails = false;
public HttpWebHandlerAdapter(WebHandler delegate) {
@@ -132,12 +133,12 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
Assert.notNull(codecConfigurer, "ServerCodecConfigurer is required");
this.codecConfigurer = codecConfigurer;
this.disableLoggingRequestDetails = false;
this.enableLoggingRequestDetails = false;
this.codecConfigurer.getReaders().stream()
.filter(LoggingCodecSupport.class::isInstance)
.forEach(reader -> {
if (((LoggingCodecSupport) reader).isDisableLoggingRequestDetails()) {
this.disableLoggingRequestDetails = true;
if (((LoggingCodecSupport) reader).isEnableLoggingRequestDetails()) {
this.enableLoggingRequestDetails = true;
}
});
}
@@ -195,17 +196,11 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
*/
public void afterPropertiesSet() {
if (logger.isDebugEnabled()) {
if (this.disableLoggingRequestDetails) {
logger.debug("Logging query, form data, multipart data, and headers is OFF.");
}
else {
logger.warn("\n\n" +
"!!!!!!!!!!!!!!!!!!!\n" +
"Logging query, form and multipart data (DEBUG), and headers (TRACE) may show sensitive data.\n" +
"If not in development, set \"disableLoggingRequestDetails(true)\" on ServerCodecConfigurer,\n" +
"or lower the log level.\n" +
"!!!!!!!!!!!!!!!!!!!\n");
}
String value = this.enableLoggingRequestDetails ?
"shown which may lead to unsafe logging of potentially sensitive data" :
"masked to prevent unsafe logging of potentially sensitive data";
logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
"': form data and headers will be " + value);
}
}
@@ -214,7 +209,6 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {
ServerWebExchange exchange = createExchange(request, response);
exchange.getAttributes().put(ServerWebExchange.LOG_ID_ATTRIBUTE, request.getId());
logExchange(exchange);
return getDelegate().handle(exchange)
@@ -233,8 +227,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
String logPrefix = exchange.getLogPrefix();
ServerHttpRequest request = exchange.getRequest();
if (logger.isTraceEnabled()) {
String headers = this.disableLoggingRequestDetails ? "" : ", headers=" + request.getHeaders();
logger.trace(logPrefix + formatRequest(request) + headers);
logger.trace(logPrefix + formatRequest(request) + ", headers=" + formatHeaders(request.getHeaders()));
}
else {
logger.debug(logPrefix + formatRequest(request));
@@ -243,11 +236,8 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
}
private String formatRequest(ServerHttpRequest request) {
String query = "";
if (!this.disableLoggingRequestDetails) {
String rawQuery = request.getURI().getRawQuery();
query = StringUtils.hasText(rawQuery) ? "?" + rawQuery : "";
}
String rawQuery = request.getURI().getRawQuery();
String query = StringUtils.hasText(rawQuery) ? "?" + rawQuery : "";
return "HTTP " + request.getMethod() + " \"" + request.getPath() + query + "\"";
}
@@ -258,8 +248,7 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
HttpStatus status = response.getStatusCode();
String message = "Completed " + (status != null ? status : "200 OK");
if (logger.isTraceEnabled()) {
String headers = this.disableLoggingRequestDetails ? "" : ", headers=" + response.getHeaders();
logger.trace(logPrefix + message + headers);
logger.trace(logPrefix + message + ", headers=" + formatHeaders(response.getHeaders()));
}
else {
logger.debug(logPrefix + message);
@@ -267,6 +256,11 @@ public class HttpWebHandlerAdapter extends WebHandlerDecorator implements HttpHa
}
}
private String formatHeaders(HttpHeaders responseHeaders) {
return this.enableLoggingRequestDetails ?
responseHeaders.toString() : responseHeaders.isEmpty() ? "{}" : "{masked}";
}
private Mono<Void> handleUnresolvedError(ServerWebExchange exchange, Throwable ex) {
ServerHttpRequest request = exchange.getRequest();