////
Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements.  See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License.  You may obtain a copy of the License at

         http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
////

= JUL-to-Log4j bridge

The JUL-to-Log4j bridge provides components that allow application and library that use
https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html[`java.util.logging.Logger`]
(JUL) to log to the Log4j API instead.

[IMPORTANT]
====
This chapter covers advanced usage scenarios of the JUL-to-Log4j bridge.
For the installation procedure and basic configuration see
xref:manual/installation.adoc#impl-core-bridge-jul[Using JUL-to-Log4j]
section of our
xref:manual/installation.adoc[Installation guide].
====

[#configuration]
== Configuration

.Struggling with the logging API, implementation, and bridge concepts? Click for an introduction.
[%collapsible]
====
include::partial$concepts.adoc[tag=!software-type]
====

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
https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/LogManager.html[`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
https://bugs.openjdk.org/browse/JDK-8262741[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:

. 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 <<bridge-logmanager>> for details.
. 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 <<bridge-handler>> for details.

[#bridge-logmanager]
== 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:

[source,java]
----
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.

[#bridge-logmanager-features]
=== `LogManager`-specific features

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

* https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html#setFilter(java.util.logging.Filter)[`Logger.setFilter(j.u.l.Filter)`],
* https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html#setLevel(java.util.logging.Level)[`Logger.setLevel(j.u.l.Level)`],
* https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html#setParent(java.util.logging.Logger)[`Logger.setParent(j.u.l.Logger)`],
* https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html#setUseParentHandlers(boolean)[`Logger.setUseParentHandlers(boolean)`],
* https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html#addHandler(java.util.logging.Handler)[`Logger.addHandler(j.u.l.Handler)`],
* https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Logger.html#removeHandler(java.util.logging.Handler)[`Logger.removeHandler(j.u.l.Handler)`].

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:

* either modify the logging backend configuration directly.
See xref:manual/customconfig.adoc[] if you are using the xref:manual/implementation.adoc[Log4j Core implementation].
* or provide a custom `AbstractLoggerAdapter` that provides an implementation for these methods.
See <<log4j.jul.loggerAdapter>> for details about custom adapters.

[#bridge-handler]
== Using `Log4jBridgeHandler`

.Are you a Spring Boot user?
[TIP]
====
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
https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/Handler.html[`j.u.l.Handler`]
abstract class, which redirects all log events to Log4j Core:
`org.apache.logging.log4j.jul.Log4jBridgeHandler`.

[WARNING]
====
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:
+
[source,properties]
----
# Set Log4jBridgeHandler as only handler for all JUL loggers
handlers = org.apache.logging.log4j.jul.Log4jBridgeHandler
----
+
See the
https://docs.oracle.com/en/java/javase/{java-target-version}/docs/api/java.logging/java/util/logging/LogManager.html[JRE documentation]
for details about the format and location of the `logging.properties` file.

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

[IMPORTANT]
====
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 <<#bridge-handler-propagateLevels>> to `true` to reduce the overhead.
====

[#bridge-handler-propagator]
=== Level propagators

[#bridge-handler-config]
=== `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:

[#bridge-handler-appendSuffix]
=== `appendSuffix`

[cols="2h,5"]
|===
| 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.

[#bridge-handler-propagateLevels]
=== `propagateLevels`

[cols="2h,5"]
|===
| 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]
== 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 xref:manual/systemproperties.adoc[] for more details.

include::partial$manual/systemproperties/properties-log4j-jul.adoc[leveloffset=+1]

