[JAVA] Vous utilisez le contexte pour utiliser MDC avec Spring WebFlux

Incompatibilité entre WebFlux et MDC

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.

Pionnier

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é.

Sujet principal

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.

Que fais-tu à peu près

--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.

logOnNext (MDC génère un journal valide lorsqu'il est normal)

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.

logOnError (MDC génère un journal valide en cas d'anomalie)

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.

put (écrire MDC dans le contexte)

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.

fin

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

Vous utilisez le contexte pour utiliser MDC avec Spring WebFlux
Comment utiliser MyBatis2 (iBatis) avec Spring Boot 1.4 (Spring 4)
Comment utiliser h2db intégré avec Spring Boot
Si vous souhaitez utiliser Mockito avec Kotlin, utilisez mockito-kotlin
Utiliser Spring JDBC avec Spring Boot
Vous devez utiliser winpty avec docker exec [Windows]
Comment utiliser Lombok au printemps
Utiliser l'authentification de base avec Spring Boot
Remarques sur l'utilisation de Spring Data JDBC
Comment utiliser mssql-tools avec Alpine
Comment utiliser ModelMapper (Spring boot)
À partir de Spring Boot 0. Utilisez Spring CLI
Il semble que MDC peut être propagé entre les applications en utilisant le contexte avec Spring WebFlux.
Si vous osez comparer Integer avec "==" ...
Comment utiliser BootStrap avec Play Framework
Je souhaite utiliser DBViewer avec Eclipse 2018-12! !!
Utiliser les balises JSP Spring Security avec FreeMarker
Utiliser le cache avec EhCashe 2.x avec Spring Boot
[Java] Pourquoi vous embêtez-vous à utiliser l'interface (Spring est également disponible)
[Spring Boot] Si vous utilisez Spring Boot, il était pratique d'utiliser de nombreux utilitaires.
Avec Tomcat, vous pouvez utiliser des espaces réservés ($ {...}) dans web.xml.
Comment utiliser le framework Java avec AWS Lambda! ??
Comment utiliser les attributs de session Spring Boot (@SessionAttributes)
Je veux utiliser java8 forEach avec index
Essayez d'implémenter la fonction de connexion avec Spring Boot
Lorsque vous souhaitez utiliser la méthode à l'extérieur
Comment utiliser l'API Java avec des expressions lambda
Un moyen très simple d'utiliser enum avec JSP
Comment utiliser le protocole NFS version 2 avec Ubuntu 18.04
[JAVA] [Spring] [MyBatis] Utiliser IN () avec SQL Builder
Essayez d'automatiser la migration avec Spring Boot Flyway
[Java] Article pour ajouter une validation avec Spring Boot 2.3.1.
Je voulais classer la botte à ressort dans un multi-projet
Essayez d'afficher Hello World avec Spring + Gradle
Qu'utilisez-vous lors de la conversion en String?
[Introduction à Spring Boot] Fonction d'authentification avec Spring Security
Si vous utilisez SQLite avec VSCode, utilisez l'extension (comment voir le fichier binaire de sqlite3)
Une petite main qui lit un corps JSON à partir de ServerHttpRequest avec un WebFilter auto-créé, etc. avec Spring WebFlux
Code à utiliser lorsque vous souhaitez traiter Json en Java avec uniquement des bibliothèques standard
Paramètres de connexion à MySQL avec Spring Boot + Spring JDBC
J'ai essayé d'implémenter le téléchargement de fichiers avec Spring MVC
Mappez automatiquement DTO aux entités avec l'API Spring Boot
Si vous souhaitez séparer le traitement Spring Boot + Thymeleaf
Comment utiliser Struts2 * Spring Framework (plugin Spring) Version de juin 2017
[Java] Comment omettre l'injection de constructeur de ressort avec Lombok
Comment utiliser Oracle JDK 9 EA avec Travis CI
Compte tenu de l'éditeur de propriétés utilisé dans SpringToolSuite (STS)
Comment utiliser la bibliothèque Z3 dans Scala avec Eclipse
J'ai essayé de démarrer avec Spring Data JPA
Comment utiliser CommandLineRunner dans Spring Batch of Spring Boot
Jusqu'à ce que vous commenciez à développer avec Spring Boot dans eclipse 1
Comment utiliser la bibliothèque JDD dans Scala avec Eclipse
Comment démarrer par environnement avec Spring Boot de Maven
Jusqu'à ce que vous commenciez à développer avec Spring Boot dans eclipse 2
Comment utiliser le référentiel de jobs en mémoire avec Spring Batch
Tentative de SSR Vue.js avec Spring Boot et GraalJS
Essayez de travailler avec Keycloak en utilisant Spring Security SAML (Spring 5)