Migrating from Log4j 1

Log4j 1 has reached End of Life in 2015, and is no longer supported. Vulnerabilities reported after August 2015 against Log4j 1 are not checked and will not be fixed. Users should upgrade to Log4j 2 to obtain security fixes.

Since Log4j 2 has been rewritten from scratch, it introduces many breaking changes to its predecessor. Most notably:

  • It uses a new package namespace (org.apache.logging.log4j), whereas Log4j 1 used the org.apache.log4j namespace,

  • It features a logging API which is independent of its reference implementation,

  • It uses a new more flexible configuration file format, which is incompatible with the format used by Log4j 1.

Prepare to migrate

Are you a library developer?

If you are developing a library, which functionality is not related to logging, you only need to rewrite the library to use Log4j 2 API. Skip directly to Log4j 1 API migration.

In order to migrate your application to Log4j 2 you need to assess first how your application and its dependencies use Log4j 1. While Log4j 1 didn’t have a formal split between a logging API and a logging backend, for the purpose of this guide, we’ll introduce the following split:

Log4j 1 API

It is the part of the Log4j 1 library that produces log events, and it is the most commonly used. The methods that are considered part of the Log4j 1 API are listed below:

Table 1. Log4j 1 API methods
Class name Methods

org.apache.log4j.MDC

All methods

org.apache.log4j.NDC

All methods

org.apache.log4j.Priority

All methods

org.apache.log4j.Level

All methods

org.apache.log4j.Category

All methods, except: methods for the AppenderAttachable interface, callsAppenders and setLevel.

org.apache.log4j.Logger

Same as Category

org.apache.log4j.LogManager

All methods

Log4j 1 Backend

This is the part of the logging library that consumes log events, formats them and writes to their destination. It also allows to configure Log4j 1 programmatically. It is usually not used in code, since the recommended way to configure Log4j 1 is through a configuration file.

While it is fairly simple to check which classes and methods in the org.apache.log4j package are used by your own application, the task is much more complex, when it comes to your application dependencies.

All the libraries that use Log4j 1 API in their code must have a compile dependency on either log4j:log4j or its clone ch.qos.reload4j:reload4j. There are however misconfigured libraries that declare those dependencies, even if they don’t directly use Log4j 1 at all.

To distinguish between libraries that use Log4j 1 and those that don’t, you can look for the presence of other logging APIs. If a library directly depends on:

it is fair to assume that it uses those libraries instead of Log4j 1 API, even if it has a direct dependency on log4j:log4j or ch.qos.reload4j:reload4j.

The following sections explain how to migrate from Log4j 1 to Log4j 2, depending on the way Log4j 1 is used in your application:

Log4j 1 API migration

To migrate an application that uses Log4j 1 API as logging API, the recommended approach is to modify your code. See Migrate code from Log4j 1 API to Log4j 2 API for details.

In the case one of your libraries uses Log4j 1 API or you can not modify your logging code at the moment, a Log4j 1 to Log4j 2 bridge is available. See Use Log4j 1 to Log4j 2 API bridge for details.

Migrate code from Log4j 1 API to Log4j 2 API

You can migrate your code from Log4j 1 to Log4j 2 automatically, by using the Log4j1ToLog4j2 OpenRewrite recipe. See OpenRewrite site for more details.

Except the change in the package name from org.apache.log4j to org.apache.logging.log4j, most of the class and method names in Log4j 2 API are inherited from Log4j 1 API.

In order to migrate you code, you need to:

To prevent a performance penalty from string concatenation in disabled log statements, Log4j 1 required the use of is*Enabled() guards:

if (LOGGER.isInfoEnabled()) {
    LOGGER.info("Hello " + username + "!");
}

Since Log4j 2 API introduces parameterized logging these guards are no longer necessary and the same statement can be rewritten as:

LOGGER.info("Hello {}!", username);

Use Log4j 1 to Log4j 2 API bridge

If you can not modify your application’s code or one of your dependencies is using Log4j 1 API as logging API, you can delay the migration process by installing the Log4j 1 to Log4j 2 bridge.

Since forwarding Log4j 1 API calls to Log4j 2 API calls is the basic functionality of the bridge, no further configuration is required from your part.

Log4j 1 Backend migration

