Logging improvements for WebFlux

Issue: SPR-16898
This commit is contained in:
Rossen Stoyanchev
2018-06-22 22:41:30 -04:00
parent eaffcbe3be
commit 900bc8a2e3
109 changed files with 1106 additions and 671 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
@@ -37,6 +39,8 @@ import org.springframework.util.MimeType;
*/
public abstract class AbstractDecoder<T> implements Decoder<T> {
protected final Log logger = LogFactory.getLog(getClass());
private final List<MimeType> decodableMimeTypes;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,6 +18,10 @@ package org.springframework.core.codec;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
@@ -32,6 +36,8 @@ import org.springframework.util.MimeType;
*/
public abstract class AbstractEncoder<T> implements Encoder<T> {
protected final Log logger = LogFactory.getLog(getClass());
private final List<MimeType> encodableMimeTypes;
@@ -53,4 +59,17 @@ public abstract class AbstractEncoder<T> implements Encoder<T> {
return this.encodableMimeTypes.stream().anyMatch(candidate -> candidate.isCompatibleWith(mimeType));
}
/**
* Helper method to obtain the logger to use from the Map of hints, or fall
* back on the default logger. This may be used for example to override
* logging, e.g. for a multipart request where the full map of part values
* has already been logged.
* @param hints the hints passed to the encode method
* @return the logger to use
* @since 5.1
*/
protected Log getLogger(@Nullable Map<String, Object> hints) {
return hints != null ? ((Log) hints.getOrDefault(Log.class.getName(), logger)) : logger;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,6 +53,9 @@ public class ByteArrayDecoder extends AbstractDataBufferDecoder<byte[]> {
byte[] result = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(result);
DataBufferUtils.release(dataBuffer);
if (logger.isDebugEnabled()) {
logger.debug("Read " + result.length + " bytes");
}
return result;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.core.codec;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -52,7 +53,14 @@ public class ByteArrayEncoder extends AbstractEncoder<byte[]> {
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
return Flux.from(inputStream).map(bufferFactory::wrap);
return Flux.from(inputStream).map(bytes -> {
DataBuffer dataBuffer = bufferFactory.wrap(bytes);
Log logger = getLogger(hints);
if (logger.isDebugEnabled()) {
logger.debug("Writing " + dataBuffer.readableByteCount() + " bytes");
}
return dataBuffer;
});
}
}

View File

@@ -52,10 +52,14 @@ public class ByteBufferDecoder extends AbstractDataBufferDecoder<ByteBuffer> {
protected ByteBuffer decodeDataBuffer(DataBuffer dataBuffer, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
ByteBuffer copy = ByteBuffer.allocate(dataBuffer.readableByteCount());
int byteCount = dataBuffer.readableByteCount();
ByteBuffer copy = ByteBuffer.allocate(byteCount);
copy.put(dataBuffer.asByteBuffer());
copy.flip();
DataBufferUtils.release(dataBuffer);
if (logger.isDebugEnabled()) {
logger.debug("Read " + byteCount + " bytes");
}
return copy;
}

View File

@@ -19,6 +19,7 @@ package org.springframework.core.codec;
import java.nio.ByteBuffer;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -53,7 +54,14 @@ public class ByteBufferEncoder extends AbstractEncoder<ByteBuffer> {
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
return Flux.from(inputStream).map(bufferFactory::wrap);
return Flux.from(inputStream).map(byteBuffer -> {
DataBuffer dataBuffer = bufferFactory.wrap(byteBuffer);
Log logger = getLogger(hints);
if (logger.isDebugEnabled()) {
logger.debug("Writing " + dataBuffer.readableByteCount() + " bytes");
}
return dataBuffer;
});
}
}

View File

@@ -22,6 +22,7 @@ import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -65,6 +66,10 @@ public class CharSequenceEncoder extends AbstractEncoder<CharSequence> {
Charset charset = getCharset(mimeType);
return Flux.from(inputStream).map(charSequence -> {
Log logger = getLogger(hints);
if (logger.isDebugEnabled()) {
logger.debug("Writing '" + charSequence + "'");
}
CharBuffer charBuffer = CharBuffer.wrap(charSequence);
ByteBuffer byteBuffer = charset.encode(charBuffer);
return bufferFactory.wrap(byteBuffer);

View File

@@ -62,6 +62,9 @@ public class DataBufferDecoder extends AbstractDataBufferDecoder<DataBuffer> {
protected DataBuffer decodeDataBuffer(DataBuffer buffer, ResolvableType elementType,
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
if (logger.isDebugEnabled()) {
logger.debug("Read " + buffer.readableByteCount() + " bytes");
}
return buffer;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.core.codec;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@@ -52,7 +53,14 @@ public class DataBufferEncoder extends AbstractEncoder<DataBuffer> {
DataBufferFactory bufferFactory, ResolvableType elementType, @Nullable MimeType mimeType,
@Nullable Map<String, Object> hints) {
return Flux.from(inputStream);
Flux<DataBuffer> flux = Flux.from(inputStream);
Log logger = getLogger(hints);
if (logger.isDebugEnabled()) {
flux = flux.doOnNext(buffer -> logger.debug("Writing " + buffer.readableByteCount() + " bytes"));
}
return flux;
}
}

View File

@@ -72,6 +72,10 @@ public class ResourceDecoder extends AbstractDataBufferDecoder<Resource> {
Class<?> clazz = elementType.getRawClass();
Assert.state(clazz != null, "No resource class");
if (logger.isDebugEnabled()) {
logger.debug("Read " + bytes.length + " bytes");
}
if (InputStreamResource.class == clazz) {
return new InputStreamResource(new ByteArrayInputStream(bytes));
}

View File

@@ -18,6 +18,7 @@ package org.springframework.core.codec;
import java.util.Map;
import org.apache.commons.logging.Log;
import reactor.core.publisher.Flux;
import org.springframework.core.ResolvableType;
@@ -65,6 +66,11 @@ public class ResourceEncoder extends AbstractSingleValueEncoder<Resource> {
protected Flux<DataBuffer> encode(Resource resource, DataBufferFactory dataBufferFactory,
ResolvableType type, @Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
Log logger = getLogger(hints);
if (logger.isDebugEnabled()) {
logger.debug("Writing [" + resource + "]");
}
return DataBufferUtils.read(resource, dataBufferFactory, this.bufferSize);
}

View File

@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.OptionalLong;
import org.apache.commons.logging.Log;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@@ -81,7 +82,7 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
if (inputStream instanceof Mono) {
return ((Mono<? extends ResourceRegion>) inputStream)
.flatMapMany(region -> writeResourceRegion(region, bufferFactory));
.flatMapMany(region -> writeResourceRegion(region, bufferFactory, hints));
}
else {
Assert.notNull(hints, "'hints' must not be null");
@@ -96,7 +97,7 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
concatMap(region ->
Flux.concat(
getRegionPrefix(bufferFactory, startBoundary, contentType, region),
writeResourceRegion(region, bufferFactory)
writeResourceRegion(region, bufferFactory, hints)
));
return Flux.concat(regions, getRegionSuffix(bufferFactory, boundaryString));
}
@@ -112,11 +113,20 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
);
}
private Flux<DataBuffer> writeResourceRegion(ResourceRegion region, DataBufferFactory bufferFactory) {
private Flux<DataBuffer> writeResourceRegion(
ResourceRegion region, DataBufferFactory bufferFactory, @Nullable Map<String, Object> hints) {
Resource resource = region.getResource();
long position = region.getPosition();
long count = region.getCount();
Log logger = getLogger(hints);
if (logger.isDebugEnabled()) {
logger.debug("Writing region " + position + "-" + (position + count) + " of [" + resource + "]");
}
Flux<DataBuffer> in = DataBufferUtils.read(resource, position, bufferFactory, this.bufferSize);
return DataBufferUtils.takeUntilByteCount(in, region.getCount());
return DataBufferUtils.takeUntilByteCount(in, count);
}
private Flux<DataBuffer> getRegionSuffix(DataBufferFactory bufferFactory, String boundaryString) {

View File

@@ -205,7 +205,11 @@ public class StringDecoder extends AbstractDataBufferDecoder<String> {
Charset charset = getCharset(mimeType);
CharBuffer charBuffer = charset.decode(dataBuffer.asByteBuffer());
DataBufferUtils.release(dataBuffer);
return charBuffer.toString();
String value = charBuffer.toString();
if (logger.isDebugEnabled()) {
logger.debug("Decoded '" + "'");
}
return value;
}
private static Charset getCharset(@Nullable MimeType mimeType) {