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