Configuration file

Using a configuration file is the most popular and recommended approach for configuring Log4j Core. In this page we will examine the composition of a configuration file and how Log4j Core uses it.

If you are looking for a quick start on using Log4j in your application or library, please refer to Getting started instead.

Configuration file location

Upon initialization of a new logger context, the anchor of the logging implementation, Log4j Core assigns it a context name and scans the following classpath locations for a configuration file in following order:

  1. Files named log4j2-test<contextName>.<extension>

  2. Files named log4j2-test.<extension>

  3. Files named log4j2<contextName>.<extension>

  4. Files named log4j2.<extension>

The <contextName> and <extension> placeholders above have the following meaning

<contextName>

A name derived from the runtime environment:

  • For standalone Java SE applications, it is a random identifier.

  • For web applications, it is an identifier derived from the application descriptor. See Log4j Web application configuration for details.

<extension>

A file extension supported by a ConfigurationFactory. The order in which an extension will be searched for first depends on the order of the associated ConfigurationFactory. See Predefined ConfigurationFactory plugins for details.

If no configuration file is found, Log4j Core uses the DefaultConfiguration and the status logger prints a warning. The default configuration prints all messages less severe than log4j2.level to the console.

You can override the location of the configuration file using the log4j2.configurationFile system property. In such a case, Log4j Core will guess the configuration file format from the provided file name, or use the default configuration factory if the extension is unknown.

There are certain best-practices we strongly recommend you to adapt in your Log4j configuration:

  • Files prefixed by log4j2-test should only be used on the test classpath.

  • If you are developing an application, don’t use multiple Log4j configuration files with same name, but different extensions. That is, don’t provide both log4j2.xml and log4j2.json files.

  • If you are developing a library, only add configuration files to your test classpath.

Predefined ConfigurationFactory plugins

Log4j Core uses plugins extending from ConfigurationFactory to determine which configuration file extensions are supported, in which order, and how to read them. How this works under the hood and how you can introduce your custom implementations is explained in Extending ConfigurationFactory plugins.

Table 1. Supported configuration file formats by predefined ConfigurationFactory plugins
File format Extension Order

XML

xml

5

JSON

json, jsn

6

YAML

yaml, yml

7

Properties

properties

8

Note that ConfigurationFactory plugins will be employed in descending order. That is, for instance, XML file format will be checked last, as a fallback.

Some ConfigurationFactory plugins require additional dependencies on the classpath:

  • log4j2.xml

  • log4j2.json

  • log4j2.yaml

  • log4j2.properties

JPMS users need to add:

module foo.bar {
    requires java.xml;
}

to their module-info.java descriptor.

  • Maven

  • Gradle

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.18.2</version>
    <scope>runtime</scope>
</dependency>
runtimeOnly 'com.fasterxml.jackson.core:jackson-databind:2.18.2'
  • Maven

  • Gradle

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.18.2</version>
    <scope>runtime</scope>
</dependency>
runtimeOnly 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.2'

No dependency required.

Syntax

Starting with Log4j 2, the configuration file syntax has been considered part of the public API and has remained stable across significant version upgrades.

The syntax of the configuration file changed between Log4j 1 and Log4j 2. Files in the Log4j 1 syntax are ignored by default. To enable partial support for old configuration syntax, see configuration compatibility.

The Log4j runtime is composed of plugins, which are like beans in the Spring Framework and Java EE. Appenders, layouts, filters, configuration loaders, and similar components are all accessed as plugins.

All configuration files are represented internally as a tree of Nodes, which is translated into a tree of Log4j plugins. The tree’s root creates a Configuration object.

A node is a relatively simple structure representing a single Log4j plugin (see Plugin reference for a complete list), such as an appender, layout, or logger configuration.

Each node has:

  • a set of simple string key-value pairs called attributes. Attributes are matched by name against the list of available configuration options of a Log4j plugin.

  • The plugin type attribute specifies the kind of Log4j plugin we want to instantiate.

  • A set of child nodes called nested elements. They are matched by type against the list of nested components a plugin accepts.

Log4j maps the concepts above to the specifics of the configuration format as follows:

  • XML

  • JSON

  • YAML

  • Properties

Since XML was the original configuration format developed, the mapping from configuration nodes and XML elements is trivial:

  • Each configuration node is represented by an XML element.

  • Each configuration attribute is represented by an XML attribute.

  • The plugin type of a node is equal to the name of the XML tag.

  • Each configuration nested element is represented by a nested XML element.

    There is an alternative XML configuration format called "XML strict format" that is activated by setting the strict attribute of the main <Configuration> element to true. It allows users to use any tag names as long as they provide the plugin type using a type property.

    The XML strict format was conceived as a simplified XML format that can be validated by an XML schema but has fallen into disuse: nowadays, the automatically generated schemas published at https://logging.apache.org/xml/ns/ offer a better alternative and allow users to use a more concise syntax.

