[JAVA] Utilisez LocationAwareLogger pour votre propre enregistreur

introduction

Il existe une histoire et une solution pour la sortie du journal.

Sortie du "générateur de demande de journalisation" dans Logback

Dans Logback, les informations du "générateur de demande de journalisation" peuvent être incluses dans la sortie du journal en spécifiant le spécificateur de conversion suivant dans la disposition du modèle [^ warning-1].

Spécificateur de conversion(alias) Contenu de sortie
C (class) Nom de la classe de l'appelant(FQCN)
M (method) Nom de la méthode de l'appelant
F (file) Nom du fichier de code source
L (line) Numéro de ligne dans le fichier de code source
caller[^1] Informations de localisation de l'appelant

[^ warning-1] :: warning: L'obtention de la "source de la demande de journalisation" est un processus coûteux et ralentit l'exécution. Utilisons-le uniquement dans l'environnement de développement, etc. [^ 1]: Le contenu de sortie étant spécial, il n'est pas traité dans cet article.

Dans cet article, nous utiliserons les paramètres suivants comme exemple de sortie de journal. Notez le contenu de l'élément pattern. Avec ce paramètre, vous pouvez afficher le nom de la classe, le nom du fichier, etc. dans le journal. Le débogage progresse.

logback.xml


<configuration>
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>[[%class.%method\(%file:%line\)]] %logger{0} - %msg%n</pattern>
    </encoder>
  </appender>

  <root level="debug">
    <appender-ref ref="STDOUT" />
  </root>
</configuration>

Exemple de sortie de journal


[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:16)]] DemoLogApplication - hello

Pour plus de détails sur les spécificateurs de conversion, reportez-vous au manuel.

[Problème] Dans le cas de la classe Logger auto-fabriquée

Pour diverses raisons, vous pouvez définir votre propre enregistreur sans utiliser directement l'enregistreur de SLF4J. À ce stade, si vous transférez simplement le traitement vers le SLF4J Logger (appelé Wrapper), tous les "générateurs de demande de journalisation" seront votre propre Logger.

MyWrongLogger.java


package com.example.demo;

import org.slf4j.LoggerFactory;
import org.slf4j.Marker;

public class MyWrongLogger {
  //Enregistreur de SLF4J à transférer
  private final org.slf4j.Logger logger;

  //Le constructeur est privé
  private MyWrongLogger(org.slf4j.Logger logger) {
    this.logger = logger;
  }

  //Méthode d'usine
  public static final MyWrongLogger getLogger(Class<?> clazz) {
    org.slf4j.Logger logger = LoggerFactory.getLogger(clazz);
    return new MyWrongLogger(logger);
  }

  //Ci-dessous, délégation à l'enregistreur

  public boolean isTraceEnabled() {
    return logger.isTraceEnabled();
  }

  public void trace(String msg) {
    logger.trace(msg);
  }

  // (Ce qui suit est omis)

}

DemoLogApplication.java


package com.example.demo;

public class DemoLogApplication {
  private static final MyWrongLogger WRONG_LOGGER = MyWrongLogger.getLogger(DemoLogApplication.class);

  public static void main(String[] args) {
    WRONG_LOGGER.info("hello");
    WRONG_LOGGER.info("hello {}", "xxx");
    WRONG_LOGGER.info("exception", new Exception("test"));
    WRONG_LOGGER.info("{} {} {} exception", 1, 2, 3, new Exception("test"));
  }
}

Exemple de sortie de journal("Générateur de demande de journalisation" est devenu MyWrongLogger)


[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:122)]] DemoLogApplication - hello
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:126)]] DemoLogApplication - hello xxx
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:138)]] DemoLogApplication - exception
java.lang.Exception: test
	at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:11)
[[com.example.demo.MyWrongLogger.info(MyWrongLogger.java:134)]] DemoLogApplication - 1 2 3 exception
java.lang.Exception: test
	at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:12)

Certes, c'est MyWrongLogger qui appelle en fait la méthode logger ... Il y a des journaux malheureux comme celui-ci de temps en temps.

[Solution] LocationAwareLogger

Vous pouvez résoudre ce problème en utilisant LocationAwareLogger [^ FQCN-1] de SLF4J. Vous pouvez spécifier FQCN dans la méthode log '' de LocationAwareLogger ''.

java:org.slf4j.spi.LocationAwareLogger


public void log(Marker marker, String fqcn, int level, String message, Object[] argArray, Throwable t);

Logger [^ FQCN-2] de Logback implémente LocationAwareLogger. En d'autres termes, si vous utilisez Logback pour implémenter la sortie du journal, vous pouvez convertir le Logger [^ FQCN-3] obtenu à partir de LoggerFactory vers le LocationAwareLogger.

Voici un exemple d'utilisation de `` LocationAwareLogger ''.

MyLocationAwareLogger.java


package com.example.demo;

import static org.slf4j.spi.LocationAwareLogger.*;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;

public class MyLocationAwareLogger {
  // Marker(Non utilisé cette fois)
  private static final Marker MARKER = null;
  //FQCN de cette classe
  private static final String FQCN = MyLocationAwareLogger.class.getName();

