Skip to content

Commit 8231066

Browse files
committed
Correlated encoding/decoding log messages via hints
Issue: SPR-16966
1 parent fd90b73 commit 8231066

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+293
-152
lines changed

spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.util.Arrays;
2020
import java.util.List;
21-
import java.util.Map;
2221

2322
import org.apache.commons.logging.Log;
2423
import org.apache.commons.logging.LogFactory;
@@ -60,17 +59,4 @@ public boolean canEncode(ResolvableType elementType, @Nullable MimeType mimeType
6059
return this.encodableMimeTypes.stream().anyMatch(candidate -> candidate.isCompatibleWith(mimeType));
6160
}
6261

63-
/**
64-
* Helper method to obtain the logger to use from the Map of hints, or fall
65-
* back on the default logger. This may be used for example to override
66-
* logging, e.g. for a multipart request where the full map of part values
67-
* has already been logged.
68-
* @param hints the hints passed to the encode method
69-
* @return the logger to use
70-
* @since 5.1
71-
*/
72-
protected Log getLogger(@Nullable Map<String, Object> hints) {
73-
return hints != null ? ((Log) hints.getOrDefault(Log.class.getName(), logger)) : logger;
74-
}
75-
7662
}

spring-core/src/main/java/org/springframework/core/codec/ByteArrayDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ protected byte[] decodeDataBuffer(DataBuffer dataBuffer, ResolvableType elementT
5454
dataBuffer.read(result);
5555
DataBufferUtils.release(dataBuffer);
5656
if (logger.isDebugEnabled()) {
57-
logger.debug("Read " + result.length + " bytes");
57+
logger.debug(Hints.getLogPrefix(hints) + "Read " + result.length + " bytes");
5858
}
5959
return result;
6060
}

