[JAVA] Verwenden Sie LocationAwareLogger für Ihren eigenen Logger

Einführung

Es gibt eine Geschichte und eine Lösung für die Protokollausgabe.

Ausgabe von "Logging Request Generator" in Logback

In Logback können die Informationen des "Protokollierungsanforderungsgenerators" in die Protokollausgabe aufgenommen werden, indem der folgende Konvertierungsspezifizierer im Musterlayout [^ warning-1] angegeben wird.

Konvertierungsspezifizierer(alias) Inhalt ausgeben
C (class) Name der Anruferklasse(FQCN)
M (method) Name der Aufrufermethode
F (file) Name der Quellcodedatei
L (line) Zeilennummer in der Quellcodedatei
caller[^1] Standortinformationen des Anrufers

[^ warning-1] :: warning: Das Abrufen der "Quelle der Protokollierungsanforderung" ist ein kostspieliger Prozess und verlangsamt die Ausführung. Verwenden wir es nur in der Entwicklungsumgebung usw. [^ 1]: Aufgrund des speziellen Ausgabeinhalts wird dieser Artikel nicht behandelt.

In diesem Artikel werden die folgenden Einstellungen als Beispiel für die Protokollausgabe verwendet. Beachten Sie den Inhalt des Elements "pattern". Mit dieser Einstellung können Sie den Klassennamen, den Dateinamen usw. in das Protokoll ausgeben. Das Debuggen schreitet voran.

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>

Beispiel für die Protokollausgabe


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

Einzelheiten zu den Konvertierungsspezifizierern finden Sie im Handbuch.

[Problem] Im Fall einer selbst erstellten Logger-Klasse

Aus verschiedenen Gründen können Sie Ihren eigenen Logger definieren, ohne den Logger von SLF4J direkt zu verwenden. Wenn Sie zu diesem Zeitpunkt einfach die Verarbeitung auf den SLF4J-Logger (sogenannter Wrapper) übertragen, sind alle "Protokollierungsanforderungsgeneratoren" Ihr eigener Logger.

MyWrongLogger.java


package com.example.demo;

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

public class MyWrongLogger {
  //Logger von SLF4J übertragen werden
  private final org.slf4j.Logger logger;

  //Der Konstruktor ist privat
  private MyWrongLogger(org.slf4j.Logger logger) {
    this.logger = logger;
  }

  //Fabrikmethode
  public static final MyWrongLogger getLogger(Class<?> clazz) {
    org.slf4j.Logger logger = LoggerFactory.getLogger(clazz);
    return new MyWrongLogger(logger);
  }

  //Unten Delegation an Logger

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

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

  // (Folgendes wird weggelassen)

}

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"));
  }
}

Beispiel für die Protokollausgabe("Generator der Protokollierungsanforderung" wurde zu 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)

Sicherlich ist es "MyWrongLogger", das die Logger-Methode aufruft ... Hin und wieder gibt es solche unglücklichen Protokolle.

[Lösung] LocationAwareLogger

Sie können dieses Problem mit SLF4Js LocationAwareLogger [^ FQCN-1] lösen. Sie können FQCN in der log -Methode von LocationAwareLogger angeben.

java:org.slf4j.spi.LocationAwareLogger


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

Logbacks Logger [^ FQCN-2] implementiert LocationAwareLogger. Mit anderen Worten, wenn Sie Logback verwenden, um die Protokollausgabe zu implementieren, können Sie den von der "LoggerFactory" erhaltenen "Logger" [^ FQCN-3] in den "LocationAwareLogger" umwandeln.

Das Folgende ist ein Beispiel für die Verwendung von 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(Diesmal nicht verwendet)
  private static final Marker MARKER = null;
  //FQCN dieser Klasse
  private static final String FQCN = MyLocationAwareLogger.class.getName();

  //Standortbewusster Logger des zu übertragenden SLF4J
  private final org.slf4j.spi.LocationAwareLogger logger;

  //Der Konstruktor ist privat
  private MyLocationAwareLogger(org.slf4j.spi.LocationAwareLogger logger) {
    this.logger = logger;
  }

  //Fabrikmethode
  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"));
  }
}

Beispiel für die Protokollausgabe(Die korrekte "Quelle der Protokollierungsanforderung" wird ausgegeben)


[[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)

abschließend

Wenn Sie nur die SLF4J-Methode "Logger" imitieren möchten, benötigen Sie keinen eigenen Logger. Wenn Sie Ihren eigenen Logger erstellen, erstellen Sie einen aussagekräftigen Logger, z. B. das Vorbereiten einer Methode für jeden Protokollausgabezweck (Überwachungsprotokoll, Leistungsprotokoll usw.). (In diesem Artikel habe ich es aus Gründen der Klarheit als Beispiel gewagt, die Methode des "Loggers" nachzuahmen. Bitte verzeihen Sie mir)

Recommended Posts

Verwenden Sie LocationAwareLogger für Ihren eigenen Logger
Erstellen Sie Ihre eigene Codierung für String.getBytes ()
Erstellen Sie Ihre eigene Android-App für das Java-Lernen
Verwenden Sie Ihre eigene docker-compose.yml in der Befehlszeile
Machen Sie Ihren eigenen Pomodoro
Verwenden Sie mit Rails6 Ihre eigene Klasse im lib-Verzeichnis
Erstellen Sie Ihre eigenen Java-Anmerkungen
Erstellen Sie Ihr eigenes Elasticsearch-Plugin