Lookups

Log4j Core provides a flexible and extensible property substitution system.

Property substitution system
Figure 1. Property substitution system

The property substitution system is composed of these elements:

  • A string interpolation engine (StrSubstitutor) that evaluates ${...} expressions. These expressions can contain recursive expressions and default values.

    See property substitution for more details.

  • The Interpolator that evaluates simple ${name} expressions.

    The Interpolator has two functions:

    • If name does not contain a colon : character, the Interpolator uses the Properties configuration element to resolve its value.

    • If name is of the form prefix:key, the Interpolator delegates the lookup to a StrLookup associated with prefix and falls back to evaluating ${key} if the lookup was not successful.

  • A set of StrLookup plugins, each one associated with a prefix, which retrieve data from external sources.

StrLookup is a simple map-like interface. The main difference between a map and StrLookup is that the latter can compute the value of a key dynamically in a global context or in the context of log event.

Common concerns

Evaluation contexts

Each lookup has an associated prefix, and Log4j can evaluate it in one of the following ways:

Global context

In a global context Log4j evaluates ${prefix:key} expressions by calling lookup("key") on the lookup associated to prefix. The result of this call only takes into account the global state of the system.

The global context is used to expand the attributes of a configuration file.

Log event context

In the context of a log event event, Log4j evaluates ${prefix:key} expressions by calling lookup(event, "key") on the lookup associated to prefix. The result of this call might take into account the contents of the log event, besides the global state of the system.

Some configuration attributes (e.g., the pattern attribute of Pattern Layout) supports both evaluation contexts:

  • During the configuration process the ${...} expressions are evaluated using a global context. The same process converts escaped $${...} expressions to ${...} expressions.

  • For each log event, the remaining expressions are evaluated, using the log event as context.

Lookups can choose to react differently depending on the execution context. Date Lookup is such an example:

Lazy lookups and pattern converters

For historical reasons, the pattern attribute of PatternLayout supports two similar string replacement mechanisms:

Both lazy $${...} property expressions and pattern converters have access to the value of the current LogEvent and can provide similar results. There is, however, an important difference between them:

  • Pattern converters can be garbage-free. See Garbage-free pattern converters for more details.

  • Lazy lookups are not garbage-free and always create temporary String objects.

Collection

Log4j Core provides many lookups out-of-the-box:

Lookups operating on the global context

A large group of lookups supports evaluation in a global context. These lookups can be safely used in eagerly evaluated properties of a configuration file using the ${prefix:key} syntax:

Table 1. Lookups operating on the global context
Prefix Dependency Data source

bundle

A Java resource bundle

ctx

Thread Context

date

Current timestamp

docker

log4j-docker

Docker container

env

Environment variables

java

JVM characteristics

jndi

JNDI

log4j

Location of Log4j configuration file

lower

It converts the supplied key to lowercase

main

JVM application arguments

marker

Returns key if a marker named key exists

spring

log4j-spring-boot

Spring Boot 2.x environment.

sys

Java system properties

upper

It converts the supplied key to uppercase

web

log4j-jakarta-web

Jakarta ServletContext.

Lookups operating on the log event context

The following lookups only support evaluation in the context of a log event or behave differently, when evaluated in such a context:

Table 2. Lookups operating on the log event context
Prefix Dependency Data source

ctx

Log event context data

date

Log event timestamp

event

Log event

map

MapMessage

marker

Log event marker

sd

StructuredDataMessage

Resource Bundle Lookup

Context global

Syntax

bundle:<baseName>:<key>

where:

baseName

the base name of a resource bundle (see ResourceBundle).

key

the key for the resource string.

The Resource Bundle Lookup retrieves strings from Java Resource bundles, e.g.:

${bundle:org.example.Main:errorMessage}

Do you want to use the values in Spring Boot’s application.properties file? Use Spring Boot 2 Lookup or Spring Boot 3 Lookup instead.

Context Map Lookup

Context global and log event

Syntax

ctx:<key>

where <key> is any String.

The Context Map Lookup can be used in two different contexts:

Global context