In the JSON configuration format:

  • Each configuration node is represented by a JSON object,

  • JSON properties of type string, number, or boolean are mapped to node attributes.

  • JSON properties of type object or array represent nested configuration elements.

  • The plugin type of a JSON object is given by:

    • the value of the type key, if present,

    • or the key associated with the JSON object otherwise.

    • If the JSON object representing the node is part of an array, the key associated with the JSON array is used.

If you need to specify multiple plugins of the same type, you can use JSON arrays. The snippet below represents two plugins of type File.

{
  "File": [
    {
      "name": "file1"
    },
    {
      "name": "file2"
    }
  ]
}

In the YAML configuration format:

  • A YAML mapping represents each configuration node,

  • YAML properties of scalar type are mapped to node attributes.

  • YAML properties of collection type are used to represent nested configuration elements.

  • The plugin type of a YAML mapping is given by:

    • the value of the type key, if present,

    • or the key associated with the YAML mapping otherwise.

    • If the YAML mapping representing the node is part of a YAML block sequence, the key associated with the YAML sequence is used.

If you need to specify multiple plugins of the same type, you can use YAML block sequences. The snippet below represents two plugins of type File.

File:
  - name: file1
  - name: file2

In the Java properties configuration format:

  • Properties that share a common prefix (e.g., appender.foo) are mapped to a subtree of the configuration node tree.

  • Configuration attributes are specified by appending the property’s name (e.g., name) to the prefix of the node, separated by a dot (e.g., appender.foo.name).

  • The plugin type must be specified as an attribute named type.

  • Nested elements are created by:

    • Choosing an arbitrary id for the nested component (e.g., <0>)

    • Appending the id to the prefix of the parent component (e.g., appender.foo.<0>)

    • Specifying the type of the nested plugin by assigning a type attribute (e.g., appender.foo.<0>.type)

Nested components use the assigned ID for sorting purposes only.

See also Format specific notes for exceptions to the rules above.

Main configuration elements

Log4j Core’s logging pipeline is quite complex (see Architecture), but most users only require these elements:

Loggers

Loggers are the entry point of the logging pipeline, which is directly used in the code. Their configuration must specify which level of messages they log and to which appenders they send the messages. We will cover them while configuring loggers.

Appenders

Appenders are the exit point of the logging pipeline. They decide which resource (console, file, database, or similar) the log event is sent to. In the examples of this chapter, we will only use the console appender and the file appender.

Layouts

Layouts tell appenders how to format the log event: text, JSON, XML, or similar. In the examples of this chapter, we will only use Pattern Layout and JSON Template Layout.

A moderately complex configuration might look like this:

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<?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">
  <Appenders>
    <Console name="CONSOLE"> (1)
      <PatternLayout pattern="%p - %m%n"/>
    </Console>
    <File name="MAIN" fileName="logs/main.log"> (2)
      <JsonTemplateLayout/>
    </File>
    <File name="DEBUG_LOG" fileName="logs/debug.log"> (3)
      <PatternLayout pattern="%d [%t] %p %c - %m%n"/>
    </File>
  </Appenders>
  <Loggers>
    <Root level="INFO"> (4)
      <AppenderRef ref="CONSOLE" level="WARN"/>
      <AppenderRef ref="MAIN"/>
    </Root>
    <Logger name="org.example" level="DEBUG"> (5)
      <AppenderRef ref="DEBUG_LOG"/>
    </Logger>
  </Loggers>
</Configuration>
Snippet from an example log4j2.json
{
  "Configuration": {
    "Appenders": {
      "Console": { (1)
        "name": "CONSOLE",
        "PatternLayout": {
          "pattern": "%p - %m%n"
        }
      },
      "File": [
        { (2)
          "name": "MAIN",
          "fileName": "logs/main.log",
          "JsonTemplateLayout": {}
        },
        { (3)
          "name": "DEBUG_LOG",
          "fileName": "logs/debug.log",
          "PatternLayout": {
            "pattern": "%d [%t] %p %c - %m%n"
          }
        }
      ]
    },
    "Loggers": {
      "Root": { (4)
        "level": "INFO",
        "AppenderRef": [
          {
            "ref": "CONSOLE",
            "level": "WARN"
          },
          {
            "ref": "MAIN"
          }
        ]
      },
      "Logger": { (5)
        "name": "org.example",
        "level": "DEBUG",
        "AppenderRef": {
          "ref": "DEBUG_LOG"
        }
      }
    }
  }
}
Snippet from an example log4j2.yaml
Configuration:
  Appenders:
    Console: (1)
      name: "CONSOLE"
      PatternLayout:
        pattern: "%p - %m%n"
    File:
      - name: "MAIN" (2)
        fileName: "logs/main.log"
        JsonTemplateLayout: {}
      - name: "DEBUG_LOG" (3)
        fileName: "logs/debug.log"
        PatternLayout:
          pattern: "%d [%t] %p %c - %m%n"
  Loggers:
    Root: (4)
      level: "INFO"
      AppenderRef:
        - ref: "CONSOLE"
          level: "WARN"
        - ref: "MAIN"
    Logger: (5)
      name: "org.example"
      level: "DEBUG"
      AppenderRef:
        ref: "DEBUG_LOG"
