Lookups
Log4j Core provides a flexible and extensible 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 theProperties
configuration element to resolve its value. -
If
name
is of the formprefix:key
, the Interpolator delegates the lookup to aStrLookup
associated withprefix
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 callinglookup("key")
on the lookup associated toprefix
. 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 callinglookup(event, "key")
on the lookup associated toprefix
. 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:
-
When used in a global context, it formats the current timestamp obtained through
System.currentTimeMillis()
. -
When used in the context of an event, it formats the event timestamp obtained through
LogEvent.getTimeMillis()
.
Lazy lookups and pattern converters
For historical reasons, the
pattern
attribute of PatternLayout
supports two similar string replacement mechanisms:
-
${...}
property expressions.
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 A Java resource bundle
https://logging.apache.org/log4j/2.x/manual/thread-context.html
Current timestamp
log4j-docker
Docker container
Environment variables
JVM characteristics
log4j-jndi
JNDI
Location of Log4j configuration file
It converts the supplied key to lowercase
JVM application arguments
Returns
key
if a marker namedkey
existsJava system properties
It converts the supplied key to uppercase
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 Log event context data
Log event timestamp
Log event marker
Resource Bundle Lookup
Context | global |
---|---|
Syntax |
where:
|
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 |
Context Map Lookup
Context | global and log event |
---|---|
Syntax |
where |
The Context Map Lookup can be used in two different contexts:
- Global context
-
If used in the global context, it uses the ThreadContext 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 |
where |
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 |
where |
Dependency |
Docker Lookup queries the API of the Docker Engine running your container. It supports the retrieval of following container attributes:
Key | Description |
---|---|
|
Container ID |
|
Container name |
|
Container image ID |
|
Container image name |
|
The first 12 characters of the container ID |
|
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>
<scope>runtime</scope>
</dependency>
We assume you use log4j-bom
for dependency management.
runtimeOnly 'org.apache.logging.log4j:log4j-docker'
Environment Lookup
Context | global |
---|---|
Syntax |
where |
The Environment Lookup retrieves the value of the OS environment variable associated with the key.
Event Lookup
Context | log event |
---|---|
Syntax |
where |
The Event Lookup provides access to fields of the current log event. It supports the retrieval of the following event attributes:
Key | Description |
---|---|
|
Simple class name of the exception, if one is present. |
|
Logging level of the event |
|
Name of the logger |
|
Marker associated with the log event, if one is present. |
|
Formatted |
|
Thread id associated with the log event |
|
Name of the thread associated with the log event |
|
UNIX timestamp in milliseconds of the log event |
Don’t use See Lazy lookups and pattern converters for more information. |
Java Lookup
Context | global |
---|---|
Syntax |
where |
The Java Lookup allows retrieving information about the Java environment the application is using. The following keys are supported
Key | Description | Example |
---|---|---|
|
Short Java version |
|
|
Java runtime version |
|
|
Java VM version |
|
|
OS version |
|
|
System locale and file encoding |
|
|
Hardware information |
|
JNDI Lookup
Context | global |
---|---|
Syntax |
where |
Dependency |
|
You need to enable the JNDI lookup explicitly by setting the
|
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. |
Additional runtime dependencies are required for using JNDI Lookup:
-
Maven
-
Gradle
We assume you use log4j-bom
for dependency management.
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jndi</artifactId>
<scope>runtime</scope>
</dependency>
We assume you use log4j-bom
for dependency management.
runtimeOnly 'org.apache.logging.log4j:log4j-jndi'
Configuration Location Lookup
Context | global |
---|---|
Syntax |
where |
The Configuration Location Lookup supports two keys:
Key | Description |
---|---|
|
Returns the location of the configuration file as an absolute file path or URI. |
|
Returns the location of the folder containing the configuration file as an absolute file path or URI. |
Lower Lookup
Context | global |
---|---|
Syntax |
where |
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 |
wherre |
This lookup requires a setup step:
your application needs to call
|
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 followsfoo
in the argument array is returned.
|
|
|
|
|
|
|
|
|
|
|
|
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 |
where |
The Map Lookup retrieves the value assigned to the given key in a
MapMessage
.
Don’t use See Lazy lookups and pattern converters for more information. |
Marker Lookup
Context | global or log event |
---|---|
Syntax |
where |
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 namedkey
ornull
otherwise. For example:${marker:AUDIT:-NO_AUDIT}
will expand to
AUDIT
if a marker with that name exists orNO_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.
Structured Data Lookup
Context | log event |
---|---|
Syntax |
where |
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:
Key | RFC5424 field | Description |
---|---|---|
|
The
|
|
|
The
|
Except See Lazy lookups and pattern converters for more information. |
System Properties Lookup
Context | global |
---|---|
Syntax |
where |
The System Properties Lookup retrieves the value of the Java system property associated with the key.
Upper Lookup
Context | global |
---|---|
Syntax |
where |
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 |
where |
Dependency |
|
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:
Key | Description |
---|---|
|
Returns the |
|
The context path of the web application |
|
The first token in the context path of the web application splitting on "/" characters. |
|
Value of the |
|
Gets the major version of the Servlet specification that the application represented by this ServletContext is based on. |
|
Gets the minor version of the Servlet specification that the application represented by this ServletContext is based on. |
|
Value of the |
|
Returns the ServletContext initialization parameter with the specified |
|
Returns the major version of the Servlet API that this servlet container supports. |
|
Returns the minor version of the Servlet API that this servlet container supports. |
|
Value of the |
|
HTTP request method. |
|
Value of the |
|
Servlet request principal. |
|
Servlet request remote address. |
|
Servlet request remote host. |
|
Servlet request remote port. |
|
Servlet request URI. |
|
Servlet request URL. |
|
Returns the result of calling getRealPath with a value of "/". |
|
Returns the name and version of the servlet container on which the servlet is running. |
|
Returns the name of the web application as defined in the display-name element of the deployment descriptor |
|
Value of the |
|
Servlet session id. |
|
Return the first of |
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
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-jakarta-web</artifactId>
<version>3.0.0-alpha1</version>
<scope>runtime</scope>
</dependency>
runtimeOnly 'org.apache.logging.log4j:log4j-jakarta-web:3.0.0-alpha1'
Third-party lookups
The following additional lookups are available from third-party vendors:
Kubernetes Lookup
Syntax |
|
---|---|
Dependency |
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 |
|
---|---|
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.
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 make it possible for extensible components to receive feature implementations without any explicit links in between. 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 availableStrLookup
plugins -
The
category
attribute is set toStrLookup.CATEGORY
You can check out the following files for examples:
-
LowerLookup.java
– Lower Lookup lower-cases its input -
EventLookup.java
– Event Lookup extracts specified fields from the effectiveLogEvent
in the context