[JAVA] Comment fonctionne jul-to-slf4j

Qu'est-ce que jul-to-slf4j?

comment utiliser

SLF4JBridgeHandler.install();

Juste frappe le.

Exemple d'utilisation

Dans Spring Boot

[URL de référence](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.
		}
	}
...

Dans le Play framework

URL de référence

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

Alors, comment faites-vous?

Implémentation de jul-to-slf4j

Ça ressemble à ça.

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

Dès la conclusion, si vous suivez les étapes de ce qui se fait

Regardons de plus près

Qui est java.util.logging.Handler par JavaDoc Quand,

L'objet Handler reçoit les messages du journal de Logger et les exporte. Par exemple, cet objet écrit dans la console ou le fichier, l'envoie au service de journalisation du réseau, effectue des transferts vers le journal du système d'exploitation, etc.

Il y a. En d'autres termes, «Logger» est une interface vue depuis l'application, et est-ce comme ce «Handler» qui produit réellement des journaux physiques? J'ai en quelque sorte compris que c'était comme un appender dans logback.

Et qu'est-ce que LogManager? Pour autant que je lis l'instruction ʻimport`, c'est une classe de jul.

SLF4JBridgeHandler.java


import java.util.logging.LogManager;

De plus, vous pouvez voir que le nom de l'enregistreur est spécifié comme un caractère vide, tel que getLogger (" "). Qu'est-ce que c'est? Ce n'est pas que je ne peux pas l'imaginer car il n'a pas de nom, mais il semble que vous puissiez obtenir un enregistreur racine en spécifiant un nom d'enregistreur vide.

SLF4JBridgeHandler.java


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

Comme prémisse ici, tous les loggers ont une relation descendante avec jul ainsi qu'avec d'autres exemples d'API de journalisation, et héritent toujours de la route. Cela signifie que l'ajout d'un SLF4JBridgeHandler à l'enregistreur racine sur jul signifie que toute journalisation via jul sera déléguée à slf4j.

référence

Recommended Posts

Comment fonctionne jul-to-slf4j
[Java] Fonctionnement de Spring DI
Fonctionnement du compilateur JVM JIT
Comment fonctionne la mémoire dans les langages orientés objet
Fonctionnement du servlet Dispatcher dans Spring MVC
Java Performance Chapter 4 Fonctionnement du compilateur JIT
Découvrez comment HashMap fonctionne en Java