Snippet from an example log4j2.properties
appender.0.type = Console (1)
appender.0.name = CONSOLE
appender.0.layout.type = PatternLayout
appender.0.layout.pattern = %p - %m%n

appender.1.type = File (2)
appender.1.name = MAIN
appender.1.fileName = logs/main.log
appender.1.layout.type = JsonTemplateLayout

appender.2.type = File (3)
appender.2.name = DEBUG_LOG
appender.2.fileName = logs/debug.log
appender.2.layout.type = PatternLayout
appender.2.layout.pattern = %d [%t] %p %c - %m%n

rootLogger.level = INFO (4)
rootLogger.appenderRef.0.ref = CONSOLE
rootLogger.appenderRef.0.level = WARN
rootLogger.appenderRef.1.ref = MAIN

logger.0.name = org.example (5)
logger.0.level = DEBUG
logger.0.appenderRef.0.ref = DEBUG_LOG
1 Configures a console appender named CONSOLE with a pattern layout.
2 Configures a file appender named MAIN with a JSON template layout.
3 Configures a file appender named DEBUG_LOG with a pattern layout.
4 Configures the root logger at level INFO and connects it to the CONSOLE and MAIN appenders. The CONSOLE appender will only log messages at least as severe as WARN.
5 Configures a logger named "org.example" at level DEBUG and connects it to the DEBUG_LOG appender. The logger is configured to forward messages to its parent (the root appender).

Using the above configuration, the list of appenders that will be used for each log event depends only on the level of the event and the name of the logger, as in the table below:

Logger name Log event level Appenders

org.example.foo

WARN

CONSOLE, MAIN, DEBUG_LOG

org.example.foo

DEBUG

MAIN, DEBUG_LOG

org.example.foo

TRACE

none

com.example

WARN

CONSOLE, MAIN

com.example

INFO

MAIN

com.example

DEBUG

none

Additional configuration elements

A Log4j Core configuration file can also contain these configuration elements:

CustomLevels

Log4j allows the configuration of custom log-level names.

Filters

Users can add Components to loggers, appender references, appenders, or the global configuration object to provide additional filtering of log events.

See Filter configuration for details.

Properties

Represent a set of reusable configuration values for property substitution.

See Property substitution for details.

Scripts

Scripts are a container for JSR 223 scripts that users can use in other Log4j components.

For details, see Scripts configuration.

Global configuration attributes

The main Configuration element has a set of attributes that can be used to tune how the configuration file is used. The principal attributes are listed below. See Plugin reference for a complete list.

monitorInterval

Type

int

Default value

0

Determines the polling interval used by Log4j to check for changes to the configuration file. If a change in the configuration file is detected, Log4j automatically reconfigures the logger context. If set to 0, polling is disabled.

Log4j Core is designed with reliability in mind, which implies that the reconfiguration process can not lose any log event. In order to achieve this Log4j does not stop any appender until the new Configuration is active and reuses resources that are present in both the old and the new Configuration.

In order to guarantee reliability, Log4j may ignore the changes to some appender options, if they would cause log event loss. For example, changing the append option of a file appender, without changing the fileName option is not possible, since it would require closing the underlying file and reopening it with different options. Between the two operations log events might be lost.

status

Type

LEVEL

Status

DEPRECATED

Default value (since 2.24.0)

log4j2.statusLoggerLevel

Default value (before 2.24.0)

value of log4j2.defaultStatusLevel

Overrides the logging level of Status Logger.

Since version 2.24.0, this attribute is deprecated and should be replaced with the log4j2.statusLoggerLevel configuration property instead.

Loggers

Log4j 2 contains multiple types of logger configurations that can be added to the Loggers element of the configuration:

Root

is the logger that receives all events that do not have a more specific logger defined.

See also Plugin reference.

AsyncRoot

is an alternative implementation of the root logger used in the mixed synchronous and asynchronous mode.

See also Plugin reference.

Logger

the most common logger kind, which collects log events from itself and all the children loggers, which do not have an explicit configuration (see logger hierarchy).

See also Plugin Reference.

AsyncLogger

the equivalent of Logger, used in the mixed synchronous and asynchronous mode.

See also Plugin Reference.

There must be at least a Root or AsyncRoot element in every configuration file. Other logger configurations are optional.

Every Logger in your application is assigned to one of these logger configurations (see architecture), which determines the events that will be logged and those that won’t.