spring-core/src/main/java/org/springframework/core/codec/ByteArrayEncoder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@ public Flux<DataBuffer> encode(Publisher<? extends byte[]> inputStream,
5555

5656
return Flux.from(inputStream).map(bytes -> {
5757
DataBuffer dataBuffer = bufferFactory.wrap(bytes);
58-
Log logger = getLogger(hints);
59-
if (logger.isDebugEnabled()) {
60-
logger.debug("Writing " + dataBuffer.readableByteCount() + " bytes");
58+
Log theLogger = Hints.getLoggerOrDefault(hints, logger);
59+
if (theLogger.isDebugEnabled()) {
60+
theLogger.debug(Hints.getLogPrefix(hints) +
61+
"Writing " + dataBuffer.readableByteCount() + " bytes");
6162
}
6263
return dataBuffer;
6364
});

spring-core/src/main/java/org/springframework/core/codec/ByteBufferDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ protected ByteBuffer decodeDataBuffer(DataBuffer dataBuffer, ResolvableType elem
5858
copy.flip();
5959
DataBufferUtils.release(dataBuffer);
6060
if (logger.isDebugEnabled()) {
61-
logger.debug("Read " + byteCount + " bytes");
61+
logger.debug(Hints.getLogPrefix(hints) + "Read " + byteCount + " bytes");
6262
}
6363
return copy;
6464
}

spring-core/src/main/java/org/springframework/core/codec/ByteBufferEncoder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,10 @@ public Flux<DataBuffer> encode(Publisher<? extends ByteBuffer> inputStream,
5656

5757
return Flux.from(inputStream).map(byteBuffer -> {
5858
DataBuffer dataBuffer = bufferFactory.wrap(byteBuffer);
59-
Log logger = getLogger(hints);
60-
if (logger.isDebugEnabled()) {
61-
logger.debug("Writing " + dataBuffer.readableByteCount() + " bytes");
59+
Log theLogger = Hints.getLoggerOrDefault(hints, logger);
60+
if (theLogger.isDebugEnabled()) {
61+
theLogger.debug(Hints.getLogPrefix(hints) +
62+
"Writing " + dataBuffer.readableByteCount() + " bytes");
6263
}
6364
return dataBuffer;
6465
});

spring-core/src/main/java/org/springframework/core/codec/CharSequenceEncoder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ public Flux<DataBuffer> encode(Publisher<? extends CharSequence> inputStream,
6969
Charset charset = getCharset(mimeType);
7070

7171
return Flux.from(inputStream).map(charSequence -> {
72-
Log logger = getLogger(hints);
73-
if (logger.isDebugEnabled()) {
74-
logger.debug("Writing '" + charSequence + "'");
72+
Log theLogger = Hints.getLoggerOrDefault(hints, logger);
73+
if (theLogger.isDebugEnabled()) {
74+
theLogger.debug(Hints.getLogPrefix(hints) + "Writing '" + charSequence + "'");
7575
}
7676
CharBuffer charBuffer = CharBuffer.wrap(charSequence);
7777
ByteBuffer byteBuffer = charset.encode(charBuffer);

spring-core/src/main/java/org/springframework/core/codec/DataBufferDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ protected DataBuffer decodeDataBuffer(DataBuffer buffer, ResolvableType elementT
6363
@Nullable MimeType mimeType, @Nullable Map<String, Object> hints) {
6464

6565
if (logger.isDebugEnabled()) {
66-
logger.debug("Read " + buffer.readableByteCount() + " bytes");
66+
logger.debug(Hints.getLogPrefix(hints) + "Read " + buffer.readableByteCount() + " bytes");
6767
}
6868
return buffer;
6969
}

spring-core/src/main/java/org/springframework/core/codec/DataBufferEncoder.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,11 @@ public Flux<DataBuffer> encode(Publisher<? extends DataBuffer> inputStream,
5555

5656
Flux<DataBuffer> flux = Flux.from(inputStream);
5757

58-
Log logger = getLogger(hints);
59-
if (logger.isDebugEnabled()) {
60-
flux = flux.doOnNext(buffer -> logger.debug("Writing " + buffer.readableByteCount() + " bytes"));
58+
Log theLogger = Hints.getLoggerOrDefault(hints, logger);
59+
if (theLogger.isDebugEnabled()) {
60+
flux = flux.doOnNext(buffer ->
61+
theLogger.debug(Hints.getLogPrefix(hints) +
62+
"Writing " + buffer.readableByteCount() + " bytes"));
6163
}
6264

6365
return flux;
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.core.codec;
17+
18+
import java.util.Collections;
19+
import java.util.HashMap;
20+
import java.util.Map;
21+
22+
import org.apache.commons.logging.Log;
23+
24+
import org.springframework.lang.Nullable;
25+
26+
/**
27+
* Constants and convenience methods for working with hints.
28+
*
29+
* @author Rossen Stoyanchev
30+
* @since 5.1
31+
* @see ResourceRegionEncoder#BOUNDARY_STRING_HINT
32+
*/
33+
public abstract class Hints {
34+
35+
/**
36+
* Name of hint exposing a prefix to use for correlating log messages.
37+
* @since 5.1
38+
*/
39+
public static final String LOG_PREFIX_HINT = Log.class.getName() + ".PREFIX";
40+
41+
/**
42+
* Name of hint for a preferred {@link Log logger} to use. This can be used
43+
* by a composite encoder (e.g. multipart requests) to control or suppress
44+
* logging by individual part encoders.
45+
* @since 5.1
46+
*/
47+
public static final String LOGGER_HINT = Log.class.getName();
48+
49+
50+
/**
51+
* Create a map wit a single hint via {@link Collections#singletonMap}.
52+
* @param hintName the hint name
53+
* @param value the hint value
54+
* @return the created map
55+
*/
56+
public static Map<String, Object> from(String hintName, Object value) {
57+
return Collections.singletonMap(hintName, value);
58+
}
59+
60+
/**
61+
* Return an empty map of hints via {@link Collections#emptyMap()}.
62+
* @return the empty map
63+
*/
64+
public static Map<String, Object> none() {
65+
return Collections.emptyMap();
66+
}
67+
68+
/**
69+
* Obtain the value for a required hint.
70+
* @param hints the hints map
71+
* @param hintName the required hint name
72+
* @param <T> the hint type to cast to
73+
* @return the hint value
74+
* @throws IllegalArgumentException if the hint is not found
75+
*/
76+
@SuppressWarnings("unchecked")
77+
public static <T> T getRequiredHint(@Nullable Map<String, Object> hints, String hintName) {
78+
if (hints == null) {
79+
throw new IllegalArgumentException("No hints map for required hint '" + hintName + "'");
80+
}
81+
T hint = (T) hints.get(hintName);
82+
if (hint == null) {
83+
throw new IllegalArgumentException("Hints map must contain the hint '" + hintName + "'");
84+
}
85+
return hint;
86+
}
87+
88+
/**
89+
* Obtain the hint {@link #LOG_PREFIX_HINT}, if present, or an empty String.
90+
* @param hints the hints passed to the encode method
91+
* @return the log prefix
92+
*/
93+
public static String getLogPrefix(@Nullable Map<String, Object> hints) {
94+
return hints != null ? (String) hints.getOrDefault(LOG_PREFIX_HINT, "") : "";
95+
}
96+
97+
/**
98+
* Obtain the hint {@link #LOGGER_HINT}, if present, or the given logger.
99+
* @param hints the hints passed to the encode method
100+
* @param defaultLogger the logger to return if a hint is not found
101+
* @return the logger to use
102+
*/
103+
public static Log getLoggerOrDefault(@Nullable Map<String, Object> hints, Log defaultLogger) {
104+
return hints != null ? (Log) hints.getOrDefault(LOGGER_HINT, defaultLogger) : defaultLogger;
105+
}
106+
107+
/**
108+
* Merge two maps of hints, creating and copying into a new map if both have
109+
* values, or returning the non-empty map, or an empty map if both are empty.
110+
* @param hints1 1st map of hints
111+
* @param hints2 2nd map of hints
112+
* @return a single map with hints from both
113+
*/
114+
public static Map<String, Object> merge(Map<String, Object> hints1, Map<String, Object> hints2) {
115+
if (hints1.isEmpty() && hints2.isEmpty()) {
116+
return Collections.emptyMap();
117+
}
118+
else if (hints2.isEmpty()) {
119+
return hints1;
120+
}
121+
else if (hints1.isEmpty()) {
122+
return hints2;
123+
}
124+
else {
125+
Map<String, Object> result = new HashMap<>(hints1.size() + hints2.size());
126+
result.putAll(hints1);
127+
result.putAll(hints2);
128+
return result;
129+
}
130+
}
131+
132+
/**
133+
* Merge a single hint into a map of hints, possibly creating and copying
134+
* all hints into a new map, or otherwise if the map of hints is empty,
135+
* creating a new single entry map.
136+
* @param hints a map of hints to be merge
137+
* @param hintName the hint name to merge
138+
* @param hintValue the hint value to merge
139+
* @return a single map with all hints
140+
*/
141+
public static Map<String, Object> merge(Map<String, Object> hints, String hintName, Object hintValue) {
142+
if (hints.isEmpty()) {
143+
return Collections.singletonMap(hintName, hintValue);
144+
}
145+
else {
146+
Map<String, Object> result = new HashMap<>(hints.size() + 1);
147+
result.putAll(hints);
148+
result.put(hintName, hintValue);
149+
return result;
150+
}
151+
}
152+
153+
}

spring-core/src/main/java/org/springframework/core/codec/ResourceDecoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ protected Resource decodeDataBuffer(DataBuffer dataBuffer, ResolvableType elemen
7373
Assert.state(clazz != null, "No resource class");
7474

7575
if (logger.isDebugEnabled()) {
76-
logger.debug("Read " + bytes.length + " bytes");
76+
logger.debug(Hints.getLogPrefix(hints) + "Read " + bytes.length + " bytes");
7777
}
7878

7979
if (InputStreamResource.class == clazz) {

0 commit comments

Comments
 (0)