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

= Migrating from Logback

{logback-url}[Logback] is a logging implementation for the {slf4j-url}[SLF4J] logging API, just like Log4j Core is a logging implementation for the xref:manual/api.adoc[Log4j API].
In this page we will guide you through migrating from Logback to Log4j Core as your logging implementation.

[TIP]
====
Instead of migrating your logging implementation, Logback, are you looking for migrating your logging API, SLF4J?
Please refer to xref:migrate-from-slf4j.adoc[].
====

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

[#migrating]
== Migrating

You either have an application using Logback at runtime, or have a library using Logback for tests.
In either case, you can replace Logback with Log4j Core as follows:

. Remove `ch.qos.logback:logback-classic` dependency

. Remove `logback.xml` and `logback-test.xml` files

. Follow the instructions shared in the _"Getting started"_ page
** xref:manual/getting-started.adoc#install-app[for applications]
** xref:manual/getting-started.adoc#install-lib[for libraries]

Next you need to re-organize your logging API bridges such that all foreign APIs are bridged to Log4j API, the logging API implemented by Log4j Core.
This is explained in the next section.

[#bridges]
=== Bridges

It is highly likely that you were bridging all logging APIs (including Log4j API!) to SLF4J, the logging API implemented by Logback.
There are two particular approaches you can take here to ensure all logging APIs are instead bridged to Log4j API, the logging API implemented by Log4j Core:

[#bridge-to-log4j]
==== Bridge all logging APIs to Log4j API

We strongly advise you to bridge all foreign logging APIs *directly* to Log4j API.
You can use the cheat sheet shared below to implement that.

.Dependency migration cheat sheet
[cols="1,1"]
|===
| If dependency present | replace with

| `org.apache.logging.log4j:log4j-to-slf4j`
| `org.apache.logging.log4j:log4j-slf4j2-impl`

| `org.slf4j:jcl-over-slf4j`
| `commons-logging:commons-logging` version `>=1.3.0`

| `org.slf4j:jul-to-slf4j`
| `org.apache.logging.log4j:log4j-jul`

| `org.slf4j:log4j-over-slf4j`
| `org.apache.logging.log4j:log4j-1.2-api`

| `org.springframework:spring-boot-starter-logging`
| `org.springframework:spring-boot-starter-log4j2`
|===

[#bridge-to-sfl4j]
==== Bridge all logging APIs to SLF4J, and bridge SLF4J to Log4j API

You can implement this by replacing `org.apache.logging.log4j:log4j-to-slf4j` dependency with `org.apache.logging.log4j:log4j-slf4j2-impl`.

[WARNING]
====
*This approach is not recommended!*
It incurs certain drawbacks since some logging API calls will need to cross multiple bridges.
For instance, a call to JUL will first be bridged to SLF4J, and then from there to Log4j API.
====

[#config]
=== Configuration

It might not always be trivial to match the contents of the newly created `log4j2.xml` and `log4j2-test.xml` files with your old `logback.xml` and `logback-test.xml` files.
While all Logback components have corresponding equivalents in Log4j Core, they might not be sharing the same name or configuration.
To assist with migrating Logback configuration components to Log4j Core, see the following pages:

* xref:manual/appenders.adoc[]
* xref:manual/layouts.adoc[]
* xref:manual/filters.adoc[]

For the complete list of all Log4j configuration knobs, see xref:manual/configuration.adoc[the Configuration page].

[#parameterized-logging]
=== Parameterized logging

A common mistake in parameterized logging is to add a `{}` placeholder for the exception associated with a log event:

[source,java,indent=0]
----
include::example$migrate-from-logback/MigrateFromLogback.java[tag=wrong]
----

Log4j Core and Logback differ in the way they treat this statement:

Logback::
Logback interprets the `exception` argument as throwable and removes it from the list of parameters.
We end up with a parameterized statement with one placeholder, but zero parameters.
The placeholder therefore remains as is:
+
[source]
----
The foo process exited with and error: {}
java.lang.RuntimeException: Message
    at example.MigrateFromLogback.doLogWrong(MigrateFromLogback.java:10)
...
----

Log4j Core::
Log4j Core first looks for the parameters of the message.
Since the format string has one placeholder, the `exception` argument is interpreted as a parameter of the log message.
The throwable associated to the log event is `null`, which results in a missing stack trace:
+
[source]
----
The foo process exited with and error: java.lang.RuntimeException: Message
----

To fix this problem and get the same output in both backends, you should remove the placeholder from the format string:

[source,java,indent=0]
----
include::example$migrate-from-logback/MigrateFromLogback.java[tag=right]
----

After the change, the output will look us:

[source]
----
The foo process exited with and error.
java.lang.RuntimeException: Message
    at example.MigrateFromLogback.doLogWrong(MigrateFromLogback.java:10)
...
----

[TIP]
====
As a temporary solution, the SLF4J-to-Log4j API bridges contain a special
{log4j2-url}/manual/api.html#logger-message-factories[`MessageFactory`]
that classifies trailing `Throwable` arguments in the same way Logback does.
To use it, you need to set the
{log4j2-url}/manual/systemproperties.html#log4j2.messageFactory[`log4j2.messageFactory`]
configuration property to `org.apache.logging.slf4j.message.ThrowableConsumingMessageFactory`.
====