Let’s start with an example of logger configuration:

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<Loggers>
  <Root level="INFO"> (1)
    <AppenderRef ref="APPENDER1"/>
  </Root>
  <Logger name="org.example.no_additivity" additivity="false"> (2)
    <AppenderRef ref="APPENDER2"/>
  </Logger>
  <Logger name="org.example.no_location" includeLocation="false"> (3)
    <AppenderRef ref="APPENDER3"/>
  </Logger>
  <Logger name="org.example.level" level="DEBUG"> (4)
    <AppenderRef ref="APPENDER4"/>
  </Logger>
</Loggers>
Snippet from an example log4j2.json
"Loggers": {
  "Root": { (1)
    "level": "INFO",
    "AppenderRef": {
      "ref": "APPENDER1"
    }
  },
  "Logger": [
    { (2)
      "name": "org.example.no_additivity",
      "additivity": false,
      "AppenderRef": {
        "ref": "APPENDER2"
      }
    },
    { (3)
      "name": "org.example.no_location",
      "includeLocation": false,
      "AppenderRef": {
        "ref": "APPENDER3"
      }
    },
    { (4)
      "name": "org.example.level",
      "level": "DEBUG",
      "AppenderRef": {
        "ref": "APPENDER4"
      }
    }
  ]
}
Snippet from an example log4j2.yaml
Loggers:
  Root: (1)
    level: "INFO"
    AppenderRef:
      ref: "APPENDER1"
  Logger:
    - name: "org.example.no_additivity" (2)
      additivity: false
      AppenderRef:
        ref: "APPENDER2"
    - name: "org.example.no_location" (3)
      includeLocation: false
      AppenderRef:
        ref: "APPENDER3"
    - name: "org.example.level" (4)
      level: "DEBUG"
      AppenderRef:
        ref: "APPENDER4"
Snippet from an example log4j2.properties
rootLogger.level = INFO (1)
rootLogger.appenderRef.0.ref = APPENDER1

logger.0.name = org.example.no_additivity (2)
logger.0.additivity = false
logger.0.appenderRef.0.ref = APPENDER2

logger.1.name = org.example.no_location (3)
logger.1.includeLocation = false
logger.1.appenderRef.0.ref = APPENDER3

logger.2.name = org.example.level (4)
logger.2.level = DEBUG
logger.2.appenderRef.0.ref = APPENDER4

In the example above, we have four logger configurations. They differ from each other regarding the level of log messages that they allow, whether location information will be printed, and which appenders will be used. The table below summarizes the effects of each logger configuration:

Table 2. Logger configurations

Logger name

Level

Additivity

Includes location

Appenders used

1

empty

INFO

N/A

default

APPENDER1

2

org.example.no_additivity

INFO

(inherited)

false

default

APPENDER2

3

org.example.no_location

INFO

(inherited)

true

false

APPENDER1 and APPENDER3

4

org.example.level

DEBUG

true

default

APPENDER1 and APPENDER4

In the following part of this section, we explain in detail all the available options for logger configurations:

name

Type

String

Applies to

Logger and AsyncLogger

Specifies the name of the logger configuration.

Since loggers are usually named using fully qualified class names, this value usually contains the fully qualified name of a class or a package.

additivity

Type

boolean

Default value

true

Applies to

Logger and AsyncLogger

If true (default), all the messages this logger receives will also be transmitted to its parent logger).

level

Type

Level

Default value

It specifies the level threshold that a log event must have to be logged. Log events that are less severe than this setting will be filtered out.

See also Filters if you require additional filtering.

includeLocation

Type

boolean

Default value

  • false, if an asynchronous ContextSelector is used.

  • Otherwise,

    • true for Root and Logger,

    • false for AsyncRoot and AsyncLogger.

See log4j2.contextSelector for more details.

Specifies whether Log4j is allowed to compute location information. If set to false, Log4j will not attempt to infer the location of the logging call unless said location was provided explicitly using one of the available LogBuilder#withLocation() methods.

See Location information for more details.

Appender references

Loggers use appender references to list the appenders to deliver log events.

See Appender references below for more details.

Additional context properties

Loggers can emit additional context data that will be integrated with other context data sources such as ThreadContext.

The value of each property is subject to property substitution twice:

Therefore, if you wish to insert a value that changes in time, you must double the $ sign, as shown in the example below.

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<Root>
  <Property name="client.address" value="$${web:request.remoteAddress}"/>
</Root>
<Logger name="org.hibernate">
  <Property name="subsystem" value="Database"/>
</Logger>
<Logger name="io.netty">
  <Property name="subsystem" value="Networking"/>
</Logger>
Snippet from an example log4j2.json
"Root": {
  "Property": {
    "name": "client.address",
    "value": "$${web:request.remoteAddress}"
  }
},
"Logger": [
  {
    "name": "org.hibernate",
    "Property": {
      "subsystem": "Database"
    }
  },
  {
    "name": "io.netty",
    "Property": {
      "subsystem": "Networking"
    }
  }
]
Snippet from an example log4j2.yaml
Root:
  Property:
    name: "client.address"
    value: "$${web:request.remoteAddress}"
