[JAVA] Wie jul-to-slf4j funktioniert

Was ist jul-to-slf4j?

wie benutzt man

SLF4JBridgeHandler.install();

Schlagen Sie es einfach.

Anwendungsbeispiel

In Spring Boot

[Referenz-URL](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/logging/Slf4JLoggingSystem .Java)

Slf4jLoggingSystem.java


...
	private void configureJdkLoggingBridgeHandler() {
		try {
			if (isBridgeHandlerAvailable()) {
				removeJdkLoggingBridgeHandler();
				SLF4JBridgeHandler.install();
			}
		}
		catch (Throwable ex) {
			// Ignore. No java.util.logging bridge is installed.
		}
	}
...

Im Play Framework

Referenz-URL

LogbackLoggerConfigurator.scala


...
  def configure(properties: Map[String, String], config: Option[URL]): Unit = {
    // Touching LoggerContext is not thread-safe, and so if you run several
    // application tests at the same time (spec2 / scalatest with "new WithApplication()")
    // then you will see NullPointerException as the array list loggerContextListenerList
    // is accessed concurrently from several different threads.
    //
    // The workaround is to use a synchronized block around a singleton
    // instance -- in this case, we use the StaticLoggerBinder's loggerFactory.
    loggerFactory.synchronized {
      // Redirect JUL -> SL4FJ

      // Remove existing handlers from JUL
      SLF4JBridgeHandler.removeHandlersForRootLogger()

      // Configure logback
      val ctx = loggerFactory.asInstanceOf[LoggerContext]

      // Set a level change propagator to minimize the overhead of JUL
      //
      // Please note that translating a java.util.logging event into SLF4J incurs the
      // cost of constructing LogRecord instance regardless of whether the SLF4J logger
      // is disabled for the given level. Consequently, j.u.l. to SLF4J translation can
      // seriously increase the cost of disabled logging statements (60 fold or 6000%
      // increase) and measurably impact the performance of enabled log statements
      // (20% overall increase). Please note that as of logback-version 0.9.25,
      // it is possible to completely eliminate the 60 fold translation overhead for
      // disabled log statements with the help of LevelChangePropagator.
      //
      // https://www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler.html
      // https://logback.qos.ch/manual/configuration.html#LevelChangePropagator
      val levelChangePropagator = new LevelChangePropagator()
      levelChangePropagator.setContext(ctx)
      levelChangePropagator.setResetJUL(true)
      ctx.addListener(levelChangePropagator)
      SLF4JBridgeHandler.install()

      ctx.reset()

      // Ensure that play.Logger and play.api.Logger are ignored when detecting file name and line number for
      // logging
      val frameworkPackages = ctx.getFrameworkPackages
      frameworkPackages.add(classOf[play.Logger].getName)
      frameworkPackages.add(classOf[play.api.Logger].getName)

      properties.foreach { case (k, v) => ctx.putProperty(k, v) }

      config match {
        case Some(url) =>
          val initializer = new ContextInitializer(ctx)
          initializer.configureByResource(url)
        case None =>
          System.err.println("Could not detect a logback configuration file, not configuring logback")
      }

      StatusPrinter.printIfErrorsOccured(ctx)

    }
  }
...

Ugh, scala ...

Also, wie macht ihr das?

Implementierung von jul-to-slf4j

Es sieht aus wie das.

SLF4JBridgeHandler.java


    public static void install() {
        LogManager.getLogManager().getLogger("").addHandler(new SLF4JBridgeHandler());
    }

...

    public void publish(LogRecord record) {
        // Silently ignore null records.
        if (record == null) {
            return;
        }

        Logger slf4jLogger = getSLF4JLogger(record);
        // this is a check to avoid calling the underlying logging system
        // with a null message. While it is legitimate to invoke j.u.l. with
        // a null message, other logging frameworks do not support this.
        // see also http://jira.qos.ch/browse/SLF4J-99
        if (record.getMessage() == null) {
            record.setMessage("");
        }
        if (slf4jLogger instanceof LocationAwareLogger) {
            callLocationAwareLogger((LocationAwareLogger) slf4jLogger, record);
        } else {
            callPlainSLF4JLogger(slf4jLogger, record);
        }
    }

Aus der Schlussfolgerung, wenn Sie die Schritte des Tuns befolgen

Lass uns genauer hinschauen

Wer ist java.util.logging.Handler von JavaDoc Wann,

Das Handler-Objekt empfängt Protokollnachrichten von Logger und exportiert sie. Dieses Objekt schreibt beispielsweise in die Konsole oder Datei, sendet es an den Netzwerkprotokolldienst, führt Übertragungen in das Betriebssystemprotokoll durch usw.

Es gibt. Mit anderen Worten, "Logger" ist eine Schnittstelle, die von der Anwendung aus gesehen wird, und es scheint, dass dieser "Handler" tatsächlich physische Protokolle ausgibt. Ich habe irgendwie verstanden, dass es wie ein Appender in "Logback" war.

Und was ist "LogManager"? Soweit die "import" -Anweisung gelesen wird, handelt es sich um eine Jul-Klasse.

SLF4JBridgeHandler.java


import java.util.logging.LogManager;

Sie können auch sehen, dass der Loggername als leeres Zeichen angegeben wird, z. B. "getLogger (" ")". Was ist das? Es ist nicht so, dass ich es mir nicht vorstellen kann, weil es keinen Namen hat, aber es scheint, dass Sie einen Root-Logger erhalten können, indem Sie einen leeren Logger-Namen angeben.

SLF4JBridgeHandler.java


    private static java.util.logging.Logger getRootLogger() {
        return LogManager.getLogManager().getLogger("");
    }

Als Voraussetzung hier haben alle Protokollierer eine Nachkommenbeziehung zu jul sowie anderen Beispielen für die Protokollierungs-API und erben immer die Route. Dies bedeutet, dass das Hinzufügen eines "SLF4JBridgeHandler" zum Root-Logger auf dem "Jul" bedeutet, dass die gesamte Protokollierung über den "Jul" an den "Slf4j" delegiert wird.

Referenz

Recommended Posts

Wie jul-to-slf4j funktioniert
[Java] Wie Spring DI funktioniert
Funktionsweise des JVM JIT-Compilers
Wie Speicher in objektorientierten Sprachen funktioniert
Funktionsweise des Dispatcher-Servlets in Spring MVC
Java-Leistung Kapitel 4 Funktionsweise des JIT-Compilers
Tauchen Sie ein in die Funktionsweise von HashMap in Java