If used in the global context, it uses the Thread Context to retrieve data.

When used in this context custom context data providers are not supported.

Log event context

In the context of an event, the Context Map lookup uses the Log event context map data of a log event to resolve the key. Custom context data providers are therefore supported.

Don’t use $${ctx:key} in the Pattern Layout conversion patterns! Use the %X{key} pattern converter instead.

See Lazy lookups and pattern converters for more information.

Date Lookup

Context global and log event

Syntax

date:<format>

where <format> is a SimpleDateFormat pattern

The Date Lookup formats a timestamp, using the supplied key as format. The timestamp used depends on the context:

Global context

When used in a global context, the timestamp used is the current system timestamp as returned by System.currentTimeMillis().

Log event context

When used in the context of a log event, the timestamp of the log event is used.

Don’t use $${date:format} in the Pattern Layout conversion patterns! Use the %d{key} pattern converter instead.

See Lazy lookups and pattern converters for more information.

Docker Lookup

Context global

Syntax

docker:<key>

where <key> is one of the Docker Lookup supported keys.

Dependency

log4j-docker

Docker Lookup queries the API of the Docker Engine running your container. It supports the retrieval of following container attributes:

Table 3. Docker Lookup supported keys
Key Description

containerId

Container ID

containerName

Container name

imageId

Container image ID

imageName

Container image name

shortContainerId

The first 12 characters of the container ID

shortImageId

The first 12 characters of the container image ID

Additional runtime dependencies are required for using Docker Lookup:
  • Maven

  • Gradle

We assume you use log4j-bom for dependency management.

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-docker</artifactId>
  <version>2.24.0</version>
  <scope>runtime</scope>
</dependency>

We assume you use log4j-bom for dependency management.

runtimeOnly 'org.apache.logging.log4j:log4j-docker:2.24.0'

Environment Lookup

Context global

Syntax

env:<key>

where <key> is any String

The Environment Lookup retrieves the value of the OS environment variable associated with the key.

Event Lookup

Context log event

Syntax

event:<key>

where <key> is one of the Event Lookup supported keys.

The Event Lookup provides access to fields of the current log event. It supports the retrieval of the following event attributes:

Table 4. Event Lookup supported keys
Key Description

Exception

Simple class name of the exception, if one is present.

Level

Logging level of the event

Logger

Name of the logger

Marker

Marker associated with the log event, if one is present.

Message

Formatted Message

ThreadId

Thread id associated with the log event

ThreadName

Name of the thread associated with the log event

Timestamp

UNIX timestamp in milliseconds of the log event

Don’t use $${event:key} in the Pattern Layout conversion patterns! There is a specialized pattern converter replacement for each of these lookups.

See Lazy lookups and pattern converters for more information.

Java Lookup

Context global

Syntax

java:<key>

where <key> is one of the Java Lookup supported keys.

The Java Lookup allows retrieving information about the Java environment the application is using. The following keys are supported

Table 5. Java Lookup supported keys
Key Description Example

version

Short Java version

Java version 21.0.3

runtime

Java runtime version

OpenJDK Runtime Environment (build 21.0.3+9-LTS) from Eclipse Adoptium

vm

Java VM version

OpenJDK 64-Bit Server VM (build 21.0.3+9-LTS, mixed mode, sharing)

os

OS version

Linux 6.1.0-18-amd64, architecture: amd64-64

locale

System locale and file encoding

default locale: en_US, platform encoding: UTF-8

hw

Hardware information