Logger:
  - name: "org.hibernate"
    Property:
      name: "subsystem"
      value: "Database"
  - name: "io.netty"
    Property:
      name: "subsystem"
      value: "Networking"
Snippet from an example log4j2.properties
rootLogger.property.type = Property
rootLogger.property.name = client.address
rootLogger.property.value = $${web:request.remoteAddress}

logger.0.name = org.hibernate
logger.0.property.type = Property
logger.0.property.name = subsystem
logger.0.property.value = Database

logger.1.name = io.netty
logger.1.property.type = Property
logger.1.property.name = subsystem
logger.1.property.value = Networking

Filters

See Filters for additional filtering capabilities that can be applied to a logger configuration.

Appender references

Many Log4j components, such as loggers, use appender references to designate which appenders will be used to deliver their events.

Unlike in Log4j 1, where appender references were simple pointers, in Log4j 2, they have additional filtering capabilities.

Appender references can have the following configuration attributes and elements:

ref

Type

String

Specifies the name of the appender to use.

level

Type

Level

It specifies the level threshold that a log event must have to be logged. Log events that are less severe than this setting will be filtered out.

Filters

See Filters for additional filtering capabilities that can be applied to a logger configuration.

Property substitution

Log4j provides a simple and extensible mechanism to reuse values in the configuration file using ${name} expressions, such as those used in Bash, Ant or Maven.

Reusable configuration values can be added directly to a configuration file by using a Properties component.

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<?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>
    <Property name="log.dir" value="/var/log"/>
  </Properties>
