JUL-to-Log4j bridge

The JUL-to-Log4j bridge provides components that allow application and library that use java.util.logging.Logger (JUL) to log to the Log4j API instead.

This chapter covers advanced usage scenarios of the JUL-to-Log4j bridge. For the installation procedure and basic configuration see Using JUL-to-Log4j section of our Installation guide.

Configuration

Struggling with the logging API, implementation, and bridge concepts? Click for an introduction.
Logging API

A logging API is an interface your code or your dependencies directly logs against. It is required at compile-time. It is implementation agnostic to ensure that your application can write logs, but is not tied to a specific logging implementation. Log4j API, SLF4J, JUL (Java Logging), JCL (Apache Commons Logging), JPL (Java Platform Logging) and JBoss Logging are major logging APIs.

Logging implementation

A logging implementation is only required at runtime and can be changed without the need to recompile your software. Log4j Core, JUL (Java Logging), Logback are the most well-known logging implementations.

Logging bridge

Logging implementations accept input from a single logging API of their preference; Log4j Core from Log4j API, Logback from SLF4J, etc. A logging bridge is a simple logging implementation of a logging API that forwards all messages to a foreign logging API. Logging bridges allow a logging implementation to accept input from other logging APIs that are not their primary logging API. For instance, log4j-slf4j2-impl bridges SLF4J calls to Log4 API and effectively enables Log4j Core to accept input from SLF4J.

To make things a little bit more tangible, consider the following visualization of a typical Log4j Core installation with bridges for an application:

Visualization of a typical Log4j Core installation with SLF4J, JUL, and JPL bridges.
Figure 1. Visualization of a typical Log4j Core installation with SLF4J, JUL, and JPL bridges.

The java.util.logging logging API, available since JRE 1.4, shares many similarities with other logging API, such as SLF4J or Log4j API. Similarly to other APIs, it allows users to change the underlying LogManager implementation, but unlike other APIs, it has two big limitations:

  • it is part of JRE, which means that each JVM can contain only one instance of the LogManager class and all the applications of an application server must use the same LogManager implementation,

  • it does not support auto-detection of the logging backend through ServiceLoader or a similar mechanim (see JDK-8262741 ). In order to switch to an alternate LogManager implementation you must be able to set the java.util.logging.manager system property before the first logging call.

To work around the limitations of JUL, the JUL-to-Log4j bridge offers two installation options:

  1. If you are able to modify the java.util.logging.manager system property very early in the JVM startup process, you can replace the default LogManager implementation with a Log4j-specific one. This option gives the best performance. See Using LogManager for details.

  2. If JUL initializes before your application does, which is a typical behavior in application servers, you can still configure JUL to use Log4j as appender. See Using Log4jBridgeHandler for details.

Using LogManager

The best way to install the JUL-to-Log4j bridge on your system is to set the value of the java.util.logging.manager Java system property to

org.apache.logging.jul.tolog4j.LogManager

This property must be set very early in an application initialization process, e.g. using the -D<property>=<value> command line option of the java executable or by adding:

static {
  if (System.getProperty("java.util.logging.manager") == null) {
    System.setProperty("java.util.logging.manager", "org.apache.logging.jul.tolog4j.LogManager");
  }
}

at the top of your main class.

Setting this property will replace the default JUL LogManager implementation with a custom implementation that translates JUL Logger method calls into Log4j Logger calls with a minimal overhead.

LogManager-specific features

The use of the following j.u.l.Logger methods is not supported by the default AbstractLoggerAdapter implementation:

The implementation of these methods depends upon the specific Log4j API implementation used. If you need to modify the configuration of the logging backend programmatically:

Using Log4jBridgeHandler

Are you a Spring Boot user?

Spring Boot will automatically configure Log4jBridgeHandler.

If setting the java.util.logging.manager system property is not possible, the JUL-to-Log4j bridge offers an implementation of j.u.l.Handler abstract class, which redirects all log events to Log4j Core: org.apache.logging.log4j.jul.Log4jBridgeHandler.

The Log4jBridgeHandler requires Log4j Core as logging implementation and will fail with other Log4j API implementations.

In order to use Log4jBridgeHandler you can either:

  • modify the default JUL configuration file logging.properties to only contain:

    # Set Log4jBridgeHandler as only handler for all JUL loggers
    handlers = org.apache.logging.log4j.jul.Log4jBridgeHandler

    See the JRE documentation for details about the format and location of the logging.properties file.

  • or call the Log4jBridgeHandler.install() method in your code.

Usage of Log4jBridgeHandler introduces a considerably higher overhead, since logging events need to traverse the entire JUL logging pipeline followed by the logging pipeline of the Log4j API implementation.

Consider setting propagateLevels to true to reduce the overhead.

Level propagators

Log4jBridgeHandler configuration options

You can tune the behavior of Log4jBridgeHandler by adding the following properties to the logging.properties configuration file, which are also available as parameters to the install() method call:

appendSuffix

Property name

org.apache.logging.log4j.jul.Log4jBridgeHandler.appendSuffix

install() parameter

suffixToAppend

Type

String

Default value

null

Specifies the suffix to append to the name of all JUL loggers, which allows to differentiate JUL log messages from native Log4j API messages.

propagateLevels

Property name

org.apache.logging.log4j.jul.Log4jBridgeHandler.propagateLevels

install() parameter

propagateLevels

Type

boolean

Default value

false

The additional overhead of Log4jBridgeHandler can be especially heavy for disabled log statements. This is why you must ensure that log event filtering of the Log4j implementation and JUL are aligned. You can do it by either:

  • configuring JUL loggers with the same levels as the Log4j loggers,

  • or setting this property to true, which will perform the synchronization automatically.

Common configuration

Independently of the way you install the JUL-to-Log4j bridge, you can finely tune the behavior of the bridge using the following configuration properties. See Configuration properties for more details.

log4j.jul.levelConverter

Env. variable

LOG4J_JUL_LEVEL_CONVERTER

Type

Class<? extends LevelConverter>

Default value

org.apache.logging.jul.tolog4j.internal.DefaultLevelConverter

Fully qualified name of an alternative org.apache.logging.jul.tolog4j.spi.LevelConverter implementation.

Default level conversions
Java Level Log4j Level

OFF

OFF

SEVERE

ERROR

WARNING

WARN

INFO

INFO

CONFIG

custom CONFIG level with a numeric value of 450

FINE

DEBUG

FINER

TRACE

FINEST

custom FINEST level with a numeric value of 700

ALL

ALL

log4j.jul.loggerAdapter

Env. variable

LOG4J_JUL_LOGGER_ADAPTER

Type

Class<? extends AbstractLoggerAdapter>

Default value

org.apache.logging.jul.tolog4j.internal.ApiLoggerAdapter

Fully qualified class name of a custom org.apache.logging.jul.tolog4j.spi.AbstractLoggerAdapter implementation to use, which provides an implementation of the j.u.l.Logger mutator methods (e.g., Logger.setLevel()).

By default org.apache.logging.jul.tolog4j.internal.ApiLoggerAdapter is used and the mutator methods are disabled.