Spring Web MVC, qui est couramment utilisé dans Spring, ne rencontre pas ce problème.
La principale différence entre WebFlux et WebMVC est la gestion des threads lors du traitement des requêtes et des réponses. Event Loop Thread utilisé dans WebFlux est différent de Spring MVC en ce qu'une demande est traitée par plusieurs threads.
Cependant, l'implémentation de MDC dépend de LocalThread. En d'autres termes, le thread qui a exécuté le MDC a les informations MDC, mais le thread qui ne possède pas les informations MDC n'existe pas et n'apparaît pas dans le journal.
J'ai vécu cet événement à la dernière minute de la ** version de production **, et voici les résultats de cette enquête.
Les deux ci-dessus décrivent comment propager MDC entre plusieurs applications avec WebFlux, qui est une étape plus avancée que ce thème. Je voudrais approfondir cela dans Article séparé.
La réponse est publiée dans le prochain article
Il existe une fonction appelée context et trois méthodes, logOnNext
, logOnError
et put
.
Au fait, le contexte ici est le contexte de Reactor. Veuillez vous référer à this décrit dans Reactor en tant que document.
En termes simples, le contexte est un mécanisme qui "** peut propager des données dans un environnement réactif **", qui peut être utilisé pour faire fonctionner correctement MDC. (Il semble que le mécanisme de propagation de l'abonnement soit impliqué dans la propagation des données, et je ne le comprends pas jusqu'à présent, mais le document 9.8.2 ci-dessus a une explication similaire!)
En l'état, il n'est pas très précieux en tant qu'article, je vais donc approfondir chaque méthode.
--LogHelper.java
définitla chaîne finale statique publique CONTEXT_MAP = "context-map";
.
--logOnNext
et logOnError
font référence au contexte par la valeur de clé de la constante CONTEXT_MAP
. Puisque le contexte a un I / F comme Map, il prend Value. Il le pousse dans le MDC, génère un journal et efface le MDC lorsqu'il a fini de fonctionner.
--put
écrit dans le contexte avec la constante 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
est utilisé en combinaison avec la méthode doOnEach
de WebFlux.
signal.getType ()! = SignalType.ON_NEXT
est un miso, et cette méthode ne répond pas lors de l'appel d'un système anormal. Il s'enflamme et enregistre lorsque les données se propagent normalement.
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();
}
}
};
}
Le contour de «logOnError» n'est pas très différent de celui de «logOnNext». Cependant, le signal à référencer a changé et il se connecte en réponse au signal d'erreur.
En d'autres termes, si vous utilisez logOnXXX
à la fin d'une méthode, Error ne sera pas appelée si elle se termine normalement, et Next ne sera pas appelé si elle se termine anormalement.
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);
}
};
Le rôle de «put» est simple, il stocke simplement les données dans leur contexte. La méthode d'utilisation est la suivante.
.subscriberContext(put("hogehogeId", response.getHogehogeId().toString()))
subscriptionContext est une série de processus pour autant que le document soit vu. Cela semble générer le contexte dans. put prend et ajoute la constante CONTEXT
et renvoie un nouveau contexte, de sorte que vous pouvez à l'infini plonger des valeurs dans le MDC dans la chaîne de propagation des données.
Est-il impossible d'utiliser MDC dans un environnement réactif en premier lieu? S'il vous plaît laissez-moi savoir s'il existe un bon moyen.
Recommended Posts