Snippet from an example log4j2.json
{
  "Configuration": {
    "Properties": {
      "Property": [
        {
          "name": "log.dir",
          "value": "/var/log"
        },
        {
          "name": "log.file",
          "value": "${log.dir}/app.log"
        }
      ]
    }
Snippet from an example log4j2.yaml
Configuration:
  Properties:
    Property:
      - name: "log.dir"
        value: "/var/log"
      - name: "log.file"
        value: "${log.dir}/app.log"
Snippet from an example log4j2.properties
property.log.dir = /var/log
property.log.file = ${log.dir}/app.log

An extensible lookup mechanism can also provide reusable configuration values. See Lookups for more information.

Configuration values defined this way can be used in any configuration attribute by using the following expansion rules:

${name}

If the Properties element of the configuration file has a property named name, its value is substituted. Otherwise, the placeholder is not expanded.

If name contains a : character, it is expanded as in the rule below.

${lookup:name}

If both these conditions hold:

  • lookup is a prefix assigned to a Lookup,

  • the lookup has a value assigned to name,

the value for the lookup is substituted. Otherwise, the expansion of ${name} is substituted.

If name starts with a hyphen - (e.g. -variable), it must be escaped with a backslash \ (e.g. \-variable).

The most common lookup prefixes are:

The above expansions have a version with an additional default value that is expanded if the lookup fails:

${name:-default}

If the Properties element of the configuration file has a property named name, its value is substituted. Otherwise, the expansion of default is substituted.

If name contains a : character, it is expanded as in the rule below.

${lookup:name:-default}

If both these conditions hold:

  • lookup is a prefix assigned to a Lookup,

  • the lookup has a value assigned to name,

the value for the lookup is substituted. Otherwise, the expansion of ${name:-default} is substituted.

To prevent the expansion of one of the expressions above, the initial $ must be doubled as $$.

The same rule applies to the name parameter: if it contains a ${ sequence, it must be escaped as $${.

Example 1. Property substitution example

If your configuration file contains the following definitions:

  • XML

  • JSON

  • YAML

  • Properties

<Properties>
  <Property name="FOO" value="foo"/>
  <Property name="BAR" value="bar"/>
</Properties>
{
  "Properties": {
    "Property": [
      {
        "name": "FOO",
        "value": "foo"
      },
      {
        "name": "BAR",
        "value": "bar"
      }
    ]
  }
}
Properties:
  Property:
    - name: "FOO"
      value: "foo"
    - name: "BAR"
      value: "bar"
property.FOO = foo
property.BAR = bar

and the OS environment variable FOO has a value of environment, Log4j will evaluate the expression as follows

Expression Value

${FOO}

foo

${BAZ}

${BAZ}

${BAR:-${FOO}}

bar

${BAZ:-${FOO}}

foo

${env:FOO}

environment

${env:BAR}

bar

${env:BAZ}

${BAZ}

${env:BAR:-${FOO}}

bar

${env:BAZ:-${FOO}}

foo

For security reasons, if the expansion of a ${…​} expression contains other expressions, these will not be expanded.

Properties defined in the Properties container, however, can depend on each other. If your configuration contains, for example:

  • XML

  • JSON

  • YAML

  • Properties

<Properties>
  <Property name="logging.file" value="${logging.dir}/app.log"/>
  <Property name="logging.dir" value="${env:APP_BASE}/logs"/>
  <Property name="APP_BASE" value="."/>
</Properties>
{
  "Properties": {
    "Property": [
      {
        "name": "logging.file",
        "value": "${logging.path}/app.log"
      },
      {
        "name": "logging.dir",
        "value": "${env:APP_BASE}/logs"
      },
      {
        "name": "APP_BASE",
        "value": "."
      }
    ]
  }
}
Properties:
  Property:
    - name: "logging.file"
      value: "${logging.dir}/app.log"
    - name: "logging.dir"
      value: "${env:APP_BASE}/logs"
    - name: "APP_BASE"
      value: "."
property.logging.file = ${logging.dir}/app.log
property.logging.dir = ${env:APP_BASE}/logs
property.APP_BASE = .

the logging.dir property will be expanded before the logging.file property, and the expanded value will be substituted in ${logging.dir}/app.log. Therefore, the value of the logging.file property will be:

  • ./logs/app.log if the environment variable APP_BASE is not defined,

  • /var/lib/app/logs/app.log if the environment variable APP_BASE has a value of /var/lib/app.

Runtime property substitution

For most attributes, property substitution is performed only once at configuration time, but there are exceptions to this rule: some attributes are also evaluated when a component-specific event occurs.

In this case:

  • If you want property substitution to happen at configuration time, use one dollar sign, e.g., ${date:HH:mm:ss}.

  • If you want property substitution to happen at runtime, you use two dollar signs, e.g., $${date:HH:mm:ss}

The list of attributes that support runtime property substitution is:

Certain lookups might behave differently when they are expanded at runtime. See lookup evaluation contexts for details.

The Route component of the Routing Appender is a different case altogether. The attributes of its children are expanded at runtime, but are not expanded at configuration time.

Inside the Route component you should not use escaped $${...} expressions, but only unescaped ${...} expressions.

The complete spectrum of behaviors concerning runtime property substitution is given by the routing appender example below:

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<Routing name="ROUTING">
  <Routes pattern="$${sd:type}"> (1)
    <Route>
      <File name="ROUTING-${sd:type}"
            fileName="logs/${sd:type}.log"> (2)
        <JsonTemplateLayout>
          <EventTemplateAdditionalField name="type"
                                        value="${sd:type}"/> (2)
        </JsonTemplateLayout>
      </File>
    </Route>
  </Routes>
</Routing>
Snippet from an example log4j2.json
"Routing": {
  "name": "ROUTING",
  "Routes": {
    "pattern": "$${sd:type}", (1)
    "Route": {
      "File": {
        "name": "ROUTING-${sd:type}", (2)
        "fileName": "logs/${sd:type}.log", (2)
        "JsonTemplateLayout": {
          "EventTemplateAdditionalField": {
            "name": "type",
            "value": "${sd:type}" (2)
          }
        }
      }
    }
  }
}
Snippet from an example log4j2.yaml
Routing:
  name: "ROUTING"
  Routes:
    pattern: "$${sd:type}" (1)
    Route:
      File:
        name: "ROUTING-${sd:type}" (2)
        fileName: "logs/${sd:type}.log" (2)
        JsonTemplateLayout:
          EventTemplateAdditionalField:
            name: "type"
            value: "${sd:type}" (2)
Snippet from an example log4j2.properties
appender.0.type = Routing
appender.0.name = ROUTING

appender.0.routes.type = Routes
appender.0.routes.pattern = $${sd:type} (1)

appender.0.routes.route.type = Route

appender.0.routes.route.file.type = File
appender.0.routes.route.file.name = ROUTING-${sd:type} (2)
appender.0.routes.route.file.fileName = logs/${sd:type}.log (2)
appender.0.routes.route.file.layout.type = JsonTemplateLayout
appender.0.routes.route.file.layout.field.type = EventTemplateAdditionalField
appender.0.routes.route.file.layout.field.name = type
appender.0.routes.route.file.layout.field.value = ${sd:type} (2)
1 The pattern attribute is evaluated at configuration time, and also each time a log event is routed. Therefore, the dollar $ sign needs to be escaped.
2 All the attributes of children of the Route element have a deferred evaluation. Therefore, they need only one $ sign.

Arbiters

While property substitution allows using the same configuration file in multiple deployment environments, sometimes changing the values of configuration attributes is not enough.

Arbiters are to configuration elements what property substitution is for configuration attributes: they allow to conditionally add a subtree of configuration elements to a configuration file.

Arbiters may occur anywhere an element is allowed in the configuration and can be nested. So, an Arbiter could encapsulate something as simple as a single property declaration or a whole set of appenders, loggers, or other arbiters. The child elements of an arbiter must be valid elements for whatever element is the parent of the arbiter.

For a complete list of available arbiters, see plugin reference. In the examples below, we’ll use the DefaultArbiter, Select and SystemPropertyArbiter.

For example, you might want to use a different layout in a production and development environment:

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<Appenders>
  <File name="MAIN" fileName="logs/app.log">
    <SystemPropertyArbiter propertyName="env" propertyValue="dev"> (1)
      <PatternLayout pattern="%d [%t] %p %c - %m%n"/>
    </SystemPropertyArbiter>
    <SystemPropertyArbiter propertyName="env" propertyValue="prod"> (2)
      <JsonTemplateLayout/>
    </SystemPropertyArbiter>
  </File>
</Appenders>
Snippet from an example log4j2.json
"Appenders": {
  "File": {
    "name": "MAIN",
    "fileName": "logs/app.log",
    "SystemPropertyArbiter": [
      (1)
      {
        "propertyName": "env",
        "propertyValue": "dev",
        "PatternLayout": {
          "pattern": "%d [%t] %p %c - %m%n"
        }
      },
      (2)
      {
        "propertyName": "env",
        "propertyValue": "prod",
        "JsonTemplateLayout": {}
      }
    ]
  }
},
Snippet from an example log4j2.yaml
Appenders:
  File:
    name: "MAIN"
    fileName: "logs/app.log"
    SystemPropertyArbiter:
      - propertyName: "env" (1)
        propertyValue: "dev"
        PatternLayout:
          pattern: "%d [%t] %p %c - %m%n"
      - propertyName: "env" (2)
        propertyValue: "prod"
        JsonTemplateLayout: {}
appender.0.type = File
appender.0.name = MAIN
appender.0.fileName = logs/app.log

appender.0.arbiter[0].type = SystemPropertyArbiter (1)
appender.0.arbiter[0].propertyName = env
appender.0.arbiter[0].propertyValue = dev
appender.0.arbiter[0].layout.type = PatternLayout
appender.0.arbiter[0].layout.pattern = %d [%t] %p %c - %m%n

appender.0.arbiter[1].type = SystemPropertyArbiter (2)
appender.0.arbiter[1].propertyName = env
appender.0.arbiter[1].propertyValue = prod
appender.0.arbiter[1].layout.type = JsonTemplateLayout

rootLogger.level = INFO
rootLogger.appenderRef.0.ref = MAIN
1 If the Java system property env has a value of dev, a pattern layout will be used.
2 If the Java system property env has a value of prod, a JSON template layout will be used.

The above example has a problem: if the Java system property env has a value different from dev or prod, the appender will have no layout.

This is a case when the Select plugin is useful: this configuration element contains a list of arbiters and a DefaultArbiter element. If none of the arbiters match, the configuration from the DefaultArbiter element will be used:

  • XML

  • JSON

  • YAML

  • Properties

Snippet from an example log4j2.xml
<Select>
  <SystemPropertyArbiter propertyName="env" propertyValue="dev"> (1)
    <PatternLayout/>
  </SystemPropertyArbiter>
  <DefaultArbiter> (2)
    <JsonTemplateLayout/>
  </DefaultArbiter>
</Select>
Snippet from an example log4j2.json
"Select": {
  "SystemPropertyArbiter": { (1)
    "propertyName": "env",
    "propertyValue": "dev",
    "PatternLayout": {}
  },
  "DefaultArbiter": { (2)
    "JsonTemplateLayout": {}
  }
}
Snippet from an example log4j2.yaml
Select:
  SystemPropertyArbiter: (1)
    propertyName: "env"
    propertyValue: "dev"
    PatternLayout: {}
  DefaultArbiter: (2)
    JsonTemplateLayout: {}
Snippet from an example log4j2.properties
appender.0.select.type = Select

appender.0.select.0.type = SystemPropertyArbiter (1)
appender.0.select.0.propertyName = env
appender.0.select.0.propertyValue = dev
appender.0.select.0.layout.type = PatternLayout

appender.0.select.1.type = DefaultArbiter (2)
appender.0.select.1.layout.type = JsonTemplateLayout
1 If the Java system property env has a value of dev, a Pattern Layout will be used.
2 Otherwise, a JSON Template Layout will be used.

Composite configuration

There are occasions where multiple configurations might need to be combined. For instance,

  • You have a common Log4j Core configuration that should always be present, and an environment-specific one that extends the common one depending on the environment (test, production, etc.) the application is running on.

  • You develop a framework, and it contains a predefined Log4j Core configuration. Yet you want to allow users to extend it whenever necessary.

  • You collect Log4j Core configurations from multiple sources.

You can provide a list of comma-separated file paths or URLs in the log4j2.configurationFile configuration property, where each resource will get read into a Configuration, and then eventually combined into a single one using CompositeConfiguration.

How does CompositeConfiguration work?

CompositeConfiguration merges multiple configurations into a single one using a MergeStrategy, which can be customized using the log4j2.mergeStrategy configuration property. The default merge strategy works as follows:

  • Global configuration attributes in later configurations replace those in previous configurations. The only exception is the monitorInterval attribute: the lowest positive value from all the configuration files will be used.

  • Properties are aggregated. Duplicate properties override those in previous configurations.

  • Filters are aggregated under CompositeFilter, if more than one filter is defined.

  • Scripts are aggregated. Duplicate definitions override those in previous configurations.

  • Appenders are aggregated. Appenders with the same name are overridden by those in later configurations, including all their elements.

  • Loggers are aggregated. Logger attributes are individually merged, and those in later configurations replace duplicates. Appender references on a logger are aggregated, and those in later configurations replace duplicates. The strategy merges filters on loggers using the rule above.

Format specific notes

XML format

Global configuration attributes

The XML format supports the following additional attributes on the Configuration element.

schema

Type

classpath resource

Default value

null

Specifies the path to a classpath resource containing an XML schema.

strict

Type

boolean

Default value

false

If set to true, all configuration files will be checked against the XML schema provided by the schema.

This setting also enables "XML strict mode" and allows one to specify an element’s plugin type through a type attribute instead of the tag name.

XInclude

XML configuration files can include other files with XInclude.

The list of XInclude and XPath features supported depends upon your JAXP implementation.

Here is an example log4j2.xml file that includes two other files:

Snippet from an example log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration xmlns="https://logging.apache.org/xml/ns"
               xmlns:xi="http://www.w3.org/2001/XInclude"
               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>
    <Property name="filename" value="app.log"/>
  </Properties>
  <xi:include href="xinclude-appenders.xml"/>
  <xi:include href="xinclude-loggers.xml"/>
</Configuration>
Snippet from an example xinclude-appenders.xml
<?xml version="1.0" encoding="UTF-8"?>
<Appenders>
  <Console name="CONSOLE">
    <PatternLayout pattern="%d %m%n"/>
  </Console>
  <File name="FILE" fileName="${filename}">
    <PatternLayout pattern="%d %p %C{1.} [%t] %m%n"/>
  </File>
</Appenders>
Snippet from an example xinclude-loggers.xml
<?xml version="1.0" encoding="UTF-8"?>
<Loggers>
  <Logger name="org.example" level="DEBUG" additivity="false">
    <AppenderRef ref="FILE" />
  </Logger>
  <Root level="ERROR">
    <AppenderRef ref="CONSOLE" />
  </Root>
</Loggers>

Java properties format

The Java properties format is not well suited to represent hierarchical structures.

Switch to XML to avoid additional dependencies, or choose YAML for a format similar to Java properties but less verbose.

The Java properties configuration format is the most verbose of the available formats. To make it more usable, a series of exceptions to the rules in Java properties syntax have been introduced over time:

  1. The following direct children of Configuration have predefined prefixes and do not require to specify a type attribute:

  2. Properties that start with property are used for Property substitution. Their syntax is:

    property.<key> = <value>
  3. Properties that start with customLevel are used to define custom levels. Their syntax is:

    customLevel.<name> = <intValue>

    where <name> is the name of the level and <intValue> its numerical value.

  4. The root logger can be configured using properties that start with rootLogger.

  5. A shorthand notation is available that allows users to write:

    rootLogger = INFO, APPENDER

    instead of:

    rootLogger.level = INFO
    rootLogger.appenderRef.0.ref = APPENDER
  6. All the keys of the form logger.<name>.appenderRef.<id>, where <name> and <id> are arbitrary, are considered appender references.

  7. To add a filter to a component use a filter.<id> prefix instead of just <id>.

Extending

Log4j Core uses plugins to inject necessary components while reading a configuration file. In this section, we will explore extension points users can hook into to customize the way Log4j Core reads configuration files.

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 ConfigurationFactory plugins

Under the hood, Log4j Core uses plugins extending from ConfigurationFactory to load configuration files. This procedure can be summarized as follows:

  1. Load plugins which extend from ConfigurationFactory and whose plugin category is set to ConfigurationFactory.CATEGORY

  2. Sort them by @Order annotation (in decreasing value order), if present

  3. Feed found configuration files to ConfigurationFactory instances in order, if the file extension is contained by String[] returned from ConfigurationFactory#getSupportedTypes()

If the log4j2.configurationFactory system property is defined, it will be used before any other factory implementations.

For an example, see JsonConfigurationFactory.java on how Log4j Core implements JSON-formatted configuration file read.

Next to introducing new configuration file formats, ConfigurationFactory can be used for programmatic configuration too.

Plugins represented in a configuration file

As explained in Syntax, a configuration file gets parsed into a tree of plugins. If your plugin needs to be represented in a configuration file element, some extra plugin configuration needs to be administered.