Log4j Transform contains tools for binary postprocessing of projects that use the Apache Log4j2 API.

Log4j Transform Maven Plugin

The Transform Plugin is used to postprocess the compiled classes of your project and replace all Log4j 2.x API calls with LogBuilder calls with a statically precomputed location. This allows you to use location information in your logs without incurring in the expensive runtime calls usually used to acquire it.

Why do we need it

Finding the location of a logging call is a very expensive operation (a couple of microseconds).

Running LocationBenchmark on a Ryzen 7 2700U laptop with Java 17 gives the following results:

Logging interface Sync/async logger No. threads Precomputed location Score Error Units

LogBuilder

sync

1

yes

202343,624

±719,875

ops/s

LogBuilder

sync

1

no

68449,813

±5086,148

ops/s

Logger

sync

1

yes

202579,793

±547,961

ops/s

Logger

sync

1

no

100105,246

±13748,554

ops/s

Logger

async

8

yes

726877,012

±38214,575

ops/s

Logger

async

8

no

440245,135

±4849,946

ops/s

The figures show a performance bump of around 5 µs per logging statement when Logger is used and a bump of around 9 µs per logging statement when LogBuilder is used.

By comparison, disabling location information on the same machine gives:

Logging interface Sync/async logger No. threads Precomputed location Score Error Units

LogBuilder

sync

1

yes

234666,556

±19759,779

ops/s

LogBuilder

sync

1

no

212562,315

±3631,670

ops/s

Logger

sync

1

yes

210751,730

±1508,148

ops/s

Logger

sync

1

no

220837,404

±13248,184

ops/s

Logger

async

8

yes

743467,533

±38046,044

ops/s

Logger

async

8

no

776778,635

±38878,794

ops/s

How it works

The working principle is very simple: every call to the Log4j 2.x API like

public void helloLog() {
    logger.info(MarkerManager.getMarker("NET"), "Sending {} bytes of data.", 1000);
}

is rewritten at a bytecode level into an equivalent LogBuilder call:

private static final StackTraceElement[] locations = {
        new StackTraceElement("org.apache.logging.log4j.HelloWorld", "HelloWorld.java", "helloLog", 1234)
};

public void helloLog() {
    logger.atInfo()
          .withLocation(locations[0])
          .withMarker(MarkerManager.getMarker("NET"))
          .log("Sending {} bytes of data.", 1000);
}

In the current implementation locations are stored in classes whose name ends in $$Log4j2$$Cache, so they can not accidentally be used by XML/JSON serializers.

Goals

This plugin consists of a single goal:

log4j-transform:process-classes

is bound to the process-classes phase and weaves your classes to include precomputed location information.

log4j-transform:process-classes

Full name

org.apache.logging.log4j:log4j-transform-maven-plugin:0.1.0:process-classes

Description

Generates static location information of Log4j 2.x API calls in the project classes. The resulting bytecode will not rely on runtime resolution of the location information.

Attributes
  • Requires a Maven project to be executed

  • Requires dependency resolution of artifacts in scope: <code>compile</code>

  • The goal is thread-safe and supports parallel builds

  • Binds by default to the lifecycle phase: process-classes.

Required Parameters
Name Type Description

<sourceDirectory>

File

The directory containing classes to be processed. It defaults to ${project.build.outputDirectory}.

<sourceDirectory>

File

The directory where woven classes will be written. It defaults to ${project.build.outputDirectory}.

Optional Parameters
Name Type Description

<includes>

List<String>

Files to include. If empty all class files will be processed.

<excludes>

List<String>

Files to exclude.

<staleMillis>

int

Sets the granularity in milliseconds of the last modification date for testing if a class file needs weaving. It defaults to 0 and can be configured using the lastModGranularityMs property.

Usage

To use the plugin you need to declare a dependency on log4j-api version 2.20.0 or newer.

Add the following configuration to your POM file:

<plugin>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-transform-maven-plugin</artifactId>
  <version>0.1.0</version>
  <executions>
    <execution>
      <goals>
        <goal>process-classes</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Maven Shade Plugin Extensions

This project contains a collection of resource transformers for the Apache Maven Shade Plugin that allows you to use additional Log4j 2.x Core component modules.

Log4j Plugin Cache Transformer

A resource transformer for the Apache Maven Shade Plugin that merges Log4j2Plugins.dat plugin caches from all the jars containing Log4j 2.x Core components.

This transformer was formerly available at edwgiz/maven-shaded-log4j-transformer and was donated to the Apache Software Foundation by its author.

Usage

This resource transformer is usually used together with the ManifestResourceTransformer and ServicesResourceTransformer to integrate Log4j 2.x libraries in a shaded JAR.

A typical configuration is:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.4.1</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-transform-maven-shade-plugin-extensions</artifactId>
      <version>0.1.0</version>
    </dependency>
  </dependencies>
  <executions>
    <execution>
      <id>shade-jar-with-dependencies</id>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <transformers>
          <transformer implementation="org.apache.logging.log4j.maven.plugins.shade.transformer.Log4j2PluginCacheFileTransformer"/>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
              <Multi-Release>true</Multi-Release>
            </manifestEntries>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Development

Log4j Transform uses GitHub for source code management.

The project requires a Java compiler matching the [17,18) range and targets Java 8.

You can build and verify sources using:

./mvnw verify

You can build and view the website as follows:

./mvnw -N site
python -m http.server -d target/site

Distribution

In accordance with the Apache Software Foundation’s release distribution policy and creation process, project artifacts are officially accessible from the following locations:

See the release instructions for details.

Support

Please keep in mind that this project is intended for internal usage only. You can use GitHub Issues for feature requests and bug reports – not questions! See the Log4j support policy for details.

Security

If you have encountered an unlisted security vulnerability or other unexpected behaviour that has security impact, please report them privately to the Log4j security mailing list. See the Log4j Security page for further details.

Release Notes

0.x.x

This is the second release of the project.

Added

Changed

  • Migrated to logging-parent 10.1.1 and adopted its CI and pom.xml infrastructure

  • Update org.ow2.asm:asm-bom to version 9.6

0.1.0

Release date

2023-05-05

This is the first release of the project.

Added

  • Added log4j-transform-maven-plugin bytecode transformation tool to provide location information without reflection (LOG4J2-3638)

  • Added log4j-transform-maven-shade-plugin-extensions resource transformer for the Maven Shade Plugin to merge Log4j2Plugins.dat plugin caches (LOG4J2-673)

Release instructions

Log4j Transform employs the CI/CD foundation provided by the logging-parent. You can simply use its release instructions.

License

Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See NOTICE.txt 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 https://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.