If your application uses Log4j 1 only as logging backend bound to another logging API, such as Apache Commons Logging (JCL) or SLF4J, you only need to:

  1. Configure all logging bridges to log to Log4j 2 API instead. This can be done by replacing the following dependencies on your application’s runtime classpath:

    Table 5. Dependency migration from Log4j 1 to Log4j 2
    Replace Log4j 1 dependency with Log4j 2 dependency

    log4j:log4j

    org.apache.logging.log4j:log4j-core

    ch.qos.reload4j:reload4j

    org.apache.logging.log4j:log4j-core

    commons-logging:commons-logging

    either upgrade to version 1.3.0 (or later)

    or replace with org.apache.logging.log4j:log4j-jcl

    org.slf4j:slf4j-log4j12

    org.apache.logging.log4j:log4j-slf4j2-impl

    org.slf4j:slf4j-reload4j

    org.apache.logging.log4j:log4j-slf4j2-impl

    See Installation for more details.

  2. Convert your configuration files from the Log4j 1 to the Log4j 2 configuration format. See Log4j 1 Configuration file migration below for more details.

Migrate Log4j 1 custom components

Since Log4j 1 offered a limited amount of appenders and layouts, over the years users implemented many custom components that offered additional features. If you are currently using a custom Log4j 1 component you should proceed as follows:

  1. Log4j 2 provides many improvements to Log4j 1 components and many new components. Check if the feature offered by your custom component is not already available in Log4j 2. If you can not find the feature, ask on our support channels.

  2. Since Log4j 2.17.2, the Log4j 1 to Log4j 2 bridge has a limited support for using native Log4j 1 appenders and layouts. Native Log4j 1 components can only be configured using Log4j 1 configuration files (see Use Log4j 1 to Log4j 2 bridge) and require the installation of the Log4j 1 to Log4j 2 bridge.

    Mixing Log4j 1 and Log4j 2 components will most certainly reduce the performance of the logging system.

  3. If your Log4j 1 native component is not supported by the Log4j 1 to Log4j 2 bridge, we suggest to rewrite it directly as Log4j 2 component. See Extending for more details.

Log4j 1 Configuration file migration

Convert configuration file from Log4j 1 to Log4j 2

Although the Log4j 2 configuration syntax is different from that of Log4j 1, most, if not all, of the same functionality is available.

The log4j-1.2-api bridge contains a small utility that converts log4j.properties files into log4j2.xml file. In order to use it you need to:

  1. Download the log4j-api, log4j-core and log4j-1.2-api artifacts. To retrieve them all at once, see the Download page.

  2. Set the CLASSPATH environment variable to contain the artifacts mentioned above.

  3. Run

java org.apache.log4j.config.Log4j1ConfigurationConverter \
  --in log4j.properties --out log4j2.xml

Interpolation

Log4j 1 only supports interpolation using system properties and properties from the log4j.properties file using the ${foo} syntax. Log4j 2 extended this mechanism, by introducing pluggable Lookups.

In order to convert a Log4j 1 configuration file that uses interpolation to a Log4j 2 configuration file, replace all occurrences of ${foo} with ${sys:foo}.

Appenders

Log4j 2 contains an equivalent for most Log4j 1 appenders:

Table 6. Log4j 2 equivalents of Log4j 1 appenders
Log4j 1 appender Log4j 2 equivalent Notes

org.apache.log4j.AsyncAppender

Async

org.apache.log4j.ConsoleAppender

Console

org.apache.log4j.DailyRollingFileAppender

RollingFile

See additional steps below.

org.apache.log4j.FileAppender

File

org.apache.log4j.RollingFileAppender

RollingFile

See additional steps below.

org.apache.log4j.jdbc.JDBCAppender

JDBC

org.apache.log4j.net.JMSAppender

JMS

org.apache.log4j.net.SocketAppender

Socket

org.apache.log4j.net.SMTPAppender

SMTP

org.apache.log4j.net.SyslogAppender

Syslog

Does not support custom layouts.

org.apache.log4j.rewrite.RewriteAppender

Rewrite

The rolling file appender in Log4j 2 is based on the org.apache.log4j.rolling.RollingFileAppender from Apache™ Extras for Apache Log4j® and additional care must be taken to convert the Log4j 1 rolling appenders to their Log4j 2 equivalent:

  • Log4j 2 by default uses a different strategy to determine the index of the archived log files. Log4j 1 always rolls the current log file (e.g. app.log) to a log file with index 1 (e.g. app.log.1). Log4j 2 on the other hand uses the first available index (e.g. app.log.42 if files app.log.1 thru app.log.41 already exist).

    To use the same algorithm to determine the index of the logged file in Log4j 1 and Log4j 2, you need to configure the fileIndex attribute of the default rollover strategy to min.

    <DefaultRolloverStrategy fileIndex="min"/>
  • The two rolling file appenders available in Log4j 1, use an implicit file pattern and triggering policy for the archived log files. If the current log file is called app.log, you need to configure the Log4j 2 rolling file appender with the following filePattern and triggering policy configuration options:

Table 7. Rolling file appender conversion
Log4j 1 appender Log4j 2 filePattern Log4j 2 triggering policy

org.apache.log4j.DailyRollingFileAppender

app.%d{YYYY-MM-dd}

TimeBasedTriggeringPolicy

org.apache.log4j.RollingFileAppender

app.%i

SizeBasedTriggeringPolicy

Layouts

Log4j 1 layouts can be converted to Log4j 2 layouts using the following conversion rules:

org.apache.log4j.EnhancedPatternLayout

can be converted to a PatternLayout that uses the same pattern,

org.apache.log4j.HTMLLayout

can be converted to an HtmlLayout.

org.apache.log4j.PatternLayout

can be converted to a PatternLayout that uses the same pattern,

org.apache.log4j.SimpleLayout

can be converted to a PatternLayout that uses the %p - %m%n pattern,

org.apache.log4j.TTCCLayout

can be converted to a PatternLayout that uses the %r [%t] %p %c %notEmpty{%x }- %m%n pattern,

org.apache.log4j.xml.XMLLayout

does not have an exact equivalent in Log4j 2 Core. If backward compatibility is required, you can install the Log4j 1 to Log4j 2 bridge and use the Log4j1XmlLayout plugin.

The formatting of the %p (when used with custom levels), %x and %X pattern converters slightly changed between Log4j 1 and Log4j 2. If an exact backward compatibility is required, you need to install the Log4j 1 to Log4j 2 bridge and use the following extended patterns:

Log4j 1 pattern Log4j 1 to Log4j 2 bridge pattern

%p

%v1Level

%x

%ndc

%X

%properties

Use Log4j 1 to Log4j 2 bridge

If you can not convert your configuration files from Log4j 1 to Log4j 2, the Log4j 1 to Log4j 2 bridge can convert your configuration files at runtime. In order to use this feature you need to Install the Log4j 1 to Log4j 2 bridge and set one of the following configuration properties:

log4j1.compatibility

Env. variable

LOG4J_COMPATIBILITY

Type

boolean

Default value

false

If set to true, Log4j 2 will scan the classpath to find Log4j 1 configuration files in the following standard locations:

  • log4j-test.properties,

  • log4j-test.xml,

  • log4j.properties,

  • log4j.xml.

log4j.configuration

Env. variable

LOG4J_CONFIGURATION_FILE

Type

Path or URI

Default value

null

If not null, Log4j 2 will try to retrieve a Log4j 1 configuration file from the given location. The configuration file name must end in .properties (Log4j 1 properties format) or .xml (Log4j 1 XML format). See also limitations of Log4j 1 configuration compatibility layer.

Log4j 1 to Log4j 2 bridge

In order to help users with the migration process, a Log4j 1 to Log4j 2 bridge is available. The bridge can fulfill three separate functions:

  • it forwards all Log4j 1 API method calls to the corresponding Log4j 2 API calls,

  • since version 2.17.2 is supports the usage of some components written for Log4j 1 inside Log4j 2 Core,

  • it provides a limited support for programmatic configuration of Log4j 2 Core, using Log4j 1 method calls,

  • it provides a limited support for Log4j 1 configuration file formats.

Installation

Since the Log4j 1 to Log4j 2 Bridge replaces Log4j 1 classes, it is incompatible with the following artifacts:

Before installing the bridge, you need to make sure that none of the artifacts above are present in your runtime classpath.

To install the bridge, add the following dependency to your application:

  • Maven

  • Gradle

We assume you use log4j-bom for dependency management.

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-1.2-api</artifactId>
  <scope>runtime</scope>
</dependency>

We assume you use log4j-bom for dependency management.

runtimeOnly 'org.apache.logging.log4j:log4j-1.2-api'

When to stop using the Log4j 1 to Log4j 2 bridge

The Log4j 1 to Log4j 2 bridge is not conceived as a long term solution. Once:

the bridge is no longer necessary and should be removed.

The separation of logging APIs from logging implementations started in 2002, with the release of Apache Commons Logging (formerly known as Jakarta Commons Logging).

We are unaware of any maintained library that is currently using Log4j 1. However, if this is your case, please contact the library maintainer and ask them to migrate to one of the available logging APIs.