Truncate logged encoded and decoded values if necessary

At DEBUG show up to 100 chars, at TRACE show full formatted value.

Note that the formatValue helper method is duplicated a number of times
in this commit. A utility method will likely be added in spring-core
through an extra commit.

Issue: SPR-17254
This commit is contained in:
Rossen Stoyanchev
2018-09-14 12:20:03 -04:00
parent 66c66baa8f
commit e62298eaad
16 changed files with 187 additions and 32 deletions

View File

@@ -108,15 +108,26 @@ public class FormHttpMessageReader extends LoggingCodecSupport
String body = charBuffer.toString();
DataBufferUtils.release(buffer);
MultiValueMap<String, String> formData = parseFormData(charset, body);
if (logger.isDebugEnabled()) {
String details = isEnableLoggingRequestDetails() ?
formData.toString() : "form fields " + formData.keySet() + " (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Read " + details);
}
logFormData(formData, hints);
return formData;
});
}
private void logFormData(MultiValueMap<String, String> formData, Map<String, Object> hints) {
if (logger.isDebugEnabled()) {
String s = Hints.getLogPrefix(hints) + "Read " +
(isEnableLoggingRequestDetails() ?
formatValue(formData, logger.isTraceEnabled()) :
"form fields " + formData.keySet() + " (content masked)");
if (logger.isTraceEnabled()) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
}
private Charset getMediaTypeCharset(@Nullable MediaType mediaType) {
if (mediaType != null && mediaType.getCharset() != null) {
return mediaType.getCharset();

View File

@@ -132,9 +132,15 @@ public class FormHttpMessageWriter extends LoggingCodecSupport
return Mono.from(inputStream).flatMap(form -> {
if (logger.isDebugEnabled()) {
String details = isEnableLoggingRequestDetails() ?
form.toString() : "form fields " + form.keySet() + " (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Writing " + details);
String s = Hints.getLogPrefix(hints) + "Writing " +
(isEnableLoggingRequestDetails() ?
form.toString() : "form fields " + form.keySet() + " (content masked)");
if (logger.isTraceEnabled()) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
String value = serializeForm(form, charset);
ByteBuffer byteBuffer = charset.encode(value);

View File

@@ -19,6 +19,7 @@ package org.springframework.http.codec;
import org.apache.commons.logging.Log;
import org.springframework.http.HttpLogging;
import org.springframework.lang.Nullable;
/**
* Base class for {@link org.springframework.core.codec.Encoder},
@@ -55,4 +56,20 @@ public class LoggingCodecSupport {
return this.enableLoggingRequestDetails;
}
/**
* Format the given value via {{toString()}}, either in full or truncated
* if it has 100 or more characters.
* @param value the value to format
* @param logFullValue whether to log in full or truncate if necessary
* @return the formatted value
* @since 5.1
*/
protected String formatValue(@Nullable Object value, boolean logFullValue) {
if (value == null) {
return "";
}
String s = value instanceof CharSequence ? "\"" + value + "\"" : value.toString();
return logFullValue || s.length() < 100 ? s : s.substring(0, 100) + " (truncated)...";
}
}

View File

@@ -116,7 +116,14 @@ public abstract class AbstractJackson2Decoder extends Jackson2CodecSupport imple
try {
Object value = reader.readValue(tokenBuffer.asParser(getObjectMapper()));
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) +"Decoded [" + value + "]");
boolean traceOn = logger.isTraceEnabled();
String s = Hints.getLogPrefix(hints) + "Decoded [" + formatValue(value, traceOn) + "]";
if (traceOn) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
return value;
}

View File

@@ -142,7 +142,14 @@ public abstract class AbstractJackson2Encoder extends Jackson2CodecSupport imple
ResolvableType elementType, @Nullable Map<String, Object> hints, JsonEncoding encoding) {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Encoding [" + value + "]");
boolean traceOn = logger.isTraceEnabled();
String s = Hints.getLogPrefix(hints) + "Encoding [" + formatValue(value, traceOn) + "]";
if (traceOn) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
JavaType javaType = getJavaType(elementType.getType(), null);

View File

@@ -125,4 +125,12 @@ public abstract class Jackson2CodecSupport {
@Nullable
protected abstract <A extends Annotation> A getAnnotation(MethodParameter parameter, Class<A> annotType);
String formatValue(@Nullable Object value, boolean logFullValue) {
if (value == null) {
return "";
}
String s = value instanceof CharSequence ? "\"" + value + "\"" : value.toString();
return logFullValue || s.length() < 100 ? s : s.substring(0, 100) + " (truncated)...";
}
}

View File

@@ -95,9 +95,15 @@ public class MultipartHttpMessageReader extends LoggingCodecSupport
.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);
String s = Hints.getLogPrefix(hints) + "Parsed " +
(isEnableLoggingRequestDetails() ?
map.toString() : "parts " + map.keySet() + " (content masked)");
if (logger.isTraceEnabled()) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
})
.map(this::toMultiValueMap);