  //Enregistreur de localisation de SLF4J à transférer
  private final org.slf4j.spi.LocationAwareLogger logger;

  //Le constructeur est privé
  private MyLocationAwareLogger(org.slf4j.spi.LocationAwareLogger logger) {
    this.logger = logger;
  }

  //Méthode d'usine
  public static MyLocationAwareLogger getLogger(Class<?> clazz) {
    org.slf4j.spi.LocationAwareLogger logger = (org.slf4j.spi.LocationAwareLogger) LoggerFactory.getLogger(clazz);
    return new MyLocationAwareLogger(logger);
  }

  //<<< isXxxEnabled >>>
  public boolean isTraceEnabled() { return logger.isTraceEnabled(); }
  public boolean isDebugEnabled() { return logger.isDebugEnabled(); }
  public boolean isInfoEnabled () { return logger.isInfoEnabled (); }
  public boolean isWarnEnabled () { return logger.isWarnEnabled (); }
  public boolean isErrorEnabled() { return logger.isErrorEnabled(); }
  //---

  //<<< log >>>
  // (String msg)
  public void trace(String msg)                         { logger.log(MARKER, FQCN, TRACE_INT, msg,    null,      null); }
  public void debug(String msg)                         { logger.log(MARKER, FQCN, DEBUG_INT, msg,    null,      null); }
  public void info (String msg)                         { logger.log(MARKER, FQCN, INFO_INT,  msg,    null,      null); }
  public void warn (String msg)                         { logger.log(MARKER, FQCN, WARN_INT,  msg,    null,      null); }
  public void error(String msg)                         { logger.log(MARKER, FQCN, ERROR_INT, msg,    null,      null); }
  // (String msg, Throwable t)
  public void trace(String msg,    Throwable t)         { logger.log(MARKER, FQCN, TRACE_INT, msg,    null,      t   ); }
  public void debug(String msg,    Throwable t)         { logger.log(MARKER, FQCN, DEBUG_INT, msg,    null,      t   ); }
  public void info (String msg,    Throwable t)         { logger.log(MARKER, FQCN, INFO_INT,  msg,    null,      t   ); }
  public void warn (String msg,    Throwable t)         { logger.log(MARKER, FQCN, WARN_INT,  msg,    null,      t   ); }
  public void error(String msg,    Throwable t)         { logger.log(MARKER, FQCN, ERROR_INT, msg,    null,      t   ); }
  // (String format, Object... arguments)
  public void trace(String format, Object... arguments) { logger.log(MARKER, FQCN, TRACE_INT, format, arguments, null); }
  public void debug(String format, Object... arguments) { logger.log(MARKER, FQCN, DEBUG_INT, format, arguments, null); }
  public void info (String format, Object... arguments) { logger.log(MARKER, FQCN, INFO_INT,  format, arguments, null); }
  public void warn (String format, Object... arguments) { logger.log(MARKER, FQCN, WARN_INT,  format, arguments, null); }
  public void error(String format, Object... arguments) { logger.log(MARKER, FQCN, ERROR_INT, format, arguments, null); }
  //---
}

DemoLogApplication.java


package com.example.demo;

public class DemoLogApplication {
  private static final MyLocationAwareLogger MY_LOGGER = MyLocationAwareLogger.getLogger(DemoLogApplication.class);

  public static void main(String[] args) {
    MY_LOGGER.info("hello");
    MY_LOGGER.info("hello {}", "xxx");
    MY_LOGGER.info("exception", new Exception("test"));
    MY_LOGGER.info("{} {} {} exception", 1, 2, 3, new Exception("test"));
  }
}

Exemple de sortie de journal(La "source de la demande de journalisation" correcte est sortie)


[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:16)]] DemoLogApplication - hello
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:17)]] DemoLogApplication - hello xxx
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:18)]] DemoLogApplication - exception
java.lang.Exception: test
	at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:18)
[[com.example.demo.DemoLogApplication.main(DemoLogApplication.java:19)]] DemoLogApplication - 1 2 3 exception
java.lang.Exception: test
	at com.example.demo.DemoLogApplication.main(DemoLogApplication.java:19)

en conclusion

Si vous souhaitez simplement imiter la méthode SLF4J Logger '', vous n'avez pas besoin de votre propre Logger. Si vous créez votre propre enregistreur, créez un enregistreur significatif, par exemple en préparant une méthode pour chaque objectif de sortie de journal (journal d'audit, journal des performances, etc.). (Dans cet article, j'ai osé imiter la méthode de Logger '' par souci de clarté comme échantillon. Veuillez me pardonner)

Recommended Posts

Utilisez LocationAwareLogger pour votre propre enregistreur
Créez votre propre encodage pour String.getBytes ()
Créez votre propre application Android pour l'apprentissage Java
Utilisez votre propre docker-compose.yml sur la ligne de commande
Faites votre propre pomodoro
Utilisez votre propre classe dans le répertoire lib avec Rails6
Créez vos propres annotations Java
Créez votre propre plugin Elasticsearch