jul-to-slf4j is a convenient one that transfers processing to slf4j even if you are logging via the jul API.jul is the java.util.logging package, which is the default logging API in Java.slf4j is a log façade library.slf4j, the multiple processing systems mentioned above refer to each logging library such as logback and log4j (2), and serve as an interface for those processing.logback or log4j2 directly these days. The settings for each logging library that actually works cannot be eliminated.
Other than *, many things depend on this guy.jul, but even in that case, it is this one that transparently transfers processing to slf4j. It is jul-to-slf4j.jul-to-slf4j.SLF4JBridgeHandler.install();
Just hit it.
Spring Boot[Reference 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.
}
}
...
Play frameworkLogbackLoggerConfigurator.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 ...
It looks like this.
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);
}
}
From the conclusion, if you follow the steps of what is being done
SLF4JBridgeHandler which inherits java.util.logging.Handler to the root logger on jul withSLF4JBridgeHandler # install ()java.util.logging.logger # info () etc., [somehow](http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6- b14 / java / util / logging / Logger.java # Logger.log% 28java.util.logging.LogRecord% 29) There is a process transferred to java.util.logging.Handler # publish ()SLF4JBridgeHandler # publish () further transfers the processing of the Slf4j logger, logging via jul can be done by executingSLF4JBridgeHandler # install (). Processing is transferred to.Who is java.util.logging.Handler by JavaDoc When,
The Handler object receives log messages from Logger and exports them. For example, this object writes to the console or file, sends it to the network log service, performs transfers to OS logs, and so on.
There is.
In other words, Logger is an interface seen from the application, and it seems that this Handler actually outputs the physical log.
I somehow understood that it was like an appender in logback.
And what is LogManager? As far as I read the ʻimport` statement, it is a class of jul.
SLF4JBridgeHandler.java
import java.util.logging.LogManager;
Also, you can see that the empty string is specified as the logger name, such as getLogger ("") . What is this?
It's not that I can't imagine it because it doesn't have a name, but it seems that you can get a root logger by specifying an empty string logger name.
SLF4JBridgeHandler.java
private static java.util.logging.Logger getRootLogger() {
return LogManager.getLogManager().getLogger("");
}
As a premise here, all loggers have a descendant relationship with jul as well as other logging API examples, and always inherit the route.
This means that adding a SLF4JBridgeHandler to the root logger on jul means that all logging via jul will be delegated to slf4j.
Recommended Posts