With Spring Web MVC, which is commonly used in Spring, you will not encounter this problem.
The major difference between WebFlux and WebMVC is the handling of threads when processing request and response. Unlike Spring MVC, Event Loop Thread used in WebFlux handles one request in multiple threads.
However, the implementation of MDC depends on LocalThread. In other words, the thread that executed the MDC has the MDC information, but the thread that does not have the MDC information does not exist and does not appear in the log.
I've gone through this event at the last minute of the ** production release **, and here are the findings.
-[Examples of using Spring and WebFlux in the chat system of Line official account](https://speakerdeck.com/line_developers/examples-of-using-spring-and-webflux-in-the-chat-system-for-line -official-accounts)
The above two describe how to propagate MDC between multiple applications with WebFlux, which is one step more advanced than this theme. I would like to delve into this in separate article.
The answer is posted in the next article
There is a function called context and three methods, logOnNext
, logOnError
, and put
.
By the way, the context here is the context of the Reactor. Please refer to this described in Reactor as a document.
Simply put, the context is a "** data can be propagated in a reactive environment **" mechanism that allows the MDC to function properly. (It seems that the subscription propagation mechanism is involved in data propagation, and I don't understand it until now, but the above document 9.8.2 has a similar explanation!)
As it is, the value as an article is not so much, so I will delve into each method.
--In LogHelper.java
,public static final String CONTEXT_MAP = "context-map";
is defined.
--logOnNext
and logOnError
refer to the context by the Key value of the constant CONTEXT_MAP
. Since the context has an I / F like Map, it picks up the Value. It thrusts it into the MDC, outputs a log, and clears the MDC when it finishes operating.
--put
is writing to the context with the constant CONTEXT_MAP
.
LogHelper.java
public static <T> Consumer<Signal<T>> logOnNext(
Consumer<T> log) {
return signal -> {
if (signal.getType() != SignalType.ON_NEXT) return;
Optional<Map<String, String>> maybeContextMap
= signal.getContext().getOrEmpty(CONTEXT_MAP);
if (maybeContextMap.isEmpty()) {
log.accept(signal.get());
} else {
MDC.setContextMap(maybeContextMap.get());
try {
log.accept(signal.get());
} finally {
MDC.clear();
}
}
};
logOnNext
is used in combination with WebFlux's doOnEach
method.
signal.getType ()! = SignalType.ON_NEXT
is the miso, and this method does not respond when calling an abnormal system. It ignites and logs when the data propagates normally.
LogHelper.java
public static <T> Consumer<Signal<T>> logOnError(
Consumer<Throwable> log) {
return signal -> {
if (!signal.isOnError()) return;
Optional<Map<String, String>> maybeContextMap
= signal.getContext().getOrEmpty(CONTEXT_MAP);
if (maybeContextMap.isEmpty()) {
log.accept(signal.getThrowable());
} else {
MDC.setContextMap(maybeContextMap.get());
try {
log.accept(signal.getThrowable());
} finally {
MDC.clear();
}
}
};
}
The outline of logOnError
is not much different from that of logOnNext
. However, the signal it references has changed, and it logs in response to the error signal.
In other words, if you use logOnXXX
at the end of a method, Error will not be called if it ends normally, and Next will not be called if it ends abnormally.
LogHelper.java
public static Function<Context, Context> put(String key, String value) {
return ctx -> {
Optional<Map<String, String>> maybeContextMap =
ctx.getOrEmpty(CONTEXT_MAP);
if (maybeContextMap.isPresent()) {
maybeContextMap.get().put(key, value);
return ctx;
} else {
Map<String, String> ctxMap = new HashMap<>();
ctxMap.put(key, value);
return ctx.put(CONTEXT_MAP, ctxMap);
}
};
The role of put
is straightforward, it just stores the data in context.
The usage method is as follows.
.subscriberContext(put("hogehogeId", response.getHogehogeId().toString()))
subscriberContext is a series of processes as far as the document is seen. It seems to generate the context in. put picks up and adds the constant CONTEXT
and returns a new context, so you can endlessly plunge values into the MDC within the chain of data propagation.
Is it impossible to use MDC in a reactive environment in the first place? Please let me know if there is a good way.
Recommended Posts