View File

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

View File

@@ -96,9 +96,14 @@ public class SynchronossPartHttpMessageReader extends LoggingCodecSupport implem
return Flux.create(new SynchronossPartGenerator(message, this.bufferFactory, this.streamStorageFactory))
.doOnNext(part -> {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
String details = isEnableLoggingRequestDetails() ?
part.toString() : "parts '" + part.name() + "' (content masked)";
logger.debug(Hints.getLogPrefix(hints) + "Parsed " + details);
String s = Hints.getLogPrefix(hints) + "Parsed " + (isEnableLoggingRequestDetails() ?
part.toString() : "parts '" + part.name() + "' (content masked)");
if (logger.isTraceEnabled()) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
});
}

View File

@@ -108,7 +108,14 @@ public class Jaxb2XmlDecoder extends AbstractDecoder<Object> {
return splitEvents.map(events -> {
Object value = unmarshal(events, outputClass);
if (logger.isDebugEnabled()) {
logger.debug(Hints.getLogPrefix(hints) + "Decoded [" + value + "]");
boolean traceOn = logger.isTraceEnabled();
String s = Hints.getLogPrefix(hints) + "Decoded [" + formatValue(value, traceOn) + "]";
if (traceOn) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
return value;
});
@@ -206,6 +213,14 @@ public class Jaxb2XmlDecoder extends AbstractDecoder<Object> {
return xmlEventFlux.flatMap(new SplitFunction(desiredName));
}
String formatValue(@Nullable Object value, boolean logFullValue) {
if (value == null) {
return "";
}
String s = value instanceof CharSequence ? "\"" + value + "\"" : value.toString();
return logFullValue || s.length() < 100 ? s : s.substring(0, 100) + " (truncated)...";
}
private static class SplitFunction implements Function<XMLEvent, Publisher<? extends List<XMLEvent>>> {

View File

@@ -79,7 +79,14 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
try {
if (logger.isDebugEnabled() && !Hints.isLoggingSuppressed(hints)) {
logger.debug(Hints.getLogPrefix(hints) + "Encoding [" + value + "]");
boolean traceOn = logger.isTraceEnabled();
String s = Hints.getLogPrefix(hints) + "Encoding [" + formatValue(value, traceOn) + "]";
if (traceOn) {
logger.trace(s);
}
else {
logger.debug(s);
}
}
DataBuffer buffer = dataBufferFactory.allocateBuffer(1024);
OutputStream outputStream = buffer.asOutputStream();
@@ -97,4 +104,12 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
}
}
String formatValue(@Nullable Object value, boolean logFullValue) {
if (value == null) {
return "";
}
String s = value instanceof CharSequence ? "\"" + value + "\"" : value.toString();
return logFullValue || s.length() < 100 ? s : s.substring(0, 100) + " (truncated)...";
}
}