processors: 32, architecture: amd64-64, instruction sets: amd64`

JNDI Lookup

Context global

Syntax

jndi:<name>

where <name> is a JNDI Name.

As of Log4j 2.17.0 you need to enable the JNDI lookup explicitly by setting the log4j2.enableJndiLookup configuration property to true.

The JNDI Lookup retrieves the value of an environment entry from JNDI. Only the java: protocol is supported. If the key does not have a protocol, java:comp/env is prepended.

As an example, to retrieve the value of java:comp/env/app_name you can use:

$${jndi:app_name}

Android does not support JNDI.

Configuration Location Lookup

Context global

Syntax

log4j:<key>

where <key> is one of the Configuration Location Lookup supported keys.

The Configuration Location Lookup supports two keys:

Table 6. Configuration Location Lookup supported keys
Key Description

configLocation

Returns the location of the configuration file as an absolute file path or URI.

configParentLocation

Returns the location of the folder containing the configuration file as an absolute file path or URI.

Lower Lookup

Context global

Syntax

lower:<key>

where <key> is any String.

The Lower Lookup converts the passed in argument to lowercase.

Presumably, the value will be the result of a nested lookup as in the example:

${lower:${sys:appname}}

Main Arguments Lookup

Context global

Syntax

main:<key>

wherre <key> either a non-negative int or a String.

This lookup requires a setup step: your application needs to call MainMapLookup#setMainArguments() and pass as argument the arguments received by the application.

The Main Arguments Lookup provides a way to query the arguments received by your application. It supports two kinds of keys:

  • if the key is an integer, e.g. ${main:0}, it is interpreted as 0-based index in the argument array.

  • if the key is a String, e.g. ${main:foo}, the argument that follows foo in the argument array is returned.

Table 7. Lookup results for "foo bar baz" arguments

Lookup

Expansion

${main:0}

foo

${main:1}

bar

${main:2}

baz

${main:foo}

bar

${main:bar}

baz

You can use this lookup to provide a primitive argument parsing mechanism to your application:

  • First, you need to pass your application’s arguments to the MainMapLookup#setMainArguments method:

    private final Logger logger = LogManager.getLogger(); (1)
    
    public static void main(final String[] args) {
        try { (2)
            Class.forName("org.apache.logging.log4j.core.lookup.MainMapLookup")
                    .getDeclaredMethod("setMainArguments", String[].class)
                    .invoke(null, (Object) args);
        } catch (final ReflectiveOperationException e) {
            // Log4j Core is not used.
        }
        new MainArgsExample().run();
    }
    1 Use an instance logger field instead of a static one, to prevent Log4j Core initialization before main() is called.
    2 Call MainMapLookup#setMainArguments by reflection to allow your application to run with a different Log4j API implementation.
  • Now you can use ${main:...} lookups in your configuration file to support the usage of a --logfile <file> CLI argument to specify the log file and --loglevel <level> CLI argument to specify the log level.

    • XML

    • JSON

    • YAML

    • Properties

    <?xml version="1.0" encoding="UTF-8"?>
    <Configuration xmlns="https://logging.apache.org/xml/ns"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="
                       https://logging.apache.org/xml/ns
                       https://logging.apache.org/xml/ns/log4j-config-2.xsd">
      <Properties> (1)
        <Property name="--logfile" value="logs/app.log"/>
        <Property name="--loglevel" value="INFO"/>
      </Properties>
      <Appenders>
        <File fileName="${main:\--logfile}"
              name="FILE"/> (2)
      </Appenders>
      <Loggers>
        <Root level="${main:\--loglevel}"> (2)
          <AppenderRef ref="FILE"/>
        </Root>
      </Loggers>
    </Configuration>
    {
      "Configuration": {
        "Properties": {
          "Property": [ (1)
            {
              "name": "--logfile",
              "value": "logs/app.log"
            },
            {
              "name": "--loglevel",
              "value": "INFO"
            }
          ]
        },
        "Appenders": {
          "File": {
            "fileName": "${main:\\--logfile}", (2)
            "name": "FILE",
            "JsonTemplateLayout": {}
          }
        },
        "Loggers": {
          "Root": {
            "level": "${main:\\--loglevel", (2)
            "AppenderRef": {
              "ref": "FILE"
            }
          }
        }
      }
    }
    Configuration:
      Properties: (1)
        Property:
          - name: "--logfile"
            value: "logs/app.log"
          - name: "--loglevel"
            value: "INFO"
      Appenders:
        File:
          fileName: "${main:\\--logfile}" (2)
          name: "FILE"
          JsonTemplateLayout: {}
      Loggers:
        Root:
          level: "${main:\\--loglevel}" (2)
          AppenderRef:
            ref: "FILE"
    (1)
    property.--logfile = logs/app.log
    property.--loglevel = INFO
    
    appender.0.type = File
    (2)
    appender.0.fileName = ${main:\\--logfile}
    appender.0.name = FILE
    
    (2)
    rootLogger.level = ${main:\\--loglevel}
    rootLogger.appenderRef.0.ref = FILE
    1 Provide default values for the CLI arguments if they are not specified.
    2 Escape the special :- sequence using :\-.

Map Lookup

Context log event

Syntax

map:<key>

where <key> is any String.

The Map Lookup retrieves the value assigned to the given key in a MapMessage.

Don’t use $${map:key} in the Pattern Layout conversion patterns! Use the %K{key} pattern converter instead.

See Lazy lookups and pattern converters for more information.

Marker Lookup

Context global or log event

Syntax

marker:<key>

where <key> is any String

The Marker Lookup can be used in two different ways:

Global context

When used in a global context, it returns key if there is a marker named key or null otherwise. For example:

${marker:AUDIT:-NO_AUDIT}

will expand to AUDIT if a marker with that name exists or NO_AUDIT otherwise.

Log event context

When used in the context of a log event, it returns the log event marker if it exists.

Don’t use $${marker:} in the Pattern Layout conversion patterns! Use the %markerSimpleName pattern converter instead.

See Lazy lookups and pattern converters for more information.

Spring Boot 2 Lookup

Context global

Syntax

spring:<key>

where <key> is one of the Spring Boot 2 Lookup supported keys.

Dependency

Log4j Spring Boot Support

If you are using Spring Boot 3, you should use the third party Spring Boot 3 Lookup instead.

The Spring Boot 2 Lookup allows user to query Spring Boot’s externalized configuration files. It supports the following keys:

Table 8. Spring Boot 2 Lookup supported keys
Key Description

profiles.active

Comma-separated list of active profiles.

profiles.active[<n>]

The active profile with 0-based index <n>.

profiles.default

Comma-separated list of default profiles.

profiles.default[<n>]

The default profile with 0-based index <n>.

<key>

The value associated with <key> in Spring’s Environment.

Spring Boot 2 initializes Log4j Core at least twice:

  • Log4j Core is initialized the first time using its own automatic configuration procedure. At this point, the lookup will always return null. Configuration files that use the standard log4j2.<extension> naming convention, should provide default values for all Spring lookups.

  • As soon as Spring’s Environment is ready, the lookup becomes available and a reconfiguration is triggered. If you want to provide a configuration file specifically for this phase, call it log4j2-spring.<extension>.

Additional runtime dependencies are required for using Spring Boot Lookup:

  • Maven

  • Gradle

We assume you use log4j-bom for dependency management.

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-spring-boot</artifactId>
  <scope>runtime</scope>
</dependency>

We assume you use log4j-bom for dependency management.

runtimeOnly 'org.apache.logging.log4j:log4j-spring-boot'

Structured Data Lookup

Context log event

Syntax

sd:<key>

where <key> is either one of the Structured Data Lookup virtual keys or any String

The Structured Data Lookup is very similar to Map Lookup and retrieves the value assigned to the given key in a StructuredDataMessage. Additionally, the following virtual keys are supported:

Table 9. Structured Data Lookup virtual keys
Key RFC5424 field Description

id

SD-ID

The id field of the StructuredDataMessage.

type

MSGID

The type field of a StructuredDataMessage.

Except $${sd:id} and $${sd:type}, don’t use other $${sd:key} expressions in the Pattern Layout conversion patterns! Use the %K{key} pattern converter instead.

See Lazy lookups and pattern converters for more information.

System Properties Lookup

Context global

Syntax

sys:<prop>

where <prop> is any String

The System Properties Lookup retrieves the value of the Java system property associated with the key.

Upper Lookup

Context global

Syntax

upper:<key>

where <key> wi any String

The Upper Lookup converts the passed in argument to uppercase.

Presumably, the value will be the result of a nested lookup as in the example:

${upper:${sys:appname}}

Web Lookup

Context global

Syntax

web:<key>

where <key> is one of the Web Lookup supported keys.

Dependency

log4j-jakarta-web

The Web Lookup allows applications to retrieve variables that are associated with the Jakarta ServletContext of the web application.

The following table lists various keys that can be retrieved:

Table 10. Web Lookup supported keys
Key Description

attr.<name>

Returns the ServletContext attribute with the specified <name>.

contextPath

The context path of the web application

contextPathName

The first token in the context path of the web application splitting on "/" characters.

effectiveMajorVersion

Gets the major version of the Servlet specification that the application represented by this ServletContext is based on.

effectiveMinorVersion

Gets the minor version of the Servlet specification that the application represented by this ServletContext is based on.

initParam.<name>

Returns the ServletContext initialization parameter with the specified <name>.

majorVersion

Returns the major version of the Servlet API that this servlet container supports.

minorVersion

Returns the minor version of the Servlet API that this servlet container supports.

rootDir

Returns the result of calling getRealPath with a value of "/".

serverInfo

Returns the name and version of the servlet container on which the servlet is running.

servletContextName

Returns the name of the web application as defined in the display-name element of the deployment descriptor

<name>

Return the first of attr.<name> and initParam.<name> that is defined.

Using the Web Lookup, you can, for example, place the log file in the application’s root directory:

<Appenders>
  <File name="ApplicationLog" fileName="${web:rootDir}/app.log"/>
</Appenders>

Additional runtime dependencies are required for using web lookup:

  • Maven

  • Gradle

We assume you use log4j-bom for dependency management.

<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-jakarta-web</artifactId>
  <scope>runtime</scope>
</dependency>

We assume you use log4j-bom for dependency management.

runtimeOnly 'org.apache.logging.log4j:log4j-jakarta-web'
Click here if you are you using Jakarta EE 8 or any version of Java EE?

Jakarta EE 8 and all Java EE applications servers use the legacy javax package prefix instead of jakarta. If you are using those application servers, you should replace the dependencies above with:

  • Maven

  • Gradle

We assume you use log4j-bom for dependency management.

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

We assume you use log4j-bom for dependency management.

runtimeOnly 'org.apache.logging.log4j:log4j-web'

Third-party lookups

The following additional lookups are available from third-party vendors:

Kubernetes Lookup

Syntax

k8s:<key>

Dependency

Log4j Kubernetes of Fabric8

Kubernetes Lookup queries the Kubernetes API to retrieve certain information about the current container and its environment. Kubernetes Lookup is distributed as a part of Fabric8’s Kubernetes Client, refer to its website for details.

Spring Boot 3 Lookup

Syntax

spring:<key>

Dependency

integrated in Spring Boot 3

Starting with Spring Boot 3 a ${spring:...} lookup is available out-of-the-box. Spring Boot documentation for more details.

The Spring Boot 3 Lookup conflicts with the Spring Boot 2 Lookup. If you are upgrading to Spring Boot 3, make sure to remove the latter from your classpath.

Extending

Lookups are plugins implementing the StrLookup interface. This section will guide you on how to create custom ones.

While the predefined lookup collection should address most common use cases, you might find yourself needing to implement a custom one. If this is the case, we really appreciate it if you can share your use case in a user support channel.

Plugin preliminaries

Log4j plugin system is the de facto extension mechanism embraced by various Log4j components. Plugins provide extension points to components, that can be used to implement new features, without modifying the original component. It is analogous to a dependency injection framework, but curated for Log4j-specific needs.

In a nutshell, you annotate your classes with @Plugin and their (static) factory methods with @PluginFactory. Last, you inform the Log4j plugin system to discover these custom classes. This is done using running the PluginProcessor annotation processor while building your project. Refer to Plugins for details.

Extending lookups

Lookups are plugins implementing the StrLookup interface. While annotating your lookup with @Plugin, you need to make sure that

  • It has a unique name attribute across all available StrLookup plugins

  • The category attribute is set to StrLookup.CATEGORY

You can check out the following files for examples: