Log4j Users Guide
Log4j Users Guide
Apache Log4j 2
v. 2.17.0
User's Guide
......................................................................................................................................
The Apache Software Foundation 2021-12-17
Table of Contents i
Table of Contents
.......................................................................................................................................
1. Table of Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . i
2. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
3. Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4. Log4j 1.x Migration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
5. API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6. Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7. Web Applications and JSPs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
8. Plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
9. Lookups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
10. Appenders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
11. Layouts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188
12. Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
13. Async Loggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 244
14. Garbage-free Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
15. JMX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
16. Logging Separation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
17. Extending Log4j . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
18. Programmatic Log4j Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
19. Custom Log Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
1 Introduction
.......................................................................................................................................
1.1.1 Introduction
Almost every large application includes its own logging or tracing API. In conformance with this
rule, the E.U. SEMPER project decided to write its own tracing API. This was in early 1996. After
countless enhancements, several incarnations and much work that API has evolved to become log4j,
a popular logging package for Java. The package is distributed under the Apache Software License,
a fully-fledged open source license certified by the open source initiative. The latest log4j version,
including full-source code, class files and documentation can be found at http://logging.apache.org/
log4j/2.x/index.html.
Inserting log statements into code is a low-tech method for debugging it. It may also be the only way
because debuggers are not always available or applicable. This is usually the case for multithreaded
applications and distributed applications at large.
Experience indicates that logging was an important component of the development cycle. It offers
several advantages. It provides precise context about a run of the application. Once inserted into the
code, the generation of logging output requires no human intervention. Moreover, log output can
be saved in persistent medium to be studied at a later time. In addition to its use in the development
cycle, a sufficiently rich logging package can also be viewed as an auditing tool.
As Brian W. Kernighan and Rob Pike put it in their truly excellent book "The Practice of
Programming":
As personal choice, we tend not to use debuggers beyond getting a stack trace or the value of a
variable or two. One reason is that it is easy to get lost in details of complicated data structures and
control flow; we find stepping through a program less productive than thinking harder and adding
output statements and self-checking code at critical places. Clicking over statements takes longer
than scanning the output of judiciously-placed displays. It takes less time to decide where to put print
statements than to single-step to the critical section of code, even assuming we know where that is.
More important, debugging statements stay with the program; debugging sessions are transient.
Logging does have its drawbacks. It can slow down an application. If too verbose, it can cause
scrolling blindness. To alleviate these concerns, log4j is designed to be reliable, fast and extensible.
Since logging is rarely the main focus of an application, the log4j API strives to be simple to
understand and to use.
1.1.2 Log4j 2
Log4j 1.x has been widely adopted and used in many applications. However, through the years
development on it has slowed down. It has become more difficult to maintain due to its need to be
compliant with very old versions of Java and became End of Life in August 2015. Its alternative,
SLF4J/Logback made many needed improvements to the framework. So why bother with Log4j 2?
Here are a few of the reasons.
1. Log4j 2 is designed to be usable as an audit logging framework. Both Log4j 1.x and Logback
will lose events while reconfiguring. Log4j 2 will not. In Logback, exceptions in Appenders are
never visible to the application. In Log4j 2 Appenders can be configured to allow the exception
to percolate to the application.
2. Log4j 2 contains next-generation Asynchronous Loggers based on the LMAX Disruptor library.
In multi-threaded scenarios Asynchronous Loggers have 10 times higher throughput and orders
of magnitude lower latency than Log4j 1.x and Logback.
3. Log4j 2 is garbage free for stand-alone applications, and low garbage for web applications
during steady state logging. This reduces pressure on the garbage collector and can give better
response time performance.
4. Log4j 2 uses a Plugin system that makes it extremely easy to extend the framework by adding
new Appenders, Filters, Layouts, Lookups, and Pattern Converters without requiring any
changes to Log4j.
5. Due to the Plugin system configuration is simpler. Entries in the configuration do not require a
class name to be specified.
6. Support for custom log levels. Custom log levels can be defined in code or in configuration.
7. Support for lambda expressions. Client code running on Java 8 can use lambda expressions to
lazily construct a log message only if the requested log level is enabled. Explicit level checks are
not needed, resulting in cleaner code.
8. Support for Message objects. Messages allow support for interesting and complex constructs
to be passed through the logging system and be efficiently manipulated. Users are free to create
their own Message types and write custom Layouts, Filters and Lookups to manipulate
them.
9. Log4j 1.x supports Filters on Appenders. Logback added TurboFilters to allow filtering of
events before they are processed by a Logger. Log4j 2 supports Filters that can be configured to
process events before they are handled by a Logger, as they are processed by a Logger or on an
Appender.
10.Many Logback Appenders do not accept a Layout and will only send data in a fixed format.
Most Log4j 2 Appenders accept a Layout, allowing the data to be transported in any format
desired.
11.Layouts in Log4j 1.x and Logback return a String. This resulted in the problems discussed at
Logback Encoders. Log4j 2 takes the simpler approach that Layouts always return a byte array.
This has the advantage that it means they can be used in virtually any Appender, not just the ones
that write to an OutputStream.
12.The Syslog Appender supports both TCP and UDP as well as support for the BSD syslog and
the RFC 5424 formats.
13.Log4j 2 takes advantage of Java 5 concurrency support and performs locking at the lowest level
possible. Log4j 1.x has known deadlock issues. Many of these are fixed in Logback but many
Logback classes still require synchronization at a fairly high level.
14.It is an Apache Software Foundation project following the community and support model used
by all ASF projects. If you want to contribute or gain the right to commit changes just follow the
path outlined at Contributing.
2 Architecture
.......................................................................................................................................
2.1 Architecture
Applications using the Log4j 2 API will request a Logger with a specific name from the LogManager.
The LogManager will locate the appropriate LoggerContext and then obtain the Logger from it. If the
Logger must be created it will be associated with the LoggerConfig that contains either a) the same
name as the Logger, b) the name of a parent package, or c) the root LoggerConfig. LoggerConfig
objects are created from Logger declarations in the configuration. The LoggerConfig is associated
with the Appenders that actually deliver the LogEvents.
2.1.1.2 LoggerContext
The LoggerContext acts as the anchor point for the Logging system. However, it is possible to have
multiple active LoggerContexts in an application depending on the circumstances. More details on the
LoggerContext are in the Log Separation section.
2.1.1.3 Configuration
Every LoggerContext has an active Configuration. The Configuration contains all the Appenders,
context-wide Filters, LoggerConfigs and contains the reference to the StrSubstitutor. During
reconfiguration two Configuration objects will exist. Once all Loggers have been redirected to the
new Configuration, the old Configuration will be stopped and discarded.
2.1.1.4 Logger
As stated previously, Loggers are created by calling LogManager.getLogger. The Logger itself
performs no direct actions. It simply has a name and is associated with a LoggerConfig. It extends
AbstractLogger and implements the required methods. As the configuration is modified Loggers may
become associated with a different LoggerConfig, thus causing their behavior to be modified.
2.Retrieving Loggers
Calling the LogManager.getLogger method with the same name will always return a reference to
the exact same Logger object.
For example, in
Logger x = LogManager.getLogger("wombat");
Logger y = LogManager.getLogger("wombat");
class. This is a useful and straightforward method of defining loggers. As the log output bears the
name of the generating Logger, this naming strategy makes it easy to identify the origin of a log
message. However, this is only one possible, albeit common, strategy for naming loggers. Log4j does
not restrict the possible set of loggers. The developer is free to name the loggers as desired.
Since naming Loggers after their owning class is such a common idiom, the convenience method
LogManager.getLogger() is provided to automatically use the calling class's fully qualified class
name as the Logger name.
Nevertheless, naming loggers after the class where they are located seems to be the best strategy
known so far.
2.1.1.5 LoggerConfig
LoggerConfig objects are created when Loggers are declared in the logging configuration. The
LoggerConfig contains a set of Filters that must allow the LogEvent to pass before it will be passed to
any Appenders. It contains references to the set of Appenders that should be used to process the event.
2.Log Levels
LoggerConfigs will be assigned a Log Level. The set of built-in levels includes ALL, TRACE,
DEBUG, INFO, WARN, ERROR, FATAL, and OFF. Log4j 2 also supports custom log levels.
Another mechanism for getting more granularity is to use Markers instead. The OFF and ALL levels
are not intended to be used on calls to the logging API. Specifying OFF in the configuration implies
no logging events should match while specifying ALL would mean all events match, including
custom events. However, OFF can be used on logging API calls in special cases where the event
should always be logged regardless of the configuration. However, it is generally recommended that a
Marker with a corresponding global Marker Filter be used instead.
Log4j 1.x and Logback both have the concept of "Level Inheritance". In Log4j 2, Loggers and
LoggerConfigs are two different objects so this concept is implemented differently. Each Logger
references the appropriate LoggerConfig which in turn can reference its parent, thus achieving the
same effect.
Below are five tables with various assigned level values and the resulting levels that will be associated
with each Logger. Note that in all these cases if the root LoggerConfig is not configured a default
Level will be assigned to it.
Assigned
Logger Name LoggerConfig LoggerConfig Level Logger Level
root root DEBUG DEBUG
X root DEBUG DEBUG
X.Y root DEBUG DEBUG
X.Y.Z root DEBUG DEBUG
Example 1
In example 1 above, only the root logger is configured and has a Log Level. All the other Loggers
reference the root LoggerConfig and use its Level.
Assigned
Logger Name LoggerConfig LoggerConfig Level Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.Y.Z X.Y.Z WARN WARN
Example 2
In example 2, all loggers have a configured LoggerConfig and obtain their Level from it.
Assigned
Logger Name LoggerConfig LoggerConfig Level Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X.Y.Z WARN WARN
Example 3
In example 3, the loggers root, X and X.Y.Z each have a configured LoggerConfig with the same
name. The Logger X.Y does not have a configured LoggerConfig with a matching name so uses the
configuration of LoggerConfig X since that is the LoggerConfig whose name has the longest match to
the start of the Logger's name.
Assigned
Logger Name LoggerConfig LoggerConfig Level level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X ERROR ERROR
X.Y.Z X ERROR ERROR
Example 4
In example 4, the loggers root and X each have a Configured LoggerConfig with the same name.
The loggers X.Y and X.Y.Z do not have configured LoggerConfigs and so get their Level from the
LoggerConfig assigned to them, X, since it is the LoggerConfig whose name has the longest match to
the start of the Logger's name.
Assigned
Logger Name LoggerConfig LoggerConfig Level level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y INFO INFO
X.YZ X ERROR ERROR
Example 5
In example 5, the loggers root. X, and X.Y each have a Configured LoggerConfig with the same
name. The logger X.YZ does not have configured LoggerConfig and so gets its Level from the
LoggerConfig assigned to it, X, since it is the LoggerConfig whose name has the longest match to the
start of the Logger's name. It is not associated with LoggerConfig X.Y since tokens after periods must
match exactly.
Assigned
Logger Name LoggerConfig LoggerConfig Level Level
root root DEBUG DEBUG
X X ERROR ERROR
X.Y X.Y ERROR
X.Y.Z X.Y ERROR
Example 6
In example 6, LoggerConfig X.Y it has no configured level so it inherits its level from LoggerConfig
X. Logger X.Y.Z uses LoggerConfig X.Y since it doesn't have a LoggerConfig with a name that
exactly matches. It too inherits its logging level from LoggerConfig X.
The table below illustrates how Level filtering works. In the table, the vertical header shows the
Level of the LogEvent, while the horizontal header shows the Level associated with the appropriate
LoggerConfig. The intersection identifies whether the LogEvent would be allowed to pass for further
processing (Yes) or discarded (No).
Event LoggerConfig
Level Level
TRACE DEBUG INFO WARN ERROR FATAL OFF
ALL NO NO NO NO NO NO NO
TRACE YES NO NO NO NO NO NO
2.1.1.6 Filter
In addition to the automatic log Level filtering that takes place as described in the previous section,
Log4j provides Filters that can be applied before control is passed to any LoggerConfig, after
control is passed to a LoggerConfig but before calling any Appenders, after control is passed to a
LoggerConfig but before calling a specific Appender, and on each Appender. In a manner very similar
to firewall filters, each Filter can return one of three results, Accept, Deny or Neutral. A response
of Accept means that no other Filters should be called and the event should progress. A response of
Deny means the event should be immediately ignored and control should be returned to the caller. A
response of Neutral indicates the event should be passed to other Filters. If there are no other Filters
the event will be processed.
Although an event may be accepted by a Filter the event still might not be logged. This can happen
when the event is accepted by the pre-LoggerConfig Filter but is then denied by a LoggerConfig filter
or is denied by all Appenders.
2.1.1.7 Appender
The ability to selectively enable or disable logging requests based on their logger is only part of the
picture. Log4j allows logging requests to print to multiple destinations. In log4j speak, an output
destination is called an Appender. Currently, appenders exist for the console, files, remote socket
servers, Apache Flume, JMS, remote UNIX Syslog daemons, and various database APIs. See the
section on Appenders for more details on the various types available. More than one Appender can be
attached to a Logger.
An Appender can be added to a Logger by calling the addLoggerAppender method of the current
Configuration. If a LoggerConfig matching the name of the Logger does not exist, one will be created,
the Appender will be attached to it and then all Loggers will be notified to update their LoggerConfig
references.
Each enabled logging request for a given logger will be forwarded to all the appenders in
that Logger's LoggerConfig as well as the Appenders of the LoggerConfig's parents. In other
words, Appenders are inherited additively from the LoggerConfig hierarchy. For example, if a
console appender is added to the root logger, then all enabled logging requests will at least print
on the console. If in addition a file appender is added to a LoggerConfig, say C, then enabled
logging requests for C and C's children will print in a file and on the console. It is possible to
override this default behavior so that Appender accumulation is no longer additive by setting
additivity="false" on the Logger declaration in the configuration file.
The rules governing appender additivity are summarized below.
Appender Additivity
The output of a log statement of Logger L will go to all the Appenders in the LoggerConfig
associated with L and the ancestors of that LoggerConfig. This is the meaning of the term
"appender additivity".
However, if an ancestor of the LoggerConfig associated with Logger L, say P, has the
additivity flag set to false, then L's output will be directed to all the appenders in L's
LoggerConfig and it's ancestors up to and including P but not the Appenders in any of the
ancestors of P.
Loggers have their additivity flag set to true by default.
The table below shows an example:
2.1.1.8 Layout
More often than not, users wish to customize not only the output destination but also the output
format. This is accomplished by associating a Layout with an Appender. The Layout is responsible
for formatting the LogEvent according to the user's wishes, whereas an appender takes care of sending
the formatted output to its destination. The PatternLayout, part of the standard log4j distribution, lets
the user specify the output format according to conversion patterns similar to the C language printf
function.
For example, the PatternLayout with the conversion pattern "%r [%t] %-5p %c - %m%n" will output
something akin to:
176 [main] INFO org.foo.Bar - Located nearest gas station.
The first field is the number of milliseconds elapsed since the start of the program. The second field
is the thread making the log request. The third field is the level of the log statement. The fourth field
is the name of the logger associated with the log request. The text after the '-' is the message of the
statement.
Log4j comes with many different Layouts for various use cases such as JSON, XML, HTML, and
Syslog (including the new RFC 5424 version). Other appenders such as the database connectors fill in
specified fields instead of a particular textual layout.
Just as importantly, log4j will render the content of the log message according to user specified
criteria. For example, if you frequently need to log Oranges, an object type used in your current
project, then you can create an OrangeMessage that accepts an Orange instance and pass that to Log4j
so that the Orange object can be formatted into an appropriate byte array when required.
1. They must not access methods and classes internal to the Log4j 1.x implementation such as
Appenders, LoggerRepository or Category's callAppenders method.
2. They must not programmatically configure Log4j.
3. They must not configure by calling the classes DOMConfigurator or
PropertyConfigurator.
1. Starting in Log4j 2.1, you can specify a custom ShutdownCallbackRegistry to override the
default JVM shutdown hook strategy.
2. Starting in Log4j 2.6, you can now use
org.apache.logging.log4j.LogManager.shutdown() to initiate shutdown
manually.
7. Calls to org.apache.log4j.Logger.setLevel() or similar methods
are not supported in the API. Applications should remove these. Equivalent
functionality is provided in the Log4j 2 implementation classes, see
org.apache.logging.log4j.core.config.Configurator.setLevel(), but may leave
the application susceptible to changes in Log4j 2 internals.
8. Where appropriate, applications should convert to use parameterized messages instead of String
concatenation.
9. org.apache.log4j.MDC and org.apache.log4j.NDC have been replaced by the Thread
Context.
3.1.4.2 Sample 2 - Simple configuration using a File Appender, XMLLayout and SimpleLayout
Log4j 1.x XML configuration
4 API
.......................................................................................................................................
4.1.1 Overview
The Log4j 2 API provides the interface that applications should code to and provides the adapter
components required for implementers to create a logging implementation. Although Log4j 2 is
broken up between an API and an implementation, the primary purpose of doing so was not to allow
multiple implementations, although that is certainly possible, but to clearly define what classes and
methods are safe to use in "normal" application code.
To use a formatter Logger, you must call one of the LogManager getFormatterLogger methods. The
output for this example shows that Calendar toString() is verbose compared to custom formatting:
2012-12-12 11:56:19,633 [main] DEBUG: User John Smith with birthday java.util.GregorianCalendar[time=?,areFie
2012-12-12 11:56:19,643 [main] DEBUG: User John Smith with birthday 05 23, 1995
2012-12-12 11:56:19,643 [main] DEBUG: Integer.MAX_VALUE = 2,147,483,647
2012-12-12 11:56:19,643 [main] DEBUG: Long.MAX_VALUE = 9,223,372,036,854,775,807
5 Configuration
.......................................................................................................................................
5.1 Configuration
Inserting log requests into the application code requires a fair amount of planning and effort.
Observation shows that approximately 4 percent of code is dedicated to logging. Consequently, even
moderately sized applications will have thousands of logging statements embedded within their code.
Given their number, it becomes imperative to manage these log statements without the need to modify
them manually.
Configuration of Log4j 2 can be accomplished in 1 of 4 ways:
Once the Node tree is created control is delegated to AbstractConfiguration, which convertes the
Nodes into their respective Java objects using Log4j's Plugin system and provides all the common
functionality.
5.1.2 Arbiters
In some situations it is desirable to have a single logging configuration that can be used in any
deployment environment. For example, it may be necessary to have a different default logging level
in production then in development. Another case might be where one type of appender is used when
running natively but another is used when deployed to a docker container. One way to handle that is
to use a tool such as Spring Cloud Config Server that can be environment aware and serve a different
file for each environment. Another option is to include Arbiters in the configuration.
An Arbiter is a Log4j plugin that has the job of determining whether other configured elements
should be included in the generated configuration. While all other "Core" plugins are designed to
execute as part of Log4j's runtime logic Arbiters execute after the Node tree has been constructed but
before the tree is converted to a configuration. An Arbiter is a Node itself which is always removed
from the Node tree before it the tree is processed. All an arbiter really does is provide a method that
returns a boolean result that determines whether the child nodes of the arbiter should remain in the
configuration or be pruned.
Arbiters may occur anywhere an element is allowed in the configuration. So an Aribiter could
encapsulate something as simple as a single property declaration or a whole set of Appenders or
Loggers. Arbiters may also be nested although Arbiters that are the descendant of another arbiter will
only be evalued if the ancestor returned true. The child elements of an Arbiter must be valid elements
for whatever element is the parent of the Arbiter.
This example shows two Arbiters configured that will include either a Console Appender or a List
Appender depending on whether the value of the env System Property is "dev" or "prod".
</Appenders>
<Loggers>
<Logger name="org.apache.test" level="trace" additivity="false">
<AppenderRef ref="Out"/>
</Logger>
<Root level="error">
<AppenderRef ref="Out"/>
</Root>
</Loggers>
</Configuration>
Normally Arbiters act in isolation from other Arbiters. That is, the outcome of one Arbiter will not
impact any other Arbiters. This can be cumbersome when you simply want to use one of a set of
choices. A special plugin named "Select" can be used in this case. Each element under the Select
is required to be an Arbiter. The first Arbiter that returns a true value will be the one used while
others are ignored. If no Arbiter returns true a DefaultAtrbiter may be configured with the default
configuration elements. The DefaultArbiter is an Arbiter that always returns true, so using it outside
of a Select would result in its configured elements always being included just as if it hadn't been
present.
This example shows an Arbiter that uses Javascript residing in a separate file to determine whether to
include the Console Appender. If the result is false then a List Appender will be included.
Natively Log4j contains the SystemProperty Arbiter that can evaluate whether to include elements
based on whether a SystemProperty is non-null or has a specific value, a ClassArbiter that makes its
decision based on whether the specified class is present, and a ScriptArbiter that makes its decision
based on the result of the script configured with it.
For Spring Boot users an Arbiter named SpringProfile has been provided. The specified profiles
are evaluated by Spring's Environment.acceptsProfiles() method, so any expressions it
supports may be used as the name attribute.
This example will use a Console Appender when the Spring profile is "dev" or "staging" and a List
Appender when the active profile is "prod".
</Appenders>
<Loggers>
<Logger name="org.apache.test" level="trace" additivity="false">
<AppenderRef ref="Out"/>
</Logger>
<Root level="error">
<AppenderRef ref="Out"/>
</Root>
</Loggers>
</Configuration>
1. Log4j will inspect the "log4j2.configurationFile" system property and, if set, will
attempt to load the configuration using the ConfigurationFactory that matches the file
extension. Note that this is not restricted to a location on the local file system and may contain a
URL.
2. If no system property is set the properties ConfigurationFactory will look for log4j2-
test.properties in the classpath.
3. If no such file is found the YAML ConfigurationFactory will look for log4j2-test.yaml or
log4j2-test.yml in the classpath.
4. If no such file is found the JSON ConfigurationFactory will look for log4j2-test.json or
log4j2-test.jsn in the classpath.
5. If no such file is found the XML ConfigurationFactory will look for log4j2-test.xml in the
classpath.
6. If a test file cannot be located the properties ConfigurationFactory will look for
log4j2.properties on the classpath.
7. If a properties file cannot be located the YAML ConfigurationFactory will look for
log4j2.yaml or log4j2.yml on the classpath.
8. If a YAML file cannot be located the JSON ConfigurationFactory will look for log4j2.json or
log4j2.jsn on the classpath.
9. If a JSON file cannot be located the XML ConfigurationFactory will try to locate log4j2.xml
on the classpath.
10.If no configuration file could be located the DefaultConfiguration will be used. This will
cause logging output to go to the console.
An example application named MyApp that uses log4j can be used to illustrate how this is done.
import com.foo.Bar;
logger.trace("Entering application.");
Bar bar = new Bar();
if (!bar.doIt()) {
logger.error("Didn't do it.");
}
logger.trace("Exiting application.");
}
}
MyApp begins by importing log4j related classes. It then defines a static logger variable with the name
MyApp which happens to be the fully qualified name of the class.
MyApp uses the Bar class defined in the package com.foo.
package com.foo;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
Log4j will provide a default configuration if it cannot locate a configuration file. The default
configuration, provided in the DefaultConfiguration class, will set up:
As was described previously, Log4j will first attempt to configure itself from configuration files. A
configuration equivalent to the default would look like:
Once the file above is placed into the classpath as log4j2.xml you will get results identical to those
listed above. Changing the root level to trace will result in results similar to:
Note that status logging is disabled when the default configuration is used.
5.1.4 Additivity
Perhaps it is desired to eliminate all the TRACE output from everything except com.foo.Bar.
Simply changing the log level would not accomplish the task. Instead, the solution is to add a new
logger definition to the configuration:
With this configuration all log events from com.foo.Bar will be recorded while only error events
will be recorded from all other components.
In the previous example all the events from com.foo.Bar were still written to the Console. This is
because the logger for com.foo.Bar did not have any appenders configured while its parent did. In
fact, the following configuration
would result in
Notice that the trace messages from com.foo.Bar appear twice. This is because the appender
associated with logger com.foo.Bar is first used, which writes the first instance to the Console.
Next, the parent of com.foo.Bar, which in this case is the root logger, is referenced. The event is
then passed to its appender, which is also writes to the Console, resulting in the second instance. This
is known as additivity. While additivity can be quite a convenient feature (as in the first previous
example where no appender reference needed to be configured), in many cases this behavior is
considered undesirable and so it is possible to disable it by setting the additivity attribute on the logger
to false:
Once an event reaches a logger with its additivity set to false the event will not be passed to any of its
parent loggers, regardless of their additivity setting.
5.1.6 Chainsaw can automatically process your log files (Advertising appender configurations)
Log4j provides the ability to 'advertise' appender configuration details for all file-based appenders
as well as socket-based appenders. For example, for file-based appenders, the file location and the
pattern layout in the file are included in the advertisement. Chainsaw and other external systems can
discover these advertisements and use that information to intelligently process the log file.
The mechanism by which an advertisement is exposed, as well as the advertisement format, is specific
to each Advertiser implementation. An external system which would like to work with a specific
Advertiser implementation must understand how to locate the advertised configuration as well as the
format of the advertisement. For example, a 'database' Advertiser may store configuration details in
a database table. An external system can read that database table in order to discover the file location
and the file format.
Log4j provides one Advertiser implementation, a 'multicastdns' Advertiser, which advertises appender
configuration details via IP multicast using the http://jmdns.sourceforge.net library.
Chainsaw automatically discovers log4j's multicastdns-generated advertisements and displays
those discovered advertisements in Chainsaw's Zeroconf tab (if the jmdns library is in Chainsaw's
classpath). To begin parsing and tailing a log file provided in an advertisement, just double-click
the advertised entry in Chainsaw's Zeroconf tab. Currently, Chainsaw only supports FileAppender
advertisements.
To advertise an appender configuration:
• Add the JmDns library from http://jmdns.sourceforge.net to the application classpath
• Set the 'advertiser' attribute of the configuration element to 'multicastdns'
• Set the 'advertise' attribute on the appender element to 'true'
• If advertising a FileAppender-based configuration, set the 'advertiseURI' attribute on the
appender element to an appropriate URI
FileAppender-based configurations require an additional 'advertiseURI' attribute to be specified on
the appender. The 'advertiseURI' attribute provides Chainsaw with information on how the file can be
accessed. For example, the file may be remotely accessible to Chainsaw via ssh/sftp by specifying a
Commons VFS ( http://commons.apache.org/proper/commons-vfs/) sftp:// URI, an http:// URI may
be used if the file is accessible through a web server, or a file:// URI can be specified if accessing the
file from a locally-running instance of Chainsaw.
Here is an example advertisement-enabled appender configuration which can be used by a locally-
running Chainsaw to automatically tail the log file (notice the file:// advertiseURI):
Please note, you must add the JmDns library from http://jmdns.sourceforge.net to your
application classpath in order to advertise with the 'multicastdns' advertiser.
<PatternLayout>
<Pattern>%m%n</Pattern>
</PatternLayout>
are equivalent.
The file below represents the structure of an XML configuration, but note that the elements in italics
below represent the concise element names that would appear in their place.
See the many examples on this page for sample appender, filter and logger declarations.
5.Strict XML
In addition to the concise XML format above, Log4j allows configurations to be specified in a
more "normal" XML manner that can be validated using an XML Schema. This is accomplished by
replacing the friendly element names above with their object type as shown below. For example,
instead of the ConsoleAppender being configured using an element named Console it is instead
configured as an appender element with a type attribute containing "Console".
<Appenders>
<Appender type="Console" name="STDOUT">
<Layout type="PatternLayout" pattern="%m MDC%X%n"/>
<Filters>
<Filter type="MarkerFilter" marker="FLOW" onMatch="DENY" onMismatch="NEUTRAL"/>
<Filter type="MarkerFilter" marker="EXCEPTION" onMatch="DENY" onMismatch="ACCEPT"/>
</Filters>
</Appender>
<Appender type="Console" name="FLOW">
<Layout type="PatternLayout" pattern="%C{1}.%M %m %ex%n"/><!-- class and line number -->
<Filters>
<Filter type="MarkerFilter" marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<Filter type="MarkerFilter" marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
</Filters>
</Appender>
<Appender type="File" name="File" fileName="${filename}">
<Layout type="PatternLayout">
<Pattern>%d %p %C{1.} [%t] %m%n</Pattern>
</Layout>
</Appender>
</Appenders>
<Loggers>
<Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
<Filter type="ThreadContextMapFilter">
<KeyValuePair key="test" value="123"/>
</Filter>
<AppenderRef ref="STDOUT"/>
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
Note that in the RoutingAppender the Route element has been declared as an array. This is valid
because each array element will be a Route component. This won't work for elements such as
appenders and filters, where each element has a different name in the concise format. Appenders and
filters can be defined as array elements if each appender or filter declares an attribute named "type"
that contains the type of the appender. The following example illustrates this as well as how to declare
multiple loggers as an array.
Additional runtime dependencies are required for using JSON configuration files.
Configuration:
status: warn
name: YAMLConfigTest
properties:
property:
name: filename
value: target/test-yaml.log
thresholdFilter:
level: debug
appenders:
Console:
name: STDOUT
target: SYSTEM_OUT
PatternLayout:
Pattern: "%m%n"
File:
name: File
fileName: ${filename}
PatternLayout:
Pattern: "%d %p %C{1.} [%t] %m%n"
Filters:
ThresholdFilter:
level: error
Loggers:
logger:
-
name: org.apache.logging.log4j.test1
level: debug
additivity: false
ThreadContextMapFilter:
KeyValuePair:
key: test
value: 123
AppenderRef:
ref: STDOUT
-
name: org.apache.logging.log4j.test2
level: debug
additivity: false
AppenderRef:
ref: File
Root:
level: error
AppenderRef:
ref: STDOUT
Additional runtime dependencies are required for using YAML configuration files.
status = error
dest = err
name = PropertiesConfig
property.filename = target/rolling/rollingtest.log
filter.threshold.type = ThresholdFilter
filter.threshold.level = debug
appender.console.type = Console
appender.console.name = STDOUT
appender.console.layout.type = PatternLayout
appender.console.layout.pattern = %m%n
appender.console.filter.threshold.type = ThresholdFilter
appender.console.filter.threshold.level = error
appender.rolling.type = RollingFile
appender.rolling.name = RollingFile
appender.rolling.fileName = ${filename}
appender.rolling.filePattern = target/rolling2/test1-%d{MM-dd-yy-HH-mm-ss}-%i.log.gz
appender.rolling.layout.type = PatternLayout
appender.rolling.layout.pattern = %d %p %C{1.} [%t] %m%n
appender.rolling.policies.type = Policies
appender.rolling.policies.time.type = TimeBasedTriggeringPolicy
appender.rolling.policies.time.interval = 2
appender.rolling.policies.time.modulate = true
appender.rolling.policies.size.type = SizeBasedTriggeringPolicy
appender.rolling.policies.size.size=100MB
appender.rolling.strategy.type = DefaultRolloverStrategy
appender.rolling.strategy.max = 5
logger.rolling.name = com.example.my.app
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile
rootLogger.level = info
rootLogger.appenderRef.stdout.ref = STDOUT
Capturing location information (the class name, file name, method name, and line number of the
caller) can be slow. Log4j tries to optimize this by reducing the size of the stack that must be
traversed to find the caller of the logging method. It does this by determining if any component that
might be accessed requires location information. This can cause performance issues if a logger is
configured at a level like trace or debug with the expectation that most logs will be filtered on an
Appender reference or Appender as Log4j will calculate the location information even though the log
event is going to be discarded. To disable this behavior the includeLocation attribute can be set
to false on the LoggerConfig. This will cause Log4j to defer calculating the location information until
absolutely necessary.
A LoggerConfig (including the root LoggerConfig) can be configured with properties that will be
added to the properties copied from the ThreadContextMap. These properties can be referenced from
Appenders, Filters, Layouts, etc just as if they were part of the ThreadContext Map. The properties
can contain variables that will be resolved either when the configuration is parsed or dynamically
when each event is logged. See Property Substitution for more information on using variables.
The LoggerConfig may also be configured with one or more AppenderRef elements. Each appender
referenced will become associated with the specified LoggerConfig. If multiple appenders are
configured on the LoggerConfig each of them be called when processing logging events.
Every configuration must have a root logger. If one is not configured the default root LoggerConfig,
which has a level of ERROR and has a Console appender attached, will be used. The main differences
between the root logger and other loggers are
1. The root logger does not have a name attribute.
2. The root logger does not support the additivity attribute since it has no parent.
<Appenders>
<Console name="STDOUT">
<PatternLayout pattern="%m MDC%X%n"/>
</Console>
<Console name="FLOW">
<!-- this pattern outputs class name and line number -->
<PatternLayout pattern="%C{1}.%M %m %ex%n"/>
<filters>
<MarkerFilter marker="FLOW" onMatch="ACCEPT" onMismatch="NEUTRAL"/>
<MarkerFilter marker="EXCEPTION" onMatch="ACCEPT" onMismatch="DENY"/>
</filters>
</Console>
<File name="File" fileName="${filename}">
<PatternLayout>
<pattern>%d %p %C{1.} [%t] %m%n</pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Logger name="org.apache.logging.log4j.test1" level="debug" additivity="false">
<ThreadContextMapFilter>
<KeyValuePair key="test" value="123"/>
</ThreadContextMapFilter>
<AppenderRef ref="STDOUT"/>
</Logger>
<Root level="trace">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
<Appenders>
<Console name="STDOUT">
<PatternLayout pattern="%m%n"/>
<ThresholdFilter level="debug"/>
</Console>
<Routing name="Routing">
<Routes pattern="$${sd:type}">
<Route>
<RollingFile name="Rolling-${sd:type}" fileName="${filename}"
filePattern="target/rolling1/test1-${sd:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
<Route ref="STDOUT" key="Audit"/>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Logger name="EventLogger" level="info" additivity="false">
<AppenderRef ref="Routing"/>
</Logger>
<Root level="error">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
While this is useful, there are many more places properties can originate from. To accommodate this,
Log4j also supports the syntax ${prefix:name} where the prefix identifies tells Log4j that variable
name should be evaluated in a specific context. See the Lookups manual page for more details. The
contexts that are built in to Log4j are:
Prefix Context
base64 Base64 encoded data. The format is
${base64:Base64_encoded_data}.
For example:
${base64:SGVsbG8gV29ybGQhCg==} yields
Hello World!.
bundle Resource bundle. The format is
${bundle:BundleName:BundleKey}.
The bundle name follows package
naming conventions, for example:
${bundle:com.domain.Messages:MyKey}.
ctx Thread Context Map (MDC)
date Inserts the current date and/or time using the specified
format
env System environment variables. The formats are
${env:ENV_NAME} and ${env:ENV_NAME:-
default_value}.
jndi A value set in the default JNDI Context. (Requires
system property log4j2.enableJndiLookup to
be set to true.)
jvmrunargs A JVM input argument accessed through
JMX, but not a main argument; see
RuntimeMXBean.getInputArguments(). Not available
on Android.
log4j Log4j configuration properties. The expressions
${log4j:configLocation} and
${log4j:configParentLocation}
respectively provide the absolute path to the log4j
configuration file and its parent folder.
main A value set with
MapLookup.setMainArguments(String[])
map A value from a MapMessage
sd A value from a StructuredDataMessage. The key "id"
will return the name of the StructuredDataId without
the enterprise number. The key "type" will return the
message type. Other keys will retrieve individual
elements from the Map.
sys System properties. The formats are
${sys:some.property} and
${sys:some.property:-default_value}.
used. The default map is pre-populated with a value for "hostName" that is the current system's host
name or IP address and the "contextName" with is the value of the current logging context. See many
places a Properties element is used in this section for examples.
Default properties may also be specified in the Lookup by using the syntax ${lookupName:key:-
defaultValue}. In some cases the key might contain a leading '-'. When this is the case an escape
character must be included, such as ${main:\--file:-app.properties}. This would use the
MainMapLookup for a key named --file. If the key is not found then app.properties would be
used as the default value.
As a footnote, it is worth pointing out that the variables in the RollingFile appender declaration will
also not be evaluated when the configuration is processed. This is simply because the resolution
of the whole RollingFile element is deferred until a match occurs. See RoutingAppender for more
information.
5.1.13 Scripts
Log4j provides support for JSR 223 scripting languages to be used in some of its components.
Any language that provides support for the JSR 223 scripting engine may be used. A list of the
languages and bindings for them can be found at the Scripting Engine web site. However, some of
the languages listed there, such as JavaScript, Groovy and Beanshell, directly support the JSR 223
scripting framework and only require that the jars for that language be installed.
The components that support using scripts do so by allowing a <script>, <scriptFile>, or <scriptRef>
element to be configured on them. The script element contains a name for the script, the language
of the script, and the script text. The scriptFile element contains the name of the script, its location,
its language, its charset, and whether the file should be watched for changes. The scriptRef element
contains the name of the script that is defined in the <scripts> configuration element. The name of
the script is used to store the script, along with its ScriptEngine, so it can quickly be located each
time the script needs to be run. While the name is not required, providing it will help in debugging
problems when the script is running. The language must be provided on the script element and must
specify one of the language names that appear in the Configuration status log as described in the next
section. If the language is not specified on the scriptFile element the language will be determined by
the file extension of the script path. If file monitoring is requested it will only be enabled if a non-
zero monitorInterval is specified on the configuration element. That interval will be used to check for
changes in the file.
<Appenders>
<Console name="STDOUT">
<ScriptPatternSelector defaultPattern="%d %p %m%n">
<ScriptRef ref="selector"/>
<PatternMatch key="NoLocation" pattern="[%-5level] %c{1.} %msg%n"/>
<PatternMatch key="Flow" pattern="[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"/>
</ScriptPatternSelector>
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="EventLogger" level="info" additivity="false">
<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">
<Script name="GroovyFilter" language="groovy"><![CDATA[
if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("FLOW")) {
return true;
} else if (logEvent.getContextMap().containsKey("UserId")) {
return true;
}
return false;
]]>
</Script>
</ScriptFilter>
<AppenderRef ref="STDOUT"/>
</Logger>
<Root level="error">
<ScriptFilter onMatch="ACCEPT" onMisMatch="DENY">
<ScriptRef ref="groovy.filter"/>
</ScriptFilter>
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
If the status attribute on the Configuration element is set to DEBUG the list of script engines currently
installed and their attributes will be listed. Although some engines may say they are not thread safe,
Log4j takes steps to insure that the scripts will run in a thread-safe manner if the engine advertises
that it is not thread safe.
When the scripts are executed they will be provided with a set of variables that should allow them
to accomplish whatever task they are expected to perform. See the documentation for the individual
components for the list of variables that are available to the script.
The components that support scripting expect a return value to be passed back to the calling Java
code. This is not a problem for several of the scripting languages, but Javascript does not allow a
return statement unless it is within a function. However, Javascript will return the value of the last
statement executed in the script. As a consequence, code such as that shown below will result in the
desired behavior.
var result;
if (logEvent.getLoggerName().equals("JavascriptNoLocation")) {
result = "NoLocation";
} else if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("FLOW")) {
result = "Flow";
}
result;
5.1.14 XInclude
XML configuration files can include other files with XInclude. Here is an example log4j2.xml file
that includes two other files:
log4j-xinclude-appenders.xml:
log4j-xinclude-loggers.xml:
<root level="error">
<AppenderRef ref="STDOUT" />
</root>
</loggers>
When configuring Log4j it is sometimes necessary to view the generated status events. This can
be accomplished by adding the status attribute to the configuration element or a default value can
be provided by setting the "Log4jDefaultStatusLevel" system property. Valid values of the status
attribute are "trace", "debug", "info", "warn", "error" and "fatal". The following configuration has the
status attribute set to debug.
<Appenders>
<Console name="STDOUT">
<PatternLayout pattern="%m%n"/>
<ThresholdFilter level="debug"/>
</Console>
<Routing name="Routing">
<Routes pattern="$${sd:type}">
<Route>
<RollingFile name="Rolling-${sd:type}" fileName="${filename}"
filePattern="target/rolling1/test1-${sd:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
<Route ref="STDOUT" key="Audit"/>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Logger name="EventLogger" level="info" additivity="false">
<AppenderRef ref="Routing"/>
</Logger>
<Root level="error">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
@Test
public void testSomeAwesomeFeature() {
final LoggerContext ctx = init.getLoggerContext();
final Logger logger = init.getLogger("org.apache.logging.log4j.my.awesome.test.logger");
final Configuration cfg = init.getConfiguration();
final ListAppender app = init.getListAppender("List");
logger.warn("Test message");
final List<LogEvent> events = app.getEvents();
// etc.
}
}
Property Name
(Legacy Property
Name) Environment Variable Default Value Description
log4j2.configurationFile LOG4J_CONFIGURATION_FILE Path to an Log4j 2
( log4j.configurationFile) configuration file.
May also contain a
comma separated list
of configuration file
names. May contain a
URL. When specified
as a URL the "override"
query parameter may
be used to specify
additional configuration
file locations.
log4j2.debug LOG4J_DEBUG Log4j2 will print all
( log4j2.debug) internal logging to the
console if system property
log4j2.debug is
either defined empty or
its value equals to true
(ignoring case).
log4j2.disableThreadContextStack
LOG4J_DISABLE_THREAD_CONTEXT_STACK
false If true, the
(disableThreadContextStack) ThreadContext stack is
disabled.
log4j2.disableThreadContextMap
LOG4J_DISABLE_THREAD_CONTEXT_MAP
false If true, the
(disableThreadContextMap) ThreadContext map
is disabled. (May be
ignored if a custom
ThreadContext map is
specified.)
log4j2.threadContextMap LOG4J_THREAD_CONTEXT_MAP Fully specified class
(log4j2.threadContextMap) name of a custom
ThreadContextMap
implementation class.
log4j2.isThreadContextMapInheritable
LOG4J_IS_THREAD_CONTEXT_MAP_INHERITABLE
false If true use a
(isThreadContextMapInheritable) InheritableThreadLocal
to implement the
ThreadContext map.
Otherwise, use a plain
ThreadLocal. (May
be ignored if a custom
ThreadContext map is
specified.)
log4j2.contextDataInjector LOG4J_CONTEXT_DATA_INJECTOR Fully specified class
( name of a custom
log4j2.ContextDataInjector) ContextDataInjector
implementation class.
log4j2.garbagefreeThreadContextMap
LOG4J_GARBAGEFREE_THREAD_CONTEXT_MAP
false Specify "true" to make
( the ThreadContext map
log4j2.garbagefree.threadContextMap) garbage-free.
log4j2.disableJmx LOG4J_DISABLE_JMX false If true, Log4j
( log4j2.disable.jmx) configuration objects
like LoggerContexts,
Appenders, Loggers, etc.
will not be instrumented
with MBeans and cannot
be remotely monitored
and managed.
log4j2.jmxNotifyAsync LOG4J_JMX_NOTIFY_ASYNC
false for web apps, true If true, log4j's JMX
( log4j2.jmx.notify.async) otherwise notifications are sent from
a separate background
thread, otherwise they
are sent from the caller
thread. If system property
log4j2.is.webapp
is true or the
javax.servlet.Servlet
class is on the classpath,
the default behaviour is
to use the caller thread to
send JMX notifications.
log4j2.skipJansi LOG4J_SKIP_JANSI true If true, the
( log4j.skipJansi) ConsoleAppender will not
try to use the Jansi output
stream on Windows.
log4j2.simplelogLogFile LOG4J_SIMPLELOG_LOG_FILE
system.err "system.err" (case-
( insensitive) logs
org.apache.logging.log4j .simplelog.logFile) to System.err,
"system.out" (case-
insensitive) logs to
System.out, any other
value is interpreted
as a file name to save
SimpleLogger messages
to.
log4j2.simplelogLevel LOG4J_SIMPLELOG_LEVEL
ERROR Default level for new
( SimpleLogger instances.
org.apache.logging.log4j .simplelog.level)
log4j2.simplelog.<loggerName>.level
LOG4J_SIMPLELOG_<LOGGER_NAME>_LEVEL
SimpleLogger default log Log level for a the
( level SimpleLogger instance
org.apache.logging.log4j .simplelog.<loggerName>.level) with the specified name.
log4j2.simplelogStatusLoggerLevel
LOG4J_SIMPLELOG_STATUS_LOGGER_LEVEL
ERROR This property is used
( to control the initial
org.apache.logging.log4j.simplelog .StatusLogger.level) StatusLogger level,
and can be overridden
in code by calling
StatusLogger.getLogger() .setLe
Note that the
StatusLogger level is
only used to determine
the status log output
level until a listener is
registered. In practice,
a listener is registered
when a configuration
is found, and from that
point onwards, status
messages are only sent to
the listeners (depending
on their statusLevel).
log4j2.defaultStatusLevel LOG4J_DEFAULT_STATUS_LEVEL
ERROR The StatusLogger
( logs events that
Log4jDefaultStatusLevel) occur in the logging
system to the console.
During configuration,
AbstractConfiguration
registers a
StatusConsoleListener
with the StatusLogger
that may redirect
status log events from
the default console
output to a file. The
listener also supports
fine-grained filtering.
This system property
specifies the default
status log level for the
listener to use if the
configuration does not
specify a status level.
Note: this property is
used by the log4j-core
implementation only
after a configuration
file has been found.
log4j2.statusLoggerLevel LOG4J_STATUS_LOGGER_LEVEL
WARN The initial
( "listenersLevel" of
log4j2.StatusLogger.level) the StatusLogger.
If StatusLogger
listeners are added,
the "listenerLevel"
is changed to that
of the most verbose
listener. If any listeners
are registered, the
listenerLevel is used
to quickly determine
if an interested listener
exists.
By default,
StatusLogger listeners
are added when a
configuration is found
and by the JMX
StatusLoggerAdmin
MBean. For
example, if a
configuration contains
<Configuration
status="trace">,
a listener with
statusLevel TRACE
is registered and
the StatusLogger
listenerLevel is set
to TRACE, resulting
in verbose status
messages displayed on
the console.
If no listeners are
registered, the
listenersLevel is
not used, and the
StatusLogger output
level is determined by
StatusLogger.getLogger().getLev
(see property
org.apache.logging.log4j.simple
log4j2.statusEntries LOG4J_STATUS_ENTRIES200 Number of StatusLogger
( log4j2.status.entries) events that are kept
in a buffer and can
be retrieved with
StatusLogger.getStatusData().
log4j2.statusLoggerDateformat
LOG4J_STATUS_LOGGER_DATEFORMAT Date-time format string
( to use as the format
log4j2.StatusLogger.DateFormat) for timestamps in the
status logger output. See
java.text.SimpleDateFormat
for supported formats.
log4j2.asyncLoggerExceptionHandler
LOG4J_ASYNC_LOGGER_EXCEPTION_HANDLER
default handler See Async Logger
( System Properties for
AsyncLogger.ExceptionHandler) details.
log4j2.asyncLoggerRingBufferSize
LOG4J_ASYNC_LOGGER_RING_BUFFER_SIZE
256 * 1024 or 4 * 1024 in See Async Logger
( garbage-free mode System Properties for
AsyncLogger.RingBufferSize) details.
log4j2.asyncLoggerWaitStrategy
LOG4J_ASYNC_LOGGER_WAIT_STRATEGY
Timeout See Async Logger
( System Properties for
AsyncLogger.WaitStrategy) details.
log4j2.asyncLoggerTimeout LOG4J_ASYNC_LOGGER_TIMEOUT
10 See Async Logger
( AsyncLogger.Timeout) System Properties for
details.
log4j2.asyncLoggerSleepTimeNs
LOG4J_ASYNC_LOGGER_SLEEP_TIME_NS
100 See Async Logger
( System Properties for
AsyncLogger.SleepTimeNs) details.
log4j2.asyncLoggerRetries LOG4J_ASYNC_LOGGER_SLEEP_TIME_NS
200 See Async Logger
( AsyncLogger.Retries) System Properties for
details.
AsyncLogger.SynchronizeEnqueueWhenQueueFull
ASYNC_LOGGER_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL
true See Async Logger
System Properties for
details.
log4j2.asyncLoggerThreadNameStrategy
LOG4J_ASYNC_LOGGER_THREAD_NAME_STRATEGY
CACHED See Async Logger
( System Properties for
AsyncLogger.ThreadNameStrategy) details.
log4j2.asyncLoggerConfigExceptionHandler
LOG4J_ASYNC_LOGGER_CONFIG_EXCEPTION_HANDLER
default handler See Mixed Async/
( Synchronous Logger
AsyncLoggerConfig.ExceptionHandler) System Properties for
details.
log4j2.asyncLoggerConfigRingBufferSize
LOG4J_ASYNC_LOGGER_CONFIG_RING_BUFFER_SIZE
256 * 1024 or 4 * 1024 in See Mixed Async/
( garbage-free mode Synchronous Logger
AsyncLoggerConfig.RingBufferSize) System Properties for
details.
log4j2.asyncLoggerConfigWaitStrategy
LOG4J_ASYNC_LOGGER_CONFIG_WAIT_STRATEGY
Timeout See Mixed Async/
( Synchronous Logger
AsyncLoggerConfig.WaitStrategy) System Properties for
details.
AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull
ASYNC_LOGGER_CONFIG_SYNCHRONIZE_ENQUEUE_WHEN_QUEUE_FULL
true See Mixed Async/
Synchronous Logger
System Properties for
details.
log4j2.julLoggerAdapter LOG4J_JUL_LOGGER_ADAPTER
org.apache.logging.log4j .jul.ApiLoggerAdapter
Default LoggerAdapter to
( log4j.jul.LoggerAdapter) use in the JUL adapter.
By default, if log4j-core is
available, then the class
org.apache.logging.log4j.jul .C
will be used.
Otherwise, the
ApiLogggerAdapter
will be used. Custom
implementations must
provide a public default
constructor.
log4j2.formatMsgAsync LOG4J_FORMAT_MSG_ASYNC
false If false (the default),
( log4j.format.msg.async) Log4j will make sure the
message is formatted
in the caller thread, to
ensure the value at the
time of the call to the
logger is the value that is
logged.
log4j2.asyncQueueFullPolicyLOG4J_ASYNC_QUEUE_FULL_POLICY Used by Async
( Loggers and the
log4j2.AsyncQueueFullPolicy) AsyncAppender to
maintain application
throughput even
when the underlying
appender cannot keep
up with the logging rate
and the queue is filling
up.
If no value is specified
(the default) events are
never discarded. If the
queue is full, the logger
call blocks until the
event can be added to
the queue.
Specify Discard to
drop events whose
level is equal or less
than the threshold level
(INFO by default)
when the queue is full.
log4j2.discardThreshold LOG4J_DISCARD_THRESHOLD
INFO Used by the
( DiscardingAsyncQueueFullPolicy
log4j2.DiscardThreshold) to determine which
events to drop when
the queue becomes
full. By default, INFO,
DEBUG and TRACE level
events are discarded
when the queue is full.
This property only has
effect if Discard
is specified as the
log4j2.AsyncQueueFullPolicy.
log4j2.messageFactory LOG4J_MESSAGE_FACTORY
org.apache.logging.log4j.message.
Default message factory
( log4j2.messageFactory) ParameterizedMessageFactoryused by Loggers if no
or factory was specified.
org.apache.logging.log4j.message.
ReusableMessageFactory
in garbage-free mode
log4j2.flowMessageFactory LOG4J_FLOW_MESSAGE_FACTORY
org.apache.logging.log4j.message.
Default flow message
( DefaultFlowMessageFactoryfactory used by Loggers.
log4j2.flowMessageFactory)
log4j2.isWebapp LOG4J_IS_WEBAPP true if Servlet class on This system property can
( log4j2.is.webapp) class path be used to force Log4j 2
to behave as if it is part of
a web application (when
true) or as if it is not part
of a web application
(when false).
log4j2.enableThreadlocals LOG4J_ENABLE_THREADLOCALS
true This system property can
( be used to switch off the
log4j2.enable.threadlocals) use of threadlocals, which
will partly disable Log4j's
garbage-free behaviour:
to be fully garbage-free,
Log4j stores objects in
ThreadLocal fields to
reuse them, otherwise
new objects are created
for each log event. Note
that this property is not
effective when Log4j
detects it is running in a
web application.
log4j2.enableDirectEncodersLOG4J_ENABLE_DIRECT_ENCODERS
true This property can be
( used to force garbage-
log4j2.enable.direct.encoders) aware Layouts and
Appenders to revert to
the pre-2.6 behaviour
where converting log
events to text generates
temporary objects like
Strings and char[] arrays,
and converting this
text to bytes generates
temporary byte[] arrays.
By default, this property is
true and garbage-aware
Layouts and Appenders
that convert log events to
text will convert this text
to bytes without creating
temporary objects.
log4j2.initialReusableMsgSize
LOG4J_INITIAL_REUSABLE_MSG_SIZE
128 In GC-free mode, this
( property determines the
log4j.initialReusableMsgSize) initial size of the reusable
StringBuilders where the
message text is formatted
and potentially passed to
background threads.
log4j2.maxReusableMsgSizeLOG4J_MAX_REUSABLE_MSG_SIZE
518 In GC-free mode, this
( property determines the
log4j.maxReusableMsgSize) maximum size of the
reusable StringBuilders
where the message text is
formatted and potentially
passed to background
threads.
log4j2.layoutStringBuilderMaxSize
LOG4J_LAYOUT_STRING_BUILDER_MAX_SIZE
2048 This property determines
( the maximum size
log4j.layoutStringBuilder.maxSize) of the thread-local
reusable StringBuilders
used to format the
log event to text by
Layouts that extend
AbstractStringLayout.
log4j2.unboxRingbufferSize LOG4J_UNBOX_RINGBUFFER_SIZE
32 The
( org.apache.logging.log4j.util.U
log4j.unbox.ringbuffer.size) utility manages a small
thread-local ring buffer
of StringBuilders. Each
time one of the box()
methods is called, the
next slot in the ring buffer
is used, until the ring
buffer is full and the first
slot is reused. By default
the Unbox ring buffer has
32 slots, so user code
can have up to 32 boxed
primitives in a single
logger call.
If more slots
are required, set
system property
log4j.unbox.ringbuffer.size
to the desired ring
buffer size. Note that
the specified number
will be rounded up to
the nearest power of 2.
log4j2.loggerContextStacktraceOnStart
LOG4J_LOGGER_CONTEXT_STACKTRACE_ON_START
false Prints a stacktrace to
( the status logger at
log4j.LoggerContext.stacktrace.on.start) DEBUG level when the
LoggerContext is started.
For debug purposes.
log4j2.trustStoreLocation LOG4J_TRUST_STORE_LOCATION The location of the trust
store. If not provided the
default trust store will be
used.
log4j2.trustStorePassword LOG4J_TRUST_STORE_PASSWORD Password needed to
access the trust store.
log4j2.trustStorePasswordFile
LOG4J_TRUST_STORE_PASSWORD_FILE The location of a file that
contains the password for
the trust store.
log4j2.trustStorePasswordEnvironmentVariable
LOG4J_TRUST_STORE_PASSWORD_ENVIRONMENT_VARIABLE
The name of the
environment variable that
contains the trust store
password.
log4j2.trustStoreType LOG4J_TRUST_STORE_TYPE The type of key store
used for the trust store.
log4j2.trustStoreKeyManagerFactoryAlgorithm
LOG4J_TRUST_STORE_KEY_MANAGER_FACTORY_ALGORITHM
Java cryptographic
algorithm.
log4j2.keyStoreLocation LOG4J_KEY_STORE_LOCATION The location of the key
store. If not provided the
default key store will be
used.
log4j2.keyStorePassword LOG4J_KEY_STORE_PASSWORD Password needed to
access the key store.
6.1.1 Configuration
Log4j allows the configuration file to be specified in web.xml using the log4jConfiguration
context parameter. Log4j will search for configuration files by:
1. If a location is provided it will be searched for as a servlet context resource. For example, if
log4jConfiguration contains "logging.xml" then Log4j will look for a file with that name in
the root directory of the web application.
2. If no location is defined Log4j will search for a file that starts with "log4j2" in the WEB-INF
directory. If more than one file is found, and if a file that starts with "log4j2-name" is present,
where name is the name of the web application, then it will be used. Otherwise the first file will
be used.
3. The "normal" search sequence using the classpath and file URLs will be used to locate the
configuration file.
A Servlet 3.0 or newer web application is any <web-app> whose version attribute has a value of
"3.0" or higher. Of course, the application must also be running in a compatible web container.
Some examples are:
• Tomcat 7.0 and higher
• GlassFish 3.0 and higher
• JBoss 7.0 and higher
• Oracle WebLogic 12c and higher
• IBM WebSphere 8.0 and higher
Thanks to the ServletContainerInitializer API added to Servlet 3.0, the relevant Filter and
ServletContextListener classes can be registered dynamically on web application startup.
Important Note! For performance reasons, containers often ignore certain JARs known not to
contain TLDs or ServletContainerInitializers and do not scan them for web-fragments and
initializers. Importantly, Tomcat 7 <7.0.43 ignores all JAR files named log4j*.jar, which prevents this
feature from working. This has been fixed in Tomcat 7.0.43, Tomcat 8, and later. In Tomcat 7 <7.0.43
you will need to change catalina.properties and remove "log4j*.jar" from the jarsToSkip
property. You may need to do something similar on other containers if they skip scanning Log4j JAR
files.
A Servlet 2.5 web application is any <web-app> whose version attribute has a value of "2.5." The
version attribute is the only thing that matters; even if the web application is running in a Servlet
3.0 or newer container, it is a Servlet 2.5 web application if the version attribute is "2.5." Note that
Log4j 2 does not support Servlet 2.4 and older web applications.
If you are using Log4j in a Servlet 2.5 web application, or if you have disabled auto-initialization
with the isLog4jAutoInitializationDisabled context parameter, you must configure
the Log4jServletContextListener and Log4jServletFilter in the deployment descriptor or
programmatically. The filter should match all requests of any type. The listener should be the very
first listener defined in your application, and the filter should be the very first filter defined and
mapped in your application. This is easily accomplished using the following web.xml code:
<listener>
<listener-class>org.apache.logging.log4j.web.Log4jServletContextListener</listener-class>
</listener>
<filter>
<filter-name>log4jServletFilter</filter-name>
<filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>log4jServletFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
<dispatcher>ASYNC</dispatcher><!-- Servlet 3.0 w/ disabled auto-initialization only; not supported in
</filter-mapping>
You can customize the behavior of the listener and filter using the log4jContextName,
log4jConfiguration, and/or isLog4jContextSelectorNamed context parameters. Read more
about this in the Context Parameters section below.
By default, Log4j 2 uses the ServletContext's context name as the LoggerContext name
and uses the standard pattern for locating the Log4j configuration file. There are three context
parameters that you can use to control this behavior. The first, isLog4jContextSelectorNamed,
specifies whether the context should be selected using the JndiContextSelector. If
isLog4jContextSelectorNamed is not specified or is anything other than true, it is assumed to
be false.
If isLog4jContextSelectorNamed is true, log4jContextName must be specified or
display-name must be specified in web.xml; otherwise, the application will fail to start with an
exception. log4jConfiguration should also be specified in this case, and must be a valid URI for
the configuration file; however, this parameter is not required.
If isLog4jContextSelectorNamed is not true, log4jConfiguration may optionally be
specified and must be a valid URI or path to a configuration file or start with "classpath:" to denote
a configuration file that can be found on the classpath. Without this parameter, Log4j will use the
standard mechanisms for locating the configuration file.
When specifying these context parameters, you must specify them in the deployment descriptor (
web.xml) even in a Servlet 3.0 or never application. If you add them to the ServletContext within
a listener, Log4j will initialize before the context parameters are available and they will have no
effect. Here are some sample uses of these context parameters.
You may want to use information about the web application during configuration. For example,
you could embed the web application's context path in the name of a Rolling File Appender. See
WebLookup in Lookups for more information.
You may use Log4j 2 within JSPs just as you would within any other Java code. Simple obtain
a Logger and call its methods to log events. However, this requires you to use Java code within
your JSPs, and some development teams rightly are not comfortable with doing this. If you have a
dedicated user interface development team that is not familiar with using Java, you may even have
Java code disabled in your JSPs.
For this reason, Log4j 2 provides a JSP Tag Library that enables you to log events without using any
Java code. To read more about using this tag library, read the Log4j Tag Library documentation.
Important Note! As noted above, containers often ignore certain JARs known not to contain TLDs
and do not scan them for TLD files. Importantly, Tomcat 7 <7.0.43 ignores all JAR files named
log4j*.jar, which prevents the JSP tag library from being automatically discovered. This does not
affect Tomcat 6.x and has been fixed in Tomcat 7.0.43, Tomcat 8, and later. In Tomcat 7 <7.0.43
you will need to change catalina.properties and remove "log4j*.jar" from the jarsToSkip
property. You may need to do something similar on other containers if they skip scanning Log4j JAR
files.
The handling of asynchronous requests is tricky, and regardless of Servlet container version or
configuration Log4j cannot handle everything automatically. When standard requests, forwards,
includes, and error resources are processed, the Log4jServletFilter binds the LoggerContext
to the thread handling the request. After request processing completes, the filter unbinds the
LoggerContext from the thread.
Similarly, when an internal request is dispatched using a javax.servlet.AsyncContext, the
Log4jServletFilter also binds the LoggerContext to the thread handling the request and
unbinds it when request processing completes. However, this only happens for requests dispatched
through the AsyncContext. There are other asynchronous activities that can take place other than
internal dispatched requests.
For example, after starting an AsyncContext you could start up a separate thread to process the
request in the background, possibly writing the response with the ServletOutputStream. Filters
cannot intercept the execution of this thread. Filters also cannot intercept threads that you start in the
background during non-asynchronous requests. This is true whether you use a brand new thread or a
thread borrowed from a thread pool. So what can you do for these special threads?
You may not need to do anything. If you didn't use the isLog4jContextSelectorNamed
context parameter, there is no need to bind the LoggerContext to the thread. Log4j can safely
locate the LoggerContext on its own. In these cases, the filter provides only very modest
performance gains, and only when creating new Loggers. However, if you did specify the
isLog4jContextSelectorNamed context parameter with the value "true", you will need to
manually bind the LoggerContext to asynchronous threads. Otherwise, Log4j will not be able to
locate it.
Thankfully, Log4j provides a simple mechanism for binding the LoggerContext to asynchronous
threads in these special circumstances. The simplest way to do this is to wrap the Runnable instance
that is passed to the AsyncContext.start() method.
import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.web.WebLoggerContextUtils;
@Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) throws ServletExceptio
final AsyncContext asyncContext = req.startAsync();
asyncContext.start(WebLoggerContextUtils.wrapExecutionContext(this.getServletContext(), new Runnable(
@Override
public void run() {
final Logger logger = LogManager.getLogger(TestAsyncServlet.class);
logger.info("Hello, servlet!");
}
}));
}
@Override
protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletExcepti
final AsyncContext asyncContext = req.startAsync();
asyncContext.start(new Runnable() {
@Override
public void run() {
final Log4jWebSupport webSupport =
WebLoggerContextUtils.getWebLifeCycle(TestAsyncServlet.this.getServletContext());
webSupport.setLoggerContext();
// do stuff
webSupport.clearLoggerContext();
}
});
}
}
This can be slightly more convenient when using Java 1.8 and lambda functions as demonstrated
below.
import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.web.WebLoggerContextUtils;
Alternatively, you can obtain the Log4jWebLifeCycle instance from the ServletContext
attributes, call its setLoggerContext method as the very first line of code in your asynchronous
thread, and call its clearLoggerContext method as the very last line of code in your asynchronous
thread. The following code demonstrates this. It uses the container thread pool to execute
asynchronous request processing, passing an anonymous inner Runnable to the start method.
import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.web.Log4jWebLifeCycle;
import org.apache.logging.log4j.web.WebLoggerContextUtils;
Note that you must call clearLoggerContext once your thread is finished processing. Failing
to do so will result in memory leaks. If using a thread pool, it can even disrupt the logging of other
web applications in your container. For that reason, the example here shows clearing the context in a
finally block, which will always execute.
<Appenders>
<Servlet name="Servlet">
<PatternLayout pattern="%m%n%ex{none}"/>
</Servlet>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Servlet"/>
</Root>
</Loggers>
</Configuration>
To avoid double logging of exceptions to the servlet context, you must use %ex{none} in your
PatternLayout as shown in the example. The exception will be omitted from the message text but
it is passed to the servlet context as the actual Throwable object.
7 Plugins
.......................................................................................................................................
7.1 Plugins
7.1.1 Introduction
Log4j 1.x allowed for extension by requiring class attributes on most of the configuration
declarations. In the case of some elements, notably the PatternLayout, the only way to add new
pattern converters was to extend the PatternLayout class and add them via code. One goal of Log4j 2
is to make extending it extremely easy through the use of plugins.
In Log4j 2 a plugin is declared by adding a @Plugin annotation to the class declaration. During
initialization the Configuration will invoke the PluginManager to load the built-in Log4j plugins as
well as any custom plugins. The PluginManager locates plugins by looking in five places:
1. Serialized plugin listing files on the classpath. These files are generated automatically during the
build (more details below).
2. (OSGi only) Serialized plugin listing files in each active OSGi bundle. A BundleListener is
added on activation to continue checking new bundles after log4j-core has started.
3. A comma-separated list of packages specified by the log4j.plugin.packages system
property.
4. Packages passed to the static PluginManager.addPackages method (before Log4j
configuration occurs).
5. The packages declared in your log4j2 configuration file.
If multiple Plugins specify the same (case-insensitive) name, then the load order above determines
which one will be used. For example, to override the File plugin which is provided by the built-
in FileAppender class, you would need to place your plugin in a JAR file in the CLASSPATH
ahead of log4j-core.jar. This is not recommended; plugin name collisions will cause a warning
to be emitted. Note that in an OSGi environment, the order that bundles are scanned for plugins
generally follows the same order that bundles were installed into the framework. See getBundles()
and SynchronousBundleListener. In short, name collisions are even more unpredictable in an OSGi
environment.
Serialized plugin listing files are generated by an annotation processor contained in the log4j-
core artifact which will automatically scan your code for Log4j 2 plugins and output a metadata
file in your processed classes. There is nothing extra that needs to be done to enable this; the
Java compiler will automatically pick up the annotation processor on the class path unless you
explicitly disable it. In that case, it would be important to add another compiler pass to your build
process that only handles annotation processing using the Log4j 2 annotation processor class,
org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor. To
do this using Apache Maven, add the following execution to your maven-compiler-plugin (version 2.2
or higher) build plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<executions>
<execution>
<id>log4j-plugin-processor</id>
<goals>
<goal>compile</goal>
</goals>
<phase>process-classes</phase>
<configuration>
<proc>only</proc>
<annotationProcessors>
<annotationProcessor>org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor</annota
</annotationProcessors>
</configuration>
</execution>
</executions>
</plugin>
As the configuration is processed the appropriate plugins will be automatically configured and
initialized. Log4j 2 utilizes a few different categories of plugins which are described in the following
sections.
7.1.2 Core
Core plugins are those that are directly represented by an element in a configuration file, such as an
Appender, Layout, Logger or Filter. Custom plugins that conform to the rules laid out in the next
paragraph may simply be referenced in the configuration, provided they are appropriate configured to
be loaded by the PluginManager.
Every Core plugin must declare a static method annotated with @PluginFactory or
@PluginBuilderFactory. The former is used for static factory methods that provide all options
as method parameters, and the latter is used to construct a new Builder<T> class whose fields
are used for injecting attributes and child nodes. To allow the Configuration to pass the correct
parameters to the method, every parameter to the method must be annotated as one of the following
attribute types. Each attribute or element annotation must include the name that must be present in the
configuration in order to match the configuration item to its respective parameter. For plugin builders,
the names of the fields will be used by default if no name is specified in the annotation. There are
dozens of plugins in Log4j Core that can be used as examples for more complex scenarios including
hierarchical builder classes (e.g., see FileAppender). See Extending Log4j with Plugin Builders for
more details.
PluginElement
The parameter may represent a complex object that itself has parameters that can be
configured. This also supports injecting an array of elements.
PluginConfiguration
The current Configuration object will be passed to the plugin as a parameter.
PluginNode
The current Node being parsed will be passed to the plugin as a parameter.
PluginValue
The value of the current Node or its attribute named value.
7.1.3 Converters
Converters are used by PatternLayout to render the elements identified by the conversion pattern.
Every converter must specify its category as "Converter" on the @Plugin annotation, have a static
newInstance method that accepts an array of Strings as its only parameter and returns an instance
of the Converter, and must have a @ConverterKeys annotation present that contains the array of
converter patterns that will cause the Converter to be selected. Converters that are meant to handle
LogEvents must extend the LogEventPatternConverter class and must implement a format method
that accepts a LogEvent and a StringBuilder as arguments. The Converter should append the
result of its operation to the StringBuilder.
A second type of Converter is the FileConverter - which must have "FileConverter" specified in the
category attribute of the @Plugin annotation. While similar to a LogEventPatternConverter,
instead of a single format method these Converters will have two variations; one that takes an Object
and one that takes an array of Objects instead of the LogEvent. Both append to the provided
StringBuilder in the same fashion as a LogEventPatternConverter. These Converters are
typically used by the RollingFileAppender to construct the name of the file to log to.
If multiple Converters specify the same ConverterKeys, then the load order above determines
which one will be used. For example, to override the %date converter which is provided by the
built-in DatePatternConverter class, you would need to place your plugin in a JAR file in
7.1.4 KeyProviders
Some components within Log4j may provide the ability to perform data encryption. These
components require a secret key to perform the encryption. Applications may provide the key by
creating a class that implements the SecretKeyProvider interface.
7.1.5 Lookups
Lookups are perhaps the simplest plugins of all. They must declare their type as "Lookup" on the
plugin annotation and must implement the StrLookup interface. They will have two methods; a
lookup method that accepts a String key and returns a String value and a second lookup method
that accepts both a LogEvent and a String key and returns a String. Lookups may be referenced by
specifying ${name:key} where name is the name specified in the Plugin annotation and key is the
name of the item to locate.
7.1.6 TypeConverters
TypeConverters are a sort of meta-plugin used for converting strings into other types in a plugin
factory method parameter. Other plugins can already be injected via the @PluginElement
annotation; now, any type supported by the type conversion system can be used in a
@PluginAttribute parameter. Conversion of enum types are supported on demand and do
not require custom TypeConverter classes. A large number of built-in Java classes are already
supported; see TypeConverters for a more exhaustive listing.
Unlike other plugins, the plugin name of a TypeConverter is purely cosmetic. Appropriate type
converters are looked up via the Type interface rather than via Class<?> objects only. Do note that
TypeConverter plugins must have a default constructor. When multiple converters match for a type,
the first will be returned. If any extends from Comparable<TypeConverter<?>>, it will be used
for determining the order.
If a plugin class implements Collection or Map, then no factory method is used. Instead, the class
is instantiated using the default constructor, and all child configuration nodes are added to the
Collection or Map.
8 Lookups
.......................................................................................................................................
8.1 Lookups
Lookups provide a way to add values to the Log4j configuration at arbitrary places. They are a
particular type of Plugin that implements the StrLookup interface. Information on how to use
Lookups in configuration files can be found in the Property Substitution section of the Configuration
page.
8.1.5 EventLookup
The EventLookup provides access to fields within the log event from the configuration.
Key Description
Exception Returns the simple class name of the Exception, if one
is included in the event.
Level Returns the logging Level of the event.
Logger Returns the name of the Logger.
Marker Returns the name of the Marker associated with the
log event, if one is present.
Message Returns the formatted Message string.
ThreadId Returns the thread id associated with the log event.
ThreadName Returns the name of the thread associate with the log
event.
Timestamp Returns the time in milliseconds when the event
occurred.
In this example the RoutingAppender picks a route based on the presence of a Marker named
"AUDIT" being present in the log event.
Key Description
For example:
import org.apache.logging.log4j.core.lookup.MainMapLookup;
Expression Result
${main:0} --file
${main:1} foo.txt
${main:2} --verbose
${main:3} -x
${main:4} bar
${main:\--file} foo.txt
${main:\-x} bar
${main:bar} null
${main:\--quiet:-true} true
Example usage:
<Routing name="Routing">
<Routes pattern="$${map:type}">
<Route>
<RollingFile name="Rolling-${map:type}" fileName="${filename}"
filePattern="target/rolling1/test1-${map:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
</Routes>
</Routing>
Configuration:
status: debug
Appenders:
Console:
RandomAccessFile:
- name: SQL_APPENDER
fileName: logs/sql.log
PatternLayout:
Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
- name: PAYLOAD_APPENDER
fileName: logs/payload.log
PatternLayout:
Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
- name: PERFORMANCE_APPENDER
fileName: logs/performance.log
PatternLayout:
Pattern: "%d{ISO8601_BASIC} %-5level %logger{1} %X %msg%n"
Routing:
name: ROUTING_APPENDER
Routes:
pattern: "$${marker:}"
Route:
- key: PERFORMANCE
ref: PERFORMANCE_APPENDER
- key: PAYLOAD
ref: PAYLOAD_APPENDER
- key: SQL
ref: SQL_APPENDER
Loggers:
Root:
level: trace
AppenderRef:
- ref: ROUTING_APPENDER
<Routing name="Routing">
<Routes pattern="$${sd:type}">
<Route>
<RollingFile name="Rolling-${sd:type}" fileName="${filename}"
filePattern="target/rolling1/test1-${sd:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
</Routes>
</Routing>
<Appenders>
<File name="ApplicationLog" fileName="${sys:logPath}/app.log"/>
</Appenders>
This lookup also supports default value syntax. In the sample below, when the logPath system
property is undefined, the default value /var/logs is used:
<Appenders>
<File name="ApplicationLog" fileName="${sys:logPath:-/var/logs}/app.log"/>
</Appenders>
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.
Any other key names specified will first be checked to see if a ServletContext attribute exists with that
name and then will be checked to see if an initialization parameter of that name exists. If the key is
located then the corresponding value will be returned.
<Appenders>
<File name="ApplicationLog" fileName="${web:rootDir}/app.log"/>
</Appenders>
9 Appenders
.......................................................................................................................................
9.1 Appenders
Appenders are responsible for delivering LogEvents to their destination. Every Appender must
implement the Appender interface. Most Appenders will extend AbstractAppender which
adds Lifecycle and Filterable support. Lifecycle allows components to finish initialization after
configuration has completed and to perform cleanup during shutdown. Filterable allows the
component to have Filters attached to it which are evaluated during event processing.
Appenders usually are only responsible for writing the event data to the target destination. In most
cases they delegate responsibility for formatting the event to a layout. Some appenders wrap other
appenders so that they can modify the LogEvent, handle a failure in an Appender, route the event to a
subordinate Appender based on advanced Filter criteria or provide similar functionality that does not
directly format the event for viewing.
Appenders always have a name so that they can be referenced from Loggers.
In the tables below, the "Type" column corresponds to the Java type expected. For non-JDK classes,
these should usually be in Log4j Core unless otherwise noted.
9.1.1 AsyncAppender
The AsyncAppender accepts references to other Appenders and causes LogEvents to be written to
them on a separate Thread. Note that exceptions while writing to those Appenders will be hidden from
the application. The AsyncAppender should be configured after the appenders it references to allow it
to shut down properly.
By default, AsyncAppender uses java.util.concurrent.ArrayBlockingQueue which does not require
any external libraries. Note that multi-threaded applications should exercise care when using
this appender as such: the blocking queue is susceptible to lock contention and our tests showed
performance may become worse when more threads are logging concurrently. Consider using lock-
free Async Loggers for optimal performance.
AsyncAppender Parameters
There are also a few system properties that can be used to maintain application throughput
even when the underlying appender cannot keep up with the logging rate and the queue is
filling up. See the details for system properties log4j2.AsyncQueueFullPolicy and
log4j2.DiscardThreshold.
A typical AsyncAppender configuration might look like:
<Configuration name="LinkedTransferQueueExample">
<Appenders>
<List name="List"/>
<Async name="Async" bufferSize="262144">
<AppenderRef ref="List"/>
<LinkedTransferQueue/>
</Async>
</Appenders>
<Loggers>
<Root>
<AppenderRef ref="Async"/>
</Root>
</Loggers>
</Configuration>
Log4j ships with the following implementations:
BlockingQueueFactory Implementations
9.1.2 CassandraAppender
The CassandraAppender writes its output to an Apache Cassandra database.
A keyspace and table must be configured ahead of time, and the columns of
that table are mapped in a configuration file. Each column can specify either a
StringLayout (e.g., a PatternLayout) along with an optional conversion type, or only
a conversion type for org.apache.logging.log4j.spi.ThreadContextMap or
org.apache.logging.log4j.spi.ThreadContextStack to store the MDC or NDC in a map
or list column respectively. A conversion type compatible with java.util.Date will use the log
event timestamp converted to that type (e.g., use java.util.Date to fill a timestamp column type
in Cassandra).
CassandraAppender Parameters
Here is an example CassandraAppender configuration:
<Configuration name="CassandraAppenderTest">
<Appenders>
<Cassandra name="Cassandra" clusterName="Test Cluster" keyspace="test" table="logs" bufferSize="10" batch
<SocketAddress host="localhost" port="9042"/>
<ColumnMapping name="id" pattern="%uuid{TIME}" type="java.util.UUID"/>
<ColumnMapping name="timeid" literal="now()"/>
<ColumnMapping name="message" pattern="%message"/>
<ColumnMapping name="level" pattern="%level"/>
<ColumnMapping name="marker" pattern="%marker"/>
<ColumnMapping name="logger" pattern="%logger"/>
<ColumnMapping name="timestamp" type="java.util.Date"/>
<ColumnMapping name="mdc" type="org.apache.logging.log4j.spi.ThreadContextMap"/>
<ColumnMapping name="ndc" type="org.apache.logging.log4j.spi.ThreadContextStack"/>
</Cassandra>
</Appenders>
<Loggers>
<Logger name="org.apache.logging.log4j.cassandra" level="DEBUG">
<AppenderRef ref="Cassandra"/>
</Logger>
<Root level="ERROR"/>
</Loggers>
</Configuration>
9.1.3 ConsoleAppender
As one might expect, the ConsoleAppender writes its output to either System.out or System.err with
System.out being the default target. A Layout must be provided to format the LogEvent.
ConsoleAppender Parameters
A typical Console configuration might look like:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
9.1.4 FailoverAppender
The FailoverAppender wraps a set of appenders. If the primary Appender fails the secondary
appenders will be tried in order until one succeeds or there are no more secondaries to try.
FailoverAppender Parameters
A Failover configuration might look like:
9.1.5 FileAppender
The FileAppender is an OutputStreamAppender that writes to the File named in the fileName
parameter. The FileAppender uses a FileManager (which extends OutputStreamManager) to
actually perform the file I/O. While FileAppenders from different Configurations cannot be shared,
the FileManagers can be if the Manager is accessible. For example, two web applications in a
servlet container can have their own configuration and safely write to the same file if Log4j is in a
ClassLoader that is common to both of them.
FileAppender Parameters
Here is a sample File configuration:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<File name="MyFile" fileName="logs/app.log">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
</File>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="MyFile"/>
</Root>
</Loggers>
</Configuration>
9.1.6 FlumeAppender
This is an optional component supplied in a separate jar.
Apache Flume is a distributed, reliable, and available system for efficiently collecting, aggregating,
and moving large amounts of log data from many different sources to a centralized data store. The
FlumeAppender takes LogEvents and sends them to a Flume agent as serialized Avro events for
consumption.
The Flume Appender supports three modes of operation.
1. It can act as a remote Flume client which sends Flume events via Avro to a Flume Agent
configured with an Avro Source.
2. It can act as an embedded Flume Agent where Flume events pass directly into Flume for
processing.
3. It can persist events to a local BerkeleyDB data store and then asynchronously send the events to
Flume, similar to the embedded Flume Agent but without most of the Flume dependencies.
Usage as an embedded agent will cause the messages to be directly passed to the Flume Channel and
then control will be immediately returned to the application. All interaction with remote agents will
occur asynchronously. Setting the "type" attribute to "Embedded" will force the use of the embedded
agent. In addition, configuring agent properties in the appender configuration will also cause the
embedded agent to be used.
FlumeAppender Parameters
A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
compresses the body, and formats the body using the RFC5424Layout:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Flume name="eventLogger" compress="true">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
</Flume>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="eventLogger"/>
</Root>
</Loggers>
</Configuration>
A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
compresses the body, formats the body using the RFC5424Layout, and persists encrypted events to
disk:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Flume name="eventLogger" compress="true" type="persistent" dataDir="./logData">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
<Property name="keyProvider">MySecretProvider</Property>
</Flume>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="eventLogger"/>
</Root>
</Loggers>
</Configuration>
A sample FlumeAppender configuration that is configured with a primary and a secondary agent,
compresses the body, formats the body using RFC5424Layout and passes the events to an embedded
Flume Agent.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Flume name="eventLogger" compress="true" type="Embedded">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
</Flume>
<Console name="STDOUT">
<PatternLayout pattern="%d [%p] %c %m%n"/>
</Console>
</Appenders>
<Loggers>
<Logger name="EventLogger" level="info">
<AppenderRef ref="eventLogger"/>
</Logger>
<Root level="warn">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
A sample FlumeAppender configuration that is configured with a primary and a secondary agent
using Flume configuration properties, compresses the body, formats the body using RFC5424Layout
and passes the events to an embedded Flume Agent.
9.1.7 JDBCAppender
The JDBCAppender writes log events to a relational database table using standard JDBC. It
can be configured to obtain JDBC connections using a JNDI DataSource or a custom factory
method. Whichever approach you take, it must be backed by a connection pool. Otherwise, logging
performance will suffer greatly. If batch statements are supported by the configured JDBC driver
and a bufferSize is configured to be a positive number, then log events will be batched. Note
that as of Log4j 2.8, there are two ways to configure log event to column mappings: the original
ColumnConfig style that only allows strings and timestamps, and the new ColumnMapping plugin
that uses Log4j's built-in type conversion to allow for more data types (this is the same plugin as in
the Cassandra Appender).
To get off the ground quickly during development, an alternative to using a connection source based
on JNDI is to use the non-pooling DriverManager connection source. This connection source uses a
JDBC connection string, a user name, and a password. Optionally, you can also use properties.
JDBCAppender Parameters
When configuring the JDBCAppender, you must specify a ConnectionSource implementation
from which the Appender gets JDBC connections. You must use exactly one of the following nested
elements:
DataSource Parameters
ConnectionFactory Parameters
DriverManager Parameters
Column Parameters
ColumnMapping Parameters
Here are a couple sample configurations for the JDBCAppender, as well as a sample factory
implementation that uses Commons Pooling and Commons DBCP to pool database connections:
package net.example.db;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;
private ConnectionFactory() {
Properties properties = new Properties();
properties.setProperty("user", "logging");
properties.setProperty("password", "abc123"); // or get properties from some configuration file
<Configuration status="debug">
<Appenders>
<Console name="STDOUT">
<PatternLayout pattern="%C{1.} %m %level MDC%X%n"/>
</Console>
<Jdbc name="databaseAppender" tableName="dsLogEntry" ignoreExceptions="false">
<DataSource jndiName="java:/comp/env/jdbc/TestDataSourceAppender" />
<ColumnMapping name="Id" />
<ColumnMapping name="ColumnA" />
<ColumnMapping name="ColumnB" />
<MessageLayout />
</Jdbc>
</Appenders>
<Loggers>
<Logger name="org.apache.logging.log4j.core.appender.db" level="debug" additivity="false">
<AppenderRef ref="databaseAppender" />
</Logger>
<Root level="fatal">
<AppenderRef ref="STDOUT"/>
</Root>
</Loggers>
</Configuration>
9.1.9 JPAAppender
As of Log4j 2.11.0, JPA support has moved from the existing module log4j-core to the new
module log4j-jpa.
The JPAAppender writes log events to a relational database table using the Java Persistence
API 2.1. It requires the API and a provider implementation be on the classpath. It also requires
a decorated entity configured to persist to the table desired. The entity should either extend
org.apache.logging.log4j.core.appender.db.jpa.BasicLogEventEntity
(if you mostly want to use the default mappings) and provide at least an @Id property, or
org.apache.logging.log4j.core.appender.db.jpa.AbstractLogEventWrapperEntity
(if you want to significantly customize the mappings). See the Javadoc for these two classes for
more information. You can also consult the source code of these two classes as an example of how to
implement the entity.
JPAAppender Parameters
Here is a sample configuration for the JPAAppender. The first XML sample is the Log4j
configuration file, the second is the persistence.xml file. EclipseLink is assumed here, but
any JPA 2.1 or higher provider will do. You should always create a separate persistence unit
for logging, for two reasons. First, <shared-cache-mode> must be set to "NONE," which is
usually not desired in normal JPA usage. Also, for performance reasons the logging entity should
be isolated in its own persistence unit away from all other entities and you should use a non-JTA
data source. Note that your persistence unit must also contain <class> elements for all of the
org.apache.logging.log4j.core.appender.db.jpa.converter converter classes.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="error">
<Appenders>
<JPA name="databaseAppender" persistenceUnitName="loggingPersistenceUnit"
entityClassName="com.example.logging.JpaLogEntity" />
</Appenders>
<Loggers>
<Root level="warn">
<AppenderRef ref="databaseAppender"/>
</Root>
</Loggers>
</Configuration>
</persistence>
package com.example.logging;
...
@Entity
@Table(name="application_log", schema="dbo")
public class JpaLogEntity extends BasicLogEventEntity {
private static final long serialVersionUID = 1L;
private long id = 0L;
public TestEntity() {
super(null);
}
public TestEntity(LogEvent wrappedEvent) {
super(wrappedEvent);
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
public long getId() {
return this.id;
}
package com.example.logging;
...
@Entity
@Table(name="application_log", schema="dbo")
public class JpaLogEntity extends AbstractLogEventWrapperEntity {
private static final long serialVersionUID = 1L;
private long id = 0L;
public TestEntity() {
super(null);
}
public TestEntity(LogEvent wrappedEvent) {
super(wrappedEvent);
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "logEventId")
public long getId() {
return this.id;
}
@Override
@Enumerated(EnumType.STRING)
@Column(name = "level")
public Level getLevel() {
return this.getWrappedEvent().getLevel();
}
@Override
@Column(name = "logger")
public String getLoggerName() {
return this.getWrappedEvent().getLoggerName();
}
@Override
@Column(name = "message")
@Convert(converter = MyMessageConverter.class)
public Message getMessage() {
return this.getWrappedEvent().getMessage();
}
...
}
9.1.10 HttpAppender
The HttpAppender sends log events over HTTP. A Layout must be provided to format the LogEvent.
Will set the Content-Type header according to the layout. Additional headers can be specified with
embedded Property elements.
Will wait for response from server, and throw error if no 2xx response is received.
Implemented with HttpURLConnection.
HttpAppender Parameters
Here is a sample HttpAppender configuration snippet:
9.1.11 KafkaAppender
The KafkaAppender logs events to an Apache Kafka topic. Each log event is sent as a Kafka record.
KafkaAppender Parameters
Here is a sample KafkaAppender configuration snippet:
<?xml version="1.0" encoding="UTF-8"?>
...
<Appenders>
<Kafka name="Kafka" topic="log-test">
<PatternLayout pattern="%date %message"/>
<Property name="bootstrap.servers">localhost:9092</Property>
</Kafka>
</Appenders>
This appender is synchronous by default and will block until the record has been acknowledged by
the Kafka server, timeout for this can be set with the timeout.ms property (defaults to 30 seconds).
Wrap with Async appender and/or set syncSend to false to log asynchronously.
This appender requires the Kafka client library. Note that you need to use a version of the Kafka
client library matching the Kafka server used.
Note:Make sure to not let org.apache.kafka log to a Kafka appender on DEBUG level, since that
will cause recursive logging:
<?xml version="1.0" encoding="UTF-8"?>
...
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Kafka"/>
</Root>
<Logger name="org.apache.kafka" level="INFO" /> <!-- avoid recursive logging -->
</Loggers>
9.1.12 MemoryMappedFileAppender
New since 2.1. Be aware that this is a new addition, and although it has been tested on several
platforms, it does not have as much track record as the other file appenders.
The MemoryMappedFileAppender maps a part of the specified file into memory and writes log
events to this memory, relying on the operating system's virtual memory manager to synchronize the
changes to the storage device. The main benefit of using memory mapped files is I/O performance.
Instead of making system calls to write to disk, this appender can simply change the program's
local memory, which is orders of magnitude faster. Also, in most operating systems the memory
region mapped actually is the kernel's page cache (file cache), meaning that no copies need to be
created in user space. (TODO: performance tests that compare performance of this appender to
RandomAccessFileAppender and FileAppender.)
There is some overhead with mapping a file region into memory, especially very large regions (half
a gigabyte or more). The default region size is 32 MB, which should strike a reasonable balance
between the frequency and the duration of remap operations. (TODO: performance test remapping
various sizes.)
Similar to the FileAppender and the RandomAccessFileAppender, MemoryMappedFileAppender uses
a MemoryMappedFileManager to actually perform the file I/O. While MemoryMappedFileAppender
from different Configurations cannot be shared, the MemoryMappedFileManagers can be if the
Manager is accessible. For example, two web applications in a servlet container can have their own
configuration and safely write to the same file if Log4j is in a ClassLoader that is common to both of
them.
MemoryMappedFileAppender Parameters
9.1.13 NoSQLAppender
The NoSQLAppender writes log events to a NoSQL database using an internal lightweight provider
interface. Provider implementations currently exist for MongoDB and Apache CouchDB, and writing
a custom provider is quite simple.
NoSQLAppender Parameters
You specify which NoSQL provider to use by specifying the appropriate configuration element within
the <NoSql> element. The types currently supported are <MongoDb> and <CouchDb>. To create
your own custom provider, read the JavaDoc for the NoSQLProvider, NoSQLConnection, and
NoSQLObject classes and the documentation about creating Log4j plugins. We recommend you
review the source code for the MongoDB and CouchDB providers as a guide for creating your own
provider.
The following example demonstrates how log events are persisted in NoSQL databases if represented
in a JSON format:
{
"level": "WARN",
"loggerName": "com.example.application.MyClass",
"message": "Something happened that you might want to know about.",
"source": {
"className": "com.example.application.MyClass",
"methodName": "exampleMethod",
"fileName": "MyClass.java",
"lineNumber": 81
},
"marker": {
"name": "SomeMarker",
"parent" {
"name": "SomeParentMarker"
}
},
"threadName": "Thread-1",
"millis": 1368844166761,
"date": "2013-05-18T02:29:26.761Z",
"thrown": {
"type": "java.sql.SQLException",
"message": "Could not insert record. Connection lost.",
"stackTrace": [
{ "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "file
{ "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fi
{ "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName":
{ "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainCl
],
"cause": {
"type": "java.io.IOException",
"message": "Connection lost.",
"stackTrace": [
{ "className": "java.nio.channels.SocketChannel", "methodName": "write", "fileName": null, "l
{ "className": "org.example.sql.driver.PreparedStatement$1", "methodName": "responder", "file
{ "className": "org.example.sql.driver.PreparedStatement", "methodName": "executeUpdate", "fi
{ "className": "com.example.application.MyClass", "methodName": "exampleMethod", "fileName":
{ "className": "com.example.application.MainClass", "methodName": "main", "fileName": "MainCl
]
}
},
"contextMap": {
"ID": "86c3a497-4e67-4eed-9d6a-2e5797324d7b",
"username": "JohnDoe"
},
"contextStack": [
"topItem",
"anotherItem",
"bottomItem"
]
}
9.1.18 OutputStreamAppender
The OutputStreamAppender provides the base for many of the other Appenders such as the File
and Socket appenders that write the event to an Output Stream. It cannot be directly configured.
Support for immediateFlush and buffering is provided by the OutputStreamAppender. The
OutputStreamAppender uses an OutputStreamManager to handle the actual I/O, allowing the stream
to be shared by Appenders in multiple configurations.
9.1.19 RandomAccessFileAppender
The RandomAccessFileAppender is similar to the standard FileAppender except it is always
buffered (this cannot be switched off) and internally it uses a ByteBuffer + RandomAccessFile
instead of a BufferedOutputStream. We saw a 20-200% performance improvement compared
to FileAppender with "bufferedIO=true" in our measurements. Similar to the FileAppender,
RandomAccessFileAppender uses a RandomAccessFileManager to actually perform the file
I/O. While RandomAccessFileAppender from different Configurations cannot be shared, the
RandomAccessFileManagers can be if the Manager is accessible. For example, two web applications
in a servlet container can have their own configuration and safely write to the same file if Log4j is in a
ClassLoader that is common to both of them.
RandomAccessFileAppender Parameters
Here is a sample RandomAccessFile configuration:
9.1.20 RewriteAppender
The RewriteAppender allows the LogEvent to manipulated before it is processed by another
Appender. This can be used to mask sensitive information such as passwords or to inject
information into each event. The RewriteAppender must be configured with a RewritePolicy. The
RewriteAppender should be configured after any Appenders it references to allow it to shut down
properly.
RewriteAppender Parameters
9.1.20.1 RewritePolicy
RewritePolicy is an interface that allows implementations to inspect and possibly modify LogEvents
before they are passed to Appender. RewritePolicy declares a single method named rewrite that must
be implemented. The method is passed the LogEvent and can return the same event or create a new
one.
9.MapRewritePolicy
MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will add or update
elements of the Map.
The following configuration shows a RewriteAppender configured to add a product key and its value
to the MapMessage.:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT">
<PatternLayout pattern="%m%n"/>
</Console>
<Rewrite name="rewrite">
<AppenderRef ref="STDOUT"/>
<MapRewritePolicy mode="Add">
<KeyValuePair key="product" value="TestProduct"/>
</MapRewritePolicy>
</Rewrite>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Rewrite"/>
</Root>
</Loggers>
</Configuration>
9.PropertiesRewritePolicy
PropertiesRewritePolicy will add properties configured on the policy to the ThreadContext Map being
logged. The properties will not be added to the actual ThreadContext Map. The property values may
contain variables that will be evaluated when the configuration is processed as well as when the event
is logged.
The following configuration shows a RewriteAppender configured to add a product key and its value
to the MapMessage:
9.LoggerNameLevelRewritePolicy
You can use this policy to make loggers in third party code less chatty by changing event levels. The
LoggerNameLevelRewritePolicy will rewrite log event levels for a given logger name prefix. You
configure a LoggerNameLevelRewritePolicy with a logger name prefix and a pairs of levels, where a
pair defines a source level and a target level.
The following configuration shows a RewriteAppender configured to map level INFO to DEBUG and
level WARN to INFO for all loggers that start with com.foo.bar.
9.1.21 RollingFileAppender
The RollingFileAppender is an OutputStreamAppender that writes to the File named in the fileName
parameter and rolls the file over according the TriggeringPolicy and the RolloverPolicy. The
RollingFileAppender uses a RollingFileManager (which extends OutputStreamManager) to
actually perform the file I/O and perform the rollover. While RolloverFileAppenders from different
Configurations cannot be shared, the RollingFileManagers can be if the Manager is accessible. For
example, two web applications in a servlet container can have their own configuration and safely
write to the same file if Log4j is in a ClassLoader that is common to both of them.
A RollingFileAppender requires a TriggeringPolicy and a RolloverStrategy. The triggering
policy determines if a rollover should be performed while the RolloverStrategy defines how
the rollover should be done. If no RolloverStrategy is configured, RollingFileAppender will
use the DefaultRolloverStrategy. Since log4j-2.5, a custom delete action can be configured
in the DefaultRolloverStrategy to run at rollover. Since 2.8 if no file name is configured then
DirectWriteRolloverStrategy will be used instead of DefaultRolloverStrategy. Since log4j-2.9, a
custom POSIX file attribute view action can be configured in the DefaultRolloverStrategy to run at
rollover, if not defined, inherited POSIX file attribute view from the RollingFileAppender will be
applied.
File locking is not supported by the RollingFileAppender.
RollingFileAppender Parameters
CronTriggeringPolicy Parameters
9.OnStartup Triggering Policy
The OnStartupTriggeringPolicy policy causes a rollover if the log file is older than the current
JVM's start time and the minimum file size is met or exceeded.
OnStartupTriggeringPolicy Parameters
Google App Engine note:
When running in Google App Engine, the OnStartup policy causes a rollover if
the log file is older than the time when Log4J initialized. (Google App Engine
restricts access to certain classes so Log4J cannot determine JVM start time with
java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime() and
falls back to Log4J initialization time instead.)
9.SizeBased Triggering Policy
The SizeBasedTriggeringPolicy causes a rollover once the file has reached the specified size.
The size can be specified in bytes, with the suffix KB, MB or GB, for example 20MB. The size may
also contain a fractional value such as 1.5 MB. The size is evaluated using the Java root Locale so
a period must always be used for the fractional unit. When combined with a time based triggering
policy the file pattern must contain a %i otherwise the target file will be overwritten on every rollover
as the SizeBased Triggering Policy will not cause the timestamp value in the file name to change.
When used without a time based triggering policy the SizeBased Triggering Policy will cause the
timestamp value to change.
9.TimeBased Triggering Policy
The TimeBasedTriggeringPolicy causes a rollover once the date/time pattern no longer applies
to the active file. This policy accepts an interval attribute which indicates how frequently the
rollover should occur based on the time pattern and a modulate boolean attribute.
TimeBasedTriggeringPolicy Parameters
The default rollover strategy supports three variations for incrementing the counter. To illustrate
how it works, suppose that the min attribute is set to 1, the max attribute is set to 3, the file name is
"foo.log", and the file name pattern is "foo-%i.log".
By way of contrast, when the fileIndex attribute is set to "min" but all the other settings are the same
the "fixed window" strategy will be performed.
Finally, as of release 2.8, if the fileIndex attribute is set to "nomax" then the min and max values
will be ignored and file numbering will increment by 1 and each rollover will have an incrementally
higher value with no maximum number of files.
DefaultRolloverStrategy Parameters
causes multiple files to be written during the specified time period they will be numbered starting at
one and continually incremented until a time-based rollover occurs.
Warning: If the file pattern has a suffix indicating compression should take place the current file will
not be compressed when the application is shut down. Furthermore, if the time changes such that the
file pattern no longer matches the current file it will not be compressed at startup either.
DirectWriteRolloverStrategy Parameters
Below is a sample configuration that uses a RollingFileAppender with both the time and size based
triggering policies, will create up to 7 archives on the same day (1-7) that are stored in a directory
based on the current year and month, and will compress each archive using gzip:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<SizeBasedTriggeringPolicy size="250 MB"/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
This second example shows a rollover strategy that will keep up to 20 files before removing them.
Delete Parameters
year and month. All files under the base directory that match the "*/app-*.log.gz" glob and are 60
days old or older are deleted at rollover time.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy>
<Delete basePath="${baseDir}" maxDepth="2">
<IfFileName glob="*/app-*.log.gz" />
<IfLastModified age="P60D" />
</Delete>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
Below is a sample configuration that uses a RollingFileAppender with both the time and size based
triggering policies, will create up to 100 archives on the same day (1-100) that are stored in a
directory based on the current year and month, and will compress each archive using gzip and will
roll every hour. During every rollover, this configuration will delete files that match "*/app-*.log.gz"
and are 30 days old or older, but keep the most recent 100 GB or the most recent 10 files, whichever
comes first.
ScriptCondition Parameters
Script Parameters
Below is a sample configuration that uses a RollingFileAppender with the cron triggering policy
configured to trigger every day at midnight. Archives are stored in a directory based on the current
year and month. The script returns a list of rolled over files under the base directory dated Friday the
13th. The Delete action will delete all files returned by the script.
9.Log Archive File Attribute View Policy: Custom file attribute on Rollover
Log4j-2.9 introduces a PosixViewAttribute action that gives users more control over which file
attribute permissions, owner and group should be applied. The PosixViewAttribute action lets users
configure one or more conditions that select the eligible files relative to a base directory.
PosixViewAttribute Parameters
Below is a sample configuration that uses a RollingFileAppender and defines different POSIX file
attribute view for current and rolled log files.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="trace" name="MyApp" packages="">
<Properties>
<Property name="baseDir">logs</Property>
</Properties>
<Appenders>
<RollingFile name="RollingFile" fileName="${baseDir}/app.log"
filePattern="${baseDir}/$${date:yyyy-MM}/app-%d{yyyyMMdd}.log.gz"
filePermissions="rw-------">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
<CronTriggeringPolicy schedule="0 0 0 * * ?"/>
<DefaultRolloverStrategy stopCustomActionsOnError="true">
<PosixViewAttribute basePath="${baseDir}/$${date:yyyy-MM}" filePermissions="r--r--r--">
<IfFileName glob="*.gz" />
</PosixViewAttribute>
</DefaultRolloverStrategy>
</RollingFile>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="RollingFile"/>
</Root>
</Loggers>
</Configuration>
9.1.22 RollingRandomAccessFileAppender
The RollingRandomAccessFileAppender is similar to the standard RollingFileAppender except
it is always buffered (this cannot be switched off) and internally it uses a ByteBuffer +
RandomAccessFile instead of a BufferedOutputStream. We saw a 20-200% performance
improvement compared to RollingFileAppender with "bufferedIO=true" in our measurements. The
RollingRandomAccessFileAppender writes to the File named in the fileName parameter and rolls the
file over according the TriggeringPolicy and the RolloverPolicy. Similar to the RollingFileAppender,
RollingRandomAccessFileAppender uses a RollingRandomAccessFileManager to actually perform
the file I/O and perform the rollover. While RollingRandomAccessFileAppender from different
Configurations cannot be shared, the RollingRandomAccessFileManagers can be if the Manager is
accessible. For example, two web applications in a servlet container can have their own configuration
and safely write to the same file if Log4j is in a ClassLoader that is common to both of them.
RollingRandomAccessFileAppender Parameters
9.1.23 RoutingAppender
The RoutingAppender evaluates LogEvents and then routes them to a subordinate Appender. The
target Appender may be an appender previously configured and may be referenced by its name or the
Appender can be dynamically created as needed. The RoutingAppender should be configured after
any Appenders it references to allow it to shut down properly.
You can also configure a RoutingAppender with scripts: you can run a script when the appender starts
and when a route is chosen for an log event.
Parameter
Name Type Description
configurationConfiguration
The
active
Configuration.
staticVariables
Map A Map
shared
between
all script
invocations
for this
appender
instance.
This is
the same
map
passed
to the
Routes
Script.
RoutingAppender
Script Parameters
ignoreExceptions boolean The default is true, causing
exceptions encountered while
appending events to be internally
logged and then ignored. When
set to false exceptions will be
propagated to the caller, instead.
You must set this to false when
wrapping this Appender in a
FailoverAppender.
RoutingAppender Parameters
In this example, the script causes the "ServiceWindows" route to be the default route on Windows
and "ServiceOther" on all other operating systems. Note that the List Appender is one of our test
appenders, any appender can be used, it is only used as a shorthand.
9.1.23.1 Routes
The Routes element accepts a single attribute named "pattern". The pattern is evaluated against all
the registered Lookups and the result is used to select a Route. Each Route may be configured with a
key. If the key matches the result of evaluating the pattern then that Route will be selected. If no key
is specified on a Route then that Route is the default. Only one Route can be configured as the default.
The Routes element may contain a Script child element. If specified, the Script is run for each log
event and returns the String Route key to use.
You must specify either the pattern attribute or the Script element, but not both.
Each Route must reference an Appender. If the Route contains a ref attribute then the Route will
reference an Appender that was defined in the configuration. If the Route contains an Appender
definition then an Appender will be created within the context of the RoutingAppender and will be
reused each time a matching Appender name is referenced through a Route.
This script is passed the following variables:
In this example, the script runs for each log event and picks a route based on the presence of a Marker
named "AUDIT".
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" name="RoutingTest">
<Appenders>
<Console name="STDOUT" target="SYSTEM_OUT" />
<Flume name="AuditLogger" compress="true">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
</Flume>
<Routing name="Routing">
<Routes>
<Script name="RoutingInit" language="JavaScript"><![CDATA[
if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("AUDIT")) {
return "AUDIT";
} else if (logEvent.getContextMap().containsKey("UserId")) {
return logEvent.getContextMap().get("UserId");
}
return "STDOUT";]]>
</Script>
<Route>
<RollingFile
name="Rolling-${mdc:UserId}"
fileName="${mdc:UserId}.log"
filePattern="${mdc:UserId}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
<Route ref="AuditLogger" key="AUDIT"/>
<Route ref="STDOUT" key="STDOUT"/>
</Routes>
<IdlePurgePolicy timeToLive="15" timeUnit="minutes"/>
</Routing>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Routing" />
</Root>
</Loggers>
</Configuration>
should survive without having any events sent to it, and timeUnit, the String representation of
java.util.concurrent.TimeUnit which is used with the timeToLive attribute.
Below is a sample configuration that uses a RoutingAppender to route all Audit events to a
FlumeAppender and all other events will be routed to a RollingFileAppender that captures only the
specific event type. Note that the AuditAppender was predefined while the RollingFileAppenders are
created as needed.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Flume name="AuditLogger" compress="true">
<Agent host="192.168.10.101" port="8800"/>
<Agent host="192.168.10.102" port="8800"/>
<RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/>
</Flume>
<Routing name="Routing">
<Routes pattern="$${sd:type}">
<Route>
<RollingFile name="Rolling-${sd:type}" fileName="${sd:type}.log"
filePattern="${sd:type}.%i.log.gz">
<PatternLayout>
<pattern>%d %p %c{1.} [%t] %m%n</pattern>
</PatternLayout>
<SizeBasedTriggeringPolicy size="500" />
</RollingFile>
</Route>
<Route ref="AuditLogger" key="Audit"/>
</Routes>
<IdlePurgePolicy timeToLive="15" timeUnit="minutes"/>
</Routing>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Routing"/>
</Root>
</Loggers>
</Configuration>
9.1.24 SMTPAppender
Sends an e-mail when a specific logging event occurs, typically on errors or fatal errors.
The number of logging events delivered in this e-mail depend on the value of BufferSize option.
The SMTPAppender keeps only the last BufferSize logging events in its cyclic buffer. This keeps
memory requirements at a reasonable level while still delivering useful application context. All events
in the buffer are included in the email. The buffer will contain the most recent events of level TRACE
to WARN preceding the event that triggered the email.
The default behavior is to trigger sending an email whenever an ERROR or higher severity event
is logged and to format it as HTML. The circumstances on when the email is sent can be controlled
by setting one or more filters on the Appender. As with other Appenders, the formatting can be
controlled by specifying a Layout for the Appender.
SMTPAppender Parameters
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<SMTP name="Mail" subject="Error Log" to="errors@logging.apache.org" from="test@logging.apache.org"
smtpHost="localhost" smtpPort="25" bufferSize="50">
</SMTP>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="Mail"/>
</Root>
</Loggers>
</Configuration>
9.1.25 ScriptAppenderSelector
When the configuration is built, the ScriptAppenderSelector appender calls a Script
to compute an appender name. Log4j then creates one of the appender named listed under
AppenderSet using the name of the ScriptAppenderSelector. After configuration, Log4j
ignores the ScriptAppenderSelector. Log4j only builds the one selected appender from the
configuration tree, and ignores other AppenderSet child nodes.
In the following example, the script returns the name "List2". The appender name is recorded under
the name of the ScriptAppenderSelector, not the name of the selected appender, in this example,
"SelectIt".
<Configuration status="WARN" name="ScriptAppenderSelectorExample">
<Appenders>
<ScriptAppenderSelector name="SelectIt">
<Script language="JavaScript"><![CDATA[
java.lang.System.getProperty("os.name").search("Windows") > -1 ? "MyCustomWindowsAppender" : "MySyslo
</Script>
<AppenderSet>
<MyCustomWindowsAppender name="MyAppender" ... />
<SyslogAppender name="MySyslog" ... />
</AppenderSet>
</ScriptAppenderSelector>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="SelectIt" />
</Root>
</Loggers>
</Configuration>
9.1.26 SocketAppender
The SocketAppender is an OutputStreamAppender that writes its output to a remote destination
specified by a host and port. The data can be sent over either TCP or UDP and can be sent in any
format. You can optionally secure communication with SSL. Note that the TCP and SSL variants
write to the socket as a stream and do not expect response from the target destination. Due to
limitations in the TCP protocol that means that when the target server closes its connection some log
events may continue to appear to succeed until a closed connection exception is raised, causing those
events to be lost. If guaranteed delivery is required a protocol that requires acknowledgements must
be used.
SocketAppender Parameters
This is an unsecured TCP configuration:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Socket name="socket" host="localhost" port="9500">
<JsonLayout properties="true"/>
</Socket>
</Appenders>
<Loggers>
<Root level="error">
<AppenderRef ref="socket"/>
</Root>
</Loggers>
</Configuration>
This is a secured SSL configuration:
9.1.27.1 KeyStore
The keystore is meant to contain your private keys and certificates, and determines which
authentication credentials to send to the remote host.
9.1.27.2 TrustStore
The trust store is meant to contain the CA certificates you are willing to trust when a remote party
presents its certificate. Determines whether the remote authentication credentials (and thus the
connection) should be trusted.
In some cases, they can be one and the same store, although it is often better practice to use distinct
stores (especially when they are file-based).
9.1.27.3 Example
...
<SSL>
<KeyStore location="log4j2-keystore.jks" passwordEnvironmentVariable="KEYSTORE_PASSWORD"/>
<TrustStore location="truststore.jks" passwordFile="${sys:user.home}/truststore.pwd"/>
</SSL>
...
9.1.28 SyslogAppender
The SyslogAppender is a SocketAppender that writes its output to a remote destination specified
by a host and port in a format that conforms with either the BSD Syslog format or the RFC 5424
format. The data can be sent over either TCP or UDP.
SyslogAppender Parameters
A sample syslogAppender configuration that is configured with two SyslogAppenders, one using
the BSD format and one using RFC 5424.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
<Syslog name="bsd" host="localhost" port="514" protocol="TCP"/>
<Syslog name="RFC5424" format="RFC5424" host="localhost" port="8514"
protocol="TCP" appName="MyApp" includeMDC="true"
facility="LOCAL0" enterpriseNumber="18060" newLine="true"
messageId="Audit" id="App"/>
</Appenders>
<Loggers>
<Logger name="com.mycorp" level="error">
<AppenderRef ref="RFC5424"/>
</Logger>
<Root level="error">
<AppenderRef ref="bsd"/>
</Root>
</Loggers>
</Configuration>
For SSL this appender writes its output to a remote destination specified by a host and port over SSL
in a format that conforms with either the BSD Syslog format or the RFC 5424 format.
JeroMQ Parameters
10 Layouts
.......................................................................................................................................
10.1 Layouts
An Appender uses a Layout to format a LogEvent into a form that meets the needs of whatever will
be consuming the log event. In Log4j 1.x and Logback Layouts were expected to transform an event
into a String. In Log4j 2 Layouts return a byte array. This allows the result of the Layout to be useful
in many more types of Appenders. However, this means you need to configure most Layouts with a
Charset to ensure the byte array contains correct values.
The root class for layouts that use a Charset is
org.apache.logging.log4j.core.layout.AbstractStringLayout where the default is
UTF-8. Each layout that extends AbstractStringLayout can provide its own default. See each
layout below.
A custom character encoder was added to Log4j 2.4.1 for the ISO-8859-1 and US-ASCII charsets,
to bring some of the performance improvements built-in to Java 8 to Log4j for use on Java 7. For
applications that log only ISO-8859-1 characters, specifying this charset will improve performance
significantly.
The layouts CsvParameterLayout and CsvLogEventLayout are configured with the following
parameters:
1. Time Nanos
2. Time Millis
3. Level
4. Thread ID
5. Thread Name
6. Thread Priority
7. Formatted Message
8. Logger FQCN
9. Logger Name
10.Marker
11.Thrown Proxy
12.Source
13.Context Map
14.Context Stack
<Appenders>
<Socket name="Graylog" protocol="udp" host="graylog.domain.com" port="12201">
<GelfLayout host="someserver" compressionType="ZLIB" compressionThreshold="1024"/>
</Socket>
</Appenders>
<Appenders>
<Socket name="Graylog" protocol="tcp" host="graylog.domain.com" port="12201">
<GelfLayout host="someserver" compressionType="OFF" includeNullDelimiter="true"/>
</Socket>
</Appenders>
GelfLayout Parameters
To include any custom field in the output, use following syntax:
Custom fields are included in the order they are declared. The values support lookups.
See also:
HtmlLayout Parameters
Configure as follows to use dataPattern and timezone in HtmlLayout:
<Appenders>
<Console name="console">
<HtmlLayout datePattern="ISO8601" timezone="GMT+0"/>
</Console>
</Appenders>
{
"instant" : {
"epochSecond" : 1493121664,
"nanoOfSecond" : 118000000
},
"thread" : "main",
"level" : "INFO",
"loggerName" : "HelloWorld",
"marker" : {
"name" : "child",
"parents" : [ {
"name" : "parent",
"parents" : [ {
"name" : "grandparent"
} ]
} ]
},
"message" : "Hello, world!",
"thrown" : {
"commonElementCount" : 0,
"message" : "error message",
"name" : "java.lang.RuntimeException",
"extendedStackTrace" : [ {
"class" : "logtest.Main",
"method" : "main",
"file" : "Main.java",
"line" : 29,
"exact" : true,
"location" : "classes/",
"version" : "?"
} ]
},
"contextStack" : [ "one", "two" ],
"endOfBatch" : false,
"loggerFqcn" : "org.apache.logging.log4j.spi.AbstractLogger",
"contextMap" : {
"bar" : "BAR",
"foo" : "FOO"
},
"threadId" : 1,
"threadPriority" : 5,
"source" : {
"class" : "logtest.Main",
"method" : "main",
"file" : "Main.java",
"line" : 29
}
}
If complete="false", the appender does not write the JSON open array character "[" at the start of
the document, "]" and the end, nor comma "," between records.
JsonLayout Parameters
To include any custom field in the output, use following syntax:
<JsonLayout>
<KeyValuePair key="additionalField1" value="constant value"/>
<KeyValuePair key="additionalField2" value="$${ctx:key}"/>
</JsonLayout>
Custom fields are always last, in the order they are declared. The values support lookups.
Additional runtime dependencies are required for using JsonLayout.
{
"mdc": {
"$resolver": "mdc"
},
"exception": {
"exception_class": {
"$resolver": "exception",
"field": "className"
},
"exception_message": {
"$resolver": "exception",
"field": "message"
},
"stacktrace": {
"$resolver": "exception",
"field": "stackTrace",
"stackTrace": {
"stringified": true
}
}
},
"line_number": {
"$resolver": "source",
"field": "lineNumber"
},
"class": {
"$resolver": "source",
"field": "className"
},
"@version": 1,
"source_host": "${hostName}",
"message": {
"$resolver": "message",
"stringified": true
},
"thread_name": {
"$resolver": "thread",
"field": "name"
},
"@timestamp": {
"$resolver": "timestamp"
},
"level": {
"$resolver": "level",
"field": "name"
},
"file": {
"$resolver": "source",
"field": "fileName"
},
"method": {
"$resolver": "source",
"field": "methodName"
},
"logger_name": {
"$resolver": "logger",
"field": "name"
©2021, The Apache Software Foundation • ALL RIGHTS RESERVED.
}
}
10 Layouts 199
<JsonTemplateLayout eventTemplateUri="classpath:LogstashJsonEventLayoutV1.json"/>
JSON Template Layout will render JSON documents as follows:
{
"exception": {
"exception_class": "java.lang.RuntimeException",
"exception_message": "test",
"stacktrace": "java.lang.RuntimeException: test\n\tat org.apache.logging.log4j.JsonTemplateLayoutDemo.mai
},
"line_number": 12,
"class": "org.apache.logging.log4j.JsonTemplateLayoutDemo",
"@version": 1,
"source_host": "varlik",
"message": "Hello, error!",
"thread_name": "main",
"@timestamp": "2017-05-25T19:56:23.370+02:00",
"level": "ERROR",
"file": "JsonTemplateLayoutDemo.java",
"method": "main",
"logger_name": "org.apache.logging.log4j.JsonTemplateLayoutDemo"
}
See JSON Template Layout page for the complete documentation.
Note that there is no explicit separator between text and conversion specifiers. The pattern parser
knows when it has reached the end of a conversion specifier when it reads a conversion character. In
the example above the conversion specifier %-5p means the priority of the logging event should be
left justified to a width of five characters.
If the pattern string does not contain a specifier to handle a Throwable being logged, parsing of
the pattern will act as if the "%xEx" specifier had be added to the end of the string. To suppress
formatting of the Throwable completely simply add "%ex{0}" as a specifier in the pattern string.
PatternLayout Parameters
RegexReplacement Parameters
10.1.6.1 Patterns
The conversions that are provided with Log4j are:
Conversion
Pattern Logger Name Result
%c{1} org.apache. Foo
commons.Foo
%c{2} org.apache. commons.Foo
commons.Foo
%c{10} org.apache. org.apache.
commons.Foo commons.Foo
%c{-1} org.apache. apache.
commons.Foo commons.Foo
%c{-2} org.apache. commons.Foo
commons.Foo
%c{-10} org.apache. org.apache.
commons.Foo commons.Foo
%c{1.} org.apache. o.a.c.Foo
commons.Foo
%c{1.1.~.~} org.apache. o.a.~.~.Foo
commons.test.
Foo
%c{.} org.apache. ....Foo
commons.test.
Foo
Pattern Example
%d{DEFAULT} 2012-11-02 14:34:02,123
%d{DEFAULT_MICROS} 2012-11-02
14:34:02,123456
%d{DEFAULT_NANOS} 2012-11-02
14:34:02,123456789
%d{ISO8601} 2012-11-02T14:34:02,781
%d{ISO8601_BASIC} 20121102T143402,781
%d{ISO8601_OFFSET_DATE_TIME_HH}
2012-11-02'T'14:34:02,781-07
%d{ISO8601_OFFSET_DATE_TIME_HHMM}
2012-11-02'T'14:34:02,781-0700
%d{ISO8601_OFFSET_DATE_TIME_HHCMM}
2012-11-02'T'14:34:02,781-07:00
%d{ABSOLUTE} 14:34:02,781
%d{ABSOLUTE_MICROS} 14:34:02,123456
%d{ABSOLUTE_NANOS} 14:34:02,123456789
%d{DATE} 02 Nov 2012
14:34:02,781
%d{COMPACT} 20121102143402781
%d{UNIX} 1351866842
%d{UNIX_MILLIS} 1351866842781
Pattern Example
%d{HH:mm:ss,SSS} 14:34:02,123
%d{HH:mm:ss,nnnn} to 14:34:02,1234 to
%d{HH:mm:ss,nnnnnnnnn} 14:34:02,123456789
%d{dd MMM yyyy 02 Nov 2012
HH:mm:ss,SSS} 14:34:02,123
%d{dd MMM yyyy 02 Nov 2012
HH:mm:ss,nnnn} to 14:34:02,1234
%d{dd MMM yyyy to 02 Nov 2012
HH:mm:ss,nnnnnnnnn} 14:34:02,123456789
%d{HH:mm:ss}{GMT+0} 18:34:02
Character Replacement
'\r', '\n' Converted into escaped
strings "\\r" and "\\n"
respectively
&, <, >, ", ', / Replaced with the
corresponding HTML
entity
Character Replacement
&, <, >, ", ' Replaced with the
corresponding XML
entity
Character Replacement
U+0000 - U+001F \u0000 - \u001F
Any other control Encoded into its
characters \uABCD equivalent
escaped code point
" \"
\ \\
Character Replacement
'\r', '\n' Converted into escaped
strings "\\r" and "\\n"
10 Layouts 206
Intensity
Code0 1 2 3 4 5 6 7
Black Red GreenYellowBlue Magenta
Normal Cyan White
Color table
You can use the default colors with:
%highlight{%d [%t] %-5level: %msg%n%throwable}
Style Description
Default See above
Logback
ANSI
Level color
FATAL Blinking
bright red
ERROR Bright red
WARN Red
INFO Blue
DEBUG Normal
TRACE Normal
p| level{ level= label, level= label, ...} p| Outputs the level of the logging event.
level{length= n} p| level{lowerCase= true| false} You provide a level name map in the form
"level=value, level=value" where level is the
name of the Level and value is the value that
should be displayed instead of the name of the
Level.
For example:
%level{WARN=Warning, DEBUG=Debug, ERROR=Error, TRACE=Trace, IN
For example:
©2021, The Apache Software Foundation • ALL RIGHTS RESERVED.
%style{%d{ISO8601}}{black} %style{[%t]}{blue} %style{%-5level:
By default the relevant information is output as is. However, with the aid of format modifiers it is
possible to change the minimum field width, the maximum field width and justification.
The optional format modifier is placed between the percent sign and the conversion character.
The first optional format modifier is the left justification flag which is just the minus (-) character.
Then comes the optional minimum field width modifier. This is a decimal constant that represents the
minimum number of characters to output. If the data item requires fewer characters, it is padded on
either the left or the right until the minimum width is reached. The default is to pad on the left (right
justify) but you can specify right padding with the left justification flag. The padding character is
space. If the data item is larger than the minimum field width, the field is expanded to accommodate
the data. The value is never truncated. To use zeros as the padding character prepend the minimum
field width with a zero.
This behavior can be changed using the maximum field width modifier which is designated by
a period followed by a decimal constant. If the data item is longer than the maximum field, then
the extra characters are removed from the beginning of the data item and not from the end. For
example, it the maximum field width is eight and the data item is ten characters long, then the first
two characters of the data item are dropped. This behavior deviates from the printf function in C
where truncation is done from the end.
Truncation from the end is possible by appending a minus character right after the period. In that
case, if the maximum field width is eight and the data item is ten characters long, then the last two
characters of the data item are dropped.
Below are various format modifier examples for the category conversion specifier.
Pattern Converters
10.Filtered Throwables
This example shows how to filter out classes from unimportant packages in stack traces.
<properties>
<property name="filters">org.junit,org.apache.maven,sun.reflect,java.lang.reflect</property>
</properties>
...
<PatternLayout pattern="%m%xEx{filters(${filters})}%n"/>
The result printed to the console will appear similar to:
10.ANSI Styled
The log level will be highlighted according to the event's log level. All the content that follows the
level will be bright green.
<PatternLayout>
<pattern>%d %highlight{%p} %style{%C{1.} [%t] %m}{bold,green}%n</pattern>
</PatternLayout>
10.ScriptPatternSelector
The ScriptPatternSelector executes a script as descibed in the Scripts section of the Configuration
chapter. The script is passed all the properties configured in the Properties section of the
configuration, the StrSubstitutor used by the Confguration in the "substitutor" variables, and the log
event in the "logEvent" variable, and is expected to return the value of the PatternMatch key that
should be used, or null if the default pattern should be used.
<PatternLayout>
<ScriptPatternSelector defaultPattern="[%-5level] %c{1.} %C{1.}.%M.%L %msg%n">
<Script name="BeanShellSelector" language="bsh"><![CDATA[
if (logEvent.getLoggerName().equals("NoLocation")) {
return "NoLocation";
} else if (logEvent.getMarker() != null && logEvent.getMarker().isInstanceOf("FLOW")) {
return "Flow";
} else {
return null;
}]]>
</Script>
<PatternMatch key="NoLocation" pattern="[%-5level] %c{1.} %msg%n"/>
<PatternMatch key="Flow" pattern="[%-5level] %c{1.} ====== %C{1.}.%M:%L %msg ======%n"/>
</ScriptPatternSelector>
</PatternLayout>
Rfc5424Layout Parameters
SyslogLayout Parameters
<Event xmlns="http://logging.apache.org/log4j/2.0/events"
level="INFO"
loggerName="HelloWorld"
endOfBatch="false"
thread="main"
loggerFqcn="org.apache.logging.log4j.spi.AbstractLogger"
threadId="1"
threadPriority="5">
<Instant epochSecond="1493121664" nanoOfSecond="118000000"/>
<Marker name="child">
<Parents>
<Marker name="parent">
<Parents>
<Marker name="grandparent"/>
</Parents>
</Marker>
</Parents>
</Marker>
<Message>Hello, world!</Message>
<ContextMap>
<item key="bar" value="BAR"/>
<item key="foo" value="FOO"/>
</ContextMap>
<ContextStack>
<ContextStackItem>one</ContextStackItem>
<ContextStackItem>two</ContextStackItem>
</ContextStack>
<Source
class="logtest.Main"
method="main"
file="Main.java"
line="29"/>
<Thrown commonElementCount="0" message="error message" name="java.lang.RuntimeException">
<ExtendedStackTrace>
<ExtendedStackTraceItem
class="logtest.Main"
method="main"
file="Main.java"
line="29"
exact="true"
location="classes/"
version="?"/>
</ExtendedStackTrace>
</Thrown>
</Event>
If complete="false", the appender does not write the XML processing instruction and the root
element.
10.1.10.2 Marker
Markers are represented by a Marker element within the Event element. The Marker element
appears only when a marker is used in the log message. The name of the marker's parent will be
provided in the parent attribute of the Marker element.
XmlLayout Parameters
To include any custom field in the output, use following syntax:
<XmlLayout>
<KeyValuePair key="additionalField1" value="constant value"/>
<KeyValuePair key="additionalField2" value="$${ctx:key}"/>
</XmlLayout>
Custom fields are always last, in the order they are declared. The values support lookups.
Additional runtime dependencies are required for using XmlLayout.
YamlLayout Parameters
To include any custom field in the output, use following syntax:
<YamlLayout>
<KeyValuePair key="additionalField1" value="constant value"/>
<KeyValuePair key="additionalField2" value="$${ctx:key}"/>
</YamlLayout>
Custom fields are always last, in the order they are declared. The values support lookups.
Additional runtime dependencies are required for using YamlLayout.
than without location. For this reason, asynchronous loggers and asynchronous appenders do not
include location information by default.
You can override the default behaviour in your logger or asynchronous appender configuration by
specifying includeLocation="true".
11 Filters
.......................................................................................................................................
11.1 Filters
Filters allow Log Events to be evaluated to determine if or how they should be published. A Filter
will be called on one of its filter methods and will return a Result, which is an Enum that has one of 3
values - ACCEPT, DENY or NEUTRAL.
Filters may be configured in one of four locations:
1. Context-wide Filters are configured directly in the configuration. Events that are rejected by
these filters will not be passed to loggers for further processing. Once an event has been accepted
by a Context-wide filter it will not be evaluated by any other Context-wide Filters nor will the
Logger's Level be used to filter the event. The event will be evaluated by Logger and Appender
Filters however.
2. Logger Filters are configured on a specified Logger. These are evaluated after the Context-
wide Filters and the Log Level for the Logger. Events that are rejected by these filters will be
discarded and the event will not be passed to a parent Logger regardless of the additivity setting.
3. Appender Filters are used to determine if a specific Appender should handle the formatting and
publication of the event.
4. Appender Reference Filters are used to determine if a Logger should route the event to an
appender.
11.1.1 BurstFilter
The BurstFilter provides a mechanism to control the rate at which LogEvents are processed by silently
discarding events after the maximum limit has been reached.
11.1.2 CompositeFilter
The CompositeFilter provides a way to specify more than one filter. It is added to the configuration as
a filters element and contains other filters to be evaluated. The filters element accepts no parameters.
A configuration containing the CompositeFilter might look like:
11.1.3 DynamicThresholdFilter
The DynamicThresholdFilter allows filtering by log level based on specific attributes. For example,
if the user's loginId is being captured in the ThreadContext Map then it is possible to enable debug
logging for only that user. If the log event does not contain the specified ThreadContext item
NEUTRAL will be returned.
11.1.4 MapFilter
The MapFilter allows filtering against data elements that are in a MapMessage.
11.1.5 MarkerFilter
The MarkerFilter compares the configured Marker value against the Marker that is included in the
LogEvent. A match occurs when the Marker name matches either the Log Event's Marker or one of its
parents.
11.1.6 NoMarkerFilter
The NoMarkerFilter checks that there is no marker included in the LogEvent. A match occurs when
there is no marker in the Log Event.
11.1.7 RegexFilter
The RegexFilter allows the formatted or unformatted message to be compared against a regular
expression.
11.1.8 Script
The ScriptFilter executes a script that returns true or false.
Script Parameters
The sample below shows how to declare script fields and then reference them in specific components.
See ScriptCondition for an example of how the Script element can be used to embed script code
directly in the configuration.
11.1.9 StructuredDataFilter
The StructuredDataFilter is a MapFilter that also allows filtering on the event id, type and message.
11.1.11 ThresholdFilter
This filter returns the onMatch result if the level in the LogEvent is the same or more specific than
the configured level and the onMismatch value otherwise. For example, if the ThresholdFilter is
configured with Level ERROR and the LogEvent contains Level DEBUG then the onMismatch value
will be returned since ERROR events are more specific than DEBUG.
11.1.12 TimeFilter
The time filter can be used to restrict filter to only a certain portion of the day.
12 Async Loggers
.......................................................................................................................................
12.1.1 Trade-offs
Although asynchronous logging can give significant performance benefits, there are situations where
you may want to choose synchronous logging. This section describes some of the trade-offs of
asynchronous logging.
Benefits
• Higher peak throughput. With an asynchronous logger your application can log messages at 6 -
68 times the rate of a synchronous logger.
This is especially interesting for applications that occasionally need to log bursts of messages.
Async logging can help prevent or dampen latency spikes by shortening the wait time until the
next message can be logged. If the queue size is configured large enough to handle the burst,
asynchronous logging will help prevent your application from falling behind (as much) during a
sudden increase of activity.
• Lower logging response time latency. Response time latency is the time it takes for a call to
Logger.log to return under a given workload. Asynchronous Loggers have consistently lower
latency than synchronous loggers or even queue-based asynchronous appenders.
Drawbacks
• Error handling. If a problem happens during the logging process and an exception is thrown, it
is less easy for an asynchronous logger or appender to signal this problem to the application.
This can partly be alleviated by configuring an ExceptionHandler, but this may still not cover
all cases. For this reason, if logging is part of your business logic, for example if you are using
Log4j as an audit logging framework, we would recommend to synchronously log those audit
messages. (Note that you can still combine them and use asynchronous logging for debug/trace
logging in addition to synchronous logging for the audit trail.)
• In some rare cases, care must be taken with mutable messages. Most of the time you don't need
to worry about this. Log4 will ensure that log messages like logger.debug("My object
is {}", myObject) will use the state of the myObject parameter at the time of the call to
logger.debug(). The log message will not change even if myObject is modified later. It is
safe to asynchronously log mutable objects because most Message implementations built-in to
Log4j take a snapshot of the parameters. There are some exceptions however: MapMessage and
StructuredDataMessage are mutable by design: fields can be added to these messages after the
message object was created. These messages should not be modified after they are logged with
asynchronous loggers or asynchronous appenders; you may or may not see the modifications in
the resulting log output. Similarly, custom Message implementations should be designed with
asynchronous use in mind, and either take a snapshot of their parameters at construction time, or
document their thread-safety characteristics.
• If your application is running in an environment where CPU resources are scarce, like a machine
with one CPU with a single core, starting another thread is not likely to give better performance.
• If the sustained rate at which your application is logging messages is faster than the maximum
sustained throughput of the underlying appender, the queue will fill up and the application will
end up logging at the speed of the slowest appender. If this happens, consider selecting a faster
appender, or logging less. If neither of these is an option, you may get better throughput and
fewer latency spikes by logging synchronously.
<Configuration status="WARN">
<Appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<RandomAccessFile name="RandomAccessFile" fileName="async.log" immediateFlush="false" append="false">
<PatternLayout>
<Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<Root level="info" includeLocation="false">
<AppenderRef ref="RandomAccessFile"/>
</Root>
</Loggers>
</Configuration>
AsyncLogger.SynchronizeEnqueueWhenQueueFull
true Synchronizes access to the
Disruptor ring buffer for blocking
enqueue operations when the
queue is full. Users encountered
excessive CPU utilization with
Disruptor v3.4.2 when the
application was logging more
than the underlying appender
could keep up with and the ring
buffer became full, especially
when the number of application
threads vastly outnumbered the
number of cores. CPU utilization is
significantly reduced by restricting
access to the enqueue operation.
Setting this value to false may
lead to very high CPU utilization
when the async logging queue is
full.
log4j2.asyncLoggerThreadNameStrategy
CACHED Valid values: CACHED,
UNCACHED.
By default, AsyncLogger caches
the thread name in a ThreadLocal
variable to improve performance.
Specify the UNCACHED option
if your application modifies the
thread name at runtime (with
Thread.currentThread().setName())
and you want to see the new thread
name reflected in the log.
Synchronous and asynchronous loggers can be combined in configuration. This gives you more
flexibility at the cost of a slight loss in performance (compared to making all loggers asynchronous).
Use the <asyncRoot> or <asyncLogger> configuration elements to specify the loggers that
need to be asynchronous. A configuration can contain only one root logger (either a <root> or an
<asyncRoot> element), but otherwise async and non-async loggers may be combined. For example,
a configuration file containing <asyncLogger> elements can also contain <root> and <logger>
elements for the synchronous loggers.
By default, location is not passed to the I/O thread by asynchronous loggers. If one of your layouts or
custom filters needs location information, you need to set "includeLocation=true" in the configuration
of all relevant loggers, including the root logger.
A configuration that mixes asynchronous loggers might look like:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<!-- Async Loggers will auto-flush in batches, so switch off immediateFlush. -->
<RandomAccessFile name="RandomAccessFile" fileName="asyncWithLocation.log"
immediateFlush="false" append="false">
<PatternLayout>
<Pattern>%d %p %class{1.} [%t] %location %m %ex%n</Pattern>
</PatternLayout>
</RandomAccessFile>
</Appenders>
<Loggers>
<!-- pattern layout actually uses location, so we need to include it -->
<AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
<AppenderRef ref="RandomAccessFile"/>
</AsyncLogger>
<Root level="info" includeLocation="true">
<AppenderRef ref="RandomAccessFile"/>
</Root>
</Loggers>
</Configuration>
There are a few system properties you can use to control aspects of the asynchronous logging
subsystem. Some of these can be used to tune logging performance.
The below properties can also be specified by creating a file named
log4j2.component.properties and including this file in the classpath of the application.
Note that system properties were renamed into a more consistent style in Log4j 2.10. All old property
names are still supported which are documented here.
log4j2.asyncLoggerConfigExceptionHandler
default handler Fully qualified name of a
class that implements the
com.lmax.disruptor.ExceptionHandler
interface. The class needs to have
a public zero-argument constructor.
If specified, this class will be
notified when an exception occurs
while logging the messages.
If not specified, the default
exception handler will print a
message and stack trace to the
standard error output stream.
log4j2.asyncLoggerConfigRingBufferSize
256 * 1024 Size (number of slots) in
the RingBuffer used by the
asynchronous logging subsystem.
Make this value large enough
to deal with bursts of activity.
The minimum size is 128. The
RingBuffer will be pre-allocated
at first use and will never grow or
shrink during the life of the system.
When the application is
logging faster than the
underlying appender can keep
up with for a long enough
time to fill up the queue, the
behavious is determined by the
AsyncQueueFullPolicy.
log4j2.asyncLoggerConfigWaitStrategy
Timeout Valid values: Block, Timeout,
Sleep, Yield.
Block is a strategy that uses
a lock and condition variable
for the I/O thread waiting for
log events. Block can be used
when throughput and low-latency
are not as important as CPU
resource. Recommended for
resource constrained/virtualised
environments.
Timeout is a variation of
the Block strategy that will
periodically wake up from the lock
condition await() call. This ensures
that if a notification is missed
somehow the consumer thread is
not stuck but will recover with a
small latency delay (default 10ms).
Sleep is a strategy that initially
spins, then uses a Thread.yield(),
and eventually parks for the
minimum number of nanos the OS
and JVM will allow while the I/O
thread is waiting for log events.
Sleep is a good compromise
between performance and CPU
resource. This strategy has very
low impact on the application
thread, in exchange for some
additional latency for actually
getting the message logged.
Yield is a strategy that uses a
Thread.yield() for waiting for log
events after an initially spinning.
Yield is a good compromise
between performance and CPU
resource, but may use more CPU
than Sleep in order to get the
message logged to disk sooner.
log4j2.asyncLoggerConfigTimeout 10 Timeout in milliseconds of
TimeoutBlockingWaitStrategy.
See the WaitStrategy System
Property for details.
log4j2.asyncLoggerConfigSleepTimeNs
100 Sleep time (in nanoseconds) of
SleepingWaitStrategy. See
the WaitStrategy System Property
for details.
log4j2.asyncLoggerConfigRetries 200 Total number of spin cycles and
Thread.yield() cycles of
SleepingWaitStrategy. See
the WaitStrategy System Property
for details.
AsyncLoggerConfig.SynchronizeEnqueueWhenQueueFull
true Synchronizes access to the
Disruptor ring buffer for blocking
enqueue operations when the
queue is full. Users encountered
excessive CPU utilization with
Disruptor v3.4.2 when the
application was logging more
than the underlying appender
could keep up with and the ring
buffer became full, especially
when the number of application
threads vastly outnumbered the
number of cores. CPU utilization is
significantly reduced by restricting
access to the enqueue operation.
Setting this value to false may
lead to very high CPU utilization
when the async logging queue is
full.
• First, warm up the JVM by logging 200,000 log messages of 500 characters.
• Repeat the warm-up 10 times, then wait 10 seconds for the I/O thread to catch up and buffers to
drain.
• Measure how long it takes to execute 256 * 1024 / threadCount calls to Logger.log and express
the result in messages per second.
• Repeat the test 5 times and average the results.
The results below were obtained with log4j-2.0-beta5, disruptor-3.0.0.beta3, log4j-1.2.17 and
logback-1.0.10.
On Solaris 10 (64bit) with JDK1.7.0_06, 4-core Xeon X5570 dual CPU @2.93Ghz with
hyperthreading switched on (16 virtual cores):
16 32 64
Logger 1 thread 2 threads 4 threads 8 threads threads threads threads
Log4j 2: 2,652,412 909,119 776,993 516,365 239,246 253,791 288,997
Loggers all
asynchronous
Log4j 2: 2,454,358 839,394 854,578 597,913 261,003 216,863 218,937
Loggers
mixed sync/
async
Log4j 2: 1,713,429 603,019 331,506 149,408 86,107 45,529 23,980
Async
Appender
Log4j1: 2,239,664 494,470 221,402 109,314 60,580 31,706 14,072
Async
Appender
Logback: 2,206,907 624,082 307,500 160,096 85,701 43,422 21,303
Async
Appender
Log4j 2: 273,536 136,523 67,609 34,404 15,373 7,903 4,253
Synchronous
Log4j1: 326,894 105,591 57,036 30,511 13,900 7,094 3,509
Synchronous
Logback: 178,063 65,000 34,372 16,903 8,334 3,985 1,967
Synchronous
On Windows 7 (64bit) with JDK1.7.0_11, 2-core Intel i5-3317u CPU @1.70Ghz with hyperthreading
switched on (4 virtual cores):
This section has been rewritten with the Log4j 2.6 release. The previous version only reported service time
instead of response time. See the response time side bar on the performance page on why this is too
optimistic. Furthermore the previous version reported average latency, which does not make sense since
latency is not a normal distribution. Finally, the previous version of this section only reported the maximum
latency of up to 99.99% of the measurements, which does not tell you how bad the worst 0.01% were. This is
unfortunate because often the "outliers" are all that matter when it comes to response time. From this release
we will try to do better and report response time latency across the full range of percentages, including all the
outliers. Our thanks to Gil Tene for his How NOT to measure latency presentation. (Now we know why this is
also known as the "Oh s#@t!" presentation.)
Response time is how long it takes to log a message under a certain load. What is often reported as
latency is actually service time: how long it took to perform the operation. This hides the fact that a
single spike in service time adds queueing delay for many of the subsequent operations. Service time
is easy to measure (and often looks good on paper) but is irrelevant for users since it omits the time
spent waiting for service. For this reason we report response time: service time plus wait time.
The response time test results below were all derived from running the ResponseTimeTest class
which can be found in the Log4j 2 unit test source directory. If you want to run these tests yourself,
here are the command line options we used:
• -Xms1G -Xmx1G (prevent heap resizing during the test)
• -DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
-DAsyncLogger.WaitStrategy=busyspin (to use Async Loggers. The BusySpin wait strategy
reduces some jitter.)
• classic mode: -Dlog4j2.enable.threadlocals=false -Dlog4j2.enable.direct.encoders=false
garbage-free mode: -Dlog4j2.enable.threadlocals=true -Dlog4j2.enable.direct.encoders=true
• -
XX:CompileCommand=dontinline,org.apache.logging.log4j.core.async.perftest.NoOpIdleStrategy::idle
• -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime (to eyeball
GC and safepoint pauses)
The graph below compares response time latency of the ArrayBlockingQueue-based asynchronous
appenders in Logback 1.1.7, Log4j 1.2.17 to the various options for asynchronous logging that Log4j
2.6 offers. Under a workload of 128,000 messages per second, using 16 threads (each logging at a rate
of 8,000 messages per second), we see that Logback 1.1.7, Log4j 1.2.17 experience latency spikes
that are orders of magnitude larger than Log4j 2.
The graph below zooms in on the Log4j 2 results for the same test. We see that the worst-case
response time is highest for the ArrayBlockingQueue-based Async Appender. Garbage-free async
loggers have the best response time behaviour.
13 Garbage-free Logging
.......................................................................................................................................
With Log4j 2.5: memory allocation rate 809 MB/sec, Log4j 2.6 did not allocate temporary objects: 0 (zero)
141 minor collections. garbage collections.
13.1.2 Configuration
Garbage-free logging in Log4j 2.6 is partially implemented by reusing objects in ThreadLocal fields,
and partially by reusing buffers when converting text to bytes.
ThreadLocal fields holding non-JDK classes can cause memory leaks in web applications when
the application server's thread pool continues to reference these fields after the web application is
undeployed. To avoid causing memory leaks, Log4j will not use these ThreadLocals when it detects
that it is used in a web application (when the javax.servlet.Servlet class is in the classpath, or
when system property log4j2.isWebapp is set to "true").
Some garbage-reducing functionality does not rely on ThreadLocals and is enabled by default for
all applications: in Log4j 2.6, converting log events to text and text to bytes can be done by directly
encoding text into a reused ByteBuffer without creating intermediary Strings, char arrays and byte
arrays. So while logging is not completely garbage-free for web applications yet, the pressure on the
garbage collector can still be significantly reduced.
Note 1: as of version 2.6, a Log4j configuration containing a <Properties> section will result in
temporary objects being created during steady-state logging.
Note 2: the Async Logger Timeout wait strategy (the default) and the Block wait strategy cause
java.util.concurrent.locks.AbstractQueuedSynchronizer$Node objects to be created.
The Yield and Sleep wait strategies are garbage-free. (See here and here.)
• CompositeFilter (adding and removing element filters creates temporary objects for thread
safety)
• DynamicThresholdFilter
• LevelRangeFilter (garbage free since 2.8)
• MapFilter (garbage free since 2.8)
• MarkerFilter (garbage free since 2.8)
• StructuredDataFilter (garbage free since 2.8)
• ThreadContextMapFilter (garbage free since 2.8)
• ThresholdFilter (garbage free since 2.8)
• TimeFilter (garbage free since 2.8 except when range must be recalculated once per day)
Other filters like BurstFilter, RegexFilter and ScriptFilter are not trivial to make garbage free, and
there is currently no plan to change them.
13.GelfLayout
GelfLayout is garbage-free when used with compressionType="OFF", as long as no additional field
contains '${' (variable substitution).
13.JsonTemplateLayout
JsonTemplateLayout is garbage-free with a few exceptions.
13.PatternLayout
PatternLayout with the following limited set of conversion patterns is garbage-free. Format modifiers
to control such things as field width, padding, left and right justification will not generate garbage.
%d, %date Note: Only the predefined date formats are garbage-
free: (millisecond separator may be either a comma ','
or a period '.')
Pattern Example
%d{DEFAULT} 2012-11-02 14:34:02,781
%d{ISO8601} 2012-11-02T14:34:02,781
%d{ISO8601_BASIC} 20121102T143402,781
%d{ABSOLUTE} 14:34:02,781
%d{DATE} 02 Nov 2012
14:34:02,781
%d{COMPACT} 20121102143402781
%d{HH:mm:ss,SSS} 14:34:02,781
%d{dd MMM yyyy 02 Nov 2012
HH:mm:ss,SSS} 14:34:02,781
%d{HH:mm:ss}{GMT+0} 18:34:02
%d{UNIX} 1351866842
%d{UNIX_MILLIS} 1351866842781
Other PatternLayout conversion patterns, and other Layouts may be updated to avoid creating
temporary objects in future releases. (Patches welcome!)
Note: Logging exceptions and stack traces will create temporary objects with any layout. (However,
Layouts will only create these temporary objects when an exception actually occurs.) We haven't
figured out a way to log exceptions and stack traces without creating temporary objects. That is
unfortunate, but you probably still want to log them when they happen.
Note: patterns containing regular expressions and lookups for property substitution will result in temporary
objects being created during steady-state logging.
Including location information is done by walking the stacktrace of an exception, which creates
temporary objects, so the following patterns are not garbage-free:
• %C, %class - Class Name
• %F, %file - File Location
• %l, %location - Location
• %L, %line - Line Location
• %M, %method - Method Location
Also, the pattern converters for formatting Throwables are not garbage-free:
message parameters into text by appending them to a StringBuilder as a CharSequence. This avoids
calling toString() on these objects.
An alternative is to implement the
org.apache.logging.log4j.util.StringBuilderFormattable interface. If an object is
logged that implements this interface, its formatTo method is called instead of toString().
Log4j may call toString() on message and parameter objects when garbage-free logging is
disabled (when system property log4j2.enableThreadlocals is set to "false".)
...
public void garbageFree() {
logger.debug("Prevent primitive autoboxing {} {}", box(10L), box(2.6d));
}
13.1.3 Performance
single spike in service time adds queueing delay for many of the subsequent operations. Service time
is easy to measure (and often looks good on paper) but is irrelevant for users since it omits the time
spent waiting for service. For this reason we report response time: service time plus wait time. See the
response time section of the performance page for more detail.
The response time test results below were all derived from running the ResponseTimeTest class
which can be found in the Log4j 2 unit test source directory. If you want to run these tests yourself,
here are the command line options we used:
In classic mode we see numerous minor garbage collections which pause the application threads for
3 milliseconds or more. This quickly adds up to response time delays of almost 10 milliseconds. As
you can see in the graph, increasing the load shifts the curve to the left (there are more spikes). This
makes sense: logging more means more pressure on the garbage collector resulting in more minor GC
pauses. We experimented a little with reducing the load to 50,000 or even 5000 messages/second, but
this did not eliminate the 3 millisecond pauses, it just made them occur less frequently. Note that all
GC pauses in this test are minor GC pauses. We did not see any full garbage collections.
In garbage-free mode, maximum response time remains well below 1 millisecond under a wide range
of loads. (Max 780 us at 800,000 messages/sec, max 407 us at 600,000 messages/sec, with the 99%
around 5 us for all loads up to 800,000 messages/sec.) Increasing or decreasing the load does not
change the response time behaviour. We did not investigate the cause of the 200-300 microsecond
pauses we saw in these tests.
When we increased the load further we begin to see larger response time pauses for both classic and
garbage-free logging. At sustained loads of 1 million messages/second or more we start to approach
the maximum throughput of the underlying RandomAccessFile Appender (see the synchronous
logging throughput chart below). At these loads the ringbuffer starts to fill up and backpressure kicks
in: attempting to add another message when the ringbuffer is full will block until a free slot becomes
available. We start to see response times of tens of milliseconds or more; and attempting to increase
the load even more results in larger and larger response time spikes.
The above results are obtained with the ResponseTimeTest class which can be found in the Log4j 2
unit test source directory, running on JDK 1.8.0_45 on RHEL 6.5 (Linux 2.6.32-573.1.1.el6.x86_64)
with 10-core Xeon CPU E5-2660 v3 @2.60GHz with hyperthreading switched on (20 virtual cores).
The results above are obtained with the JMH Java benchmark harness. See the
FileAppenderBenchmark source code in the log4j-perf module.
14 JMX
.......................................................................................................................................
14.1 JMX
Log4j 2 has built-in support for JMX. The StatusLogger, ContextSelector, and all LoggerContexts,
LoggerConfigs and Appenders are instrumented with MBeans and can be remotely monitored and
controlled.
Also included is a simple client GUI that can be used to monitor the StatusLogger output, as well as
to remotely reconfigure Log4j with a different configuration file, or to edit the current configuration
directly.
JMX support is enabled by default. When Log4j initializes, the StatusLogger, ContextSelector,
and all LoggerContexts, LoggerConfigs and Appenders are instrumented with MBeans. To
disable JMX completely, and prevent these MBeans from being created, specify system property
log4j2.disableJmx to true when you start the Java VM.
To perform local monitoring you don't need to specify any system properties. The JConsole tool
that is included in the Java JDK can be used to monitor your application. Start JConsole by typing
$JAVA_HOME/bin/jconsole in a command shell. For more details, see Oracle's documentation on
how to use JConsole.
To enable monitoring and management from remote systems, set the following system property when
starting the Java VM.
com.sun.management.jmxremote.port=portNum
In the property above, portNum is the port number through which you want to enable JMX RMI
connections.
For more details, see Oracle's documentation on Remote Monitoring and Management.
Be aware that RMI by default triggers a full GC every hour. See the Oracle documentation for the
sun.rmi.dgc.server.gcInterval and sun.rmi.dgc.client.gcInterval properties. The
default value of both properties is 3600000 milliseconds (one hour). Before Java 6, it was one minute.
The two sun.rmi arguments reflect whether your JVM is running in server or client mode. If you want
to modify the GC interval time it may be best to specify both properties to ensure the argument is
picked up by the JVM.
An alternative may be to disable explicit calls to System.gc() altogether with -
XX:+DisableExplicitGC, or (if you are using the CMS or G1 collector) add -XX:
+ExplicitGCInvokesConcurrent to ensure the full GCs are done concurrently in parallel with
your application instead of forcing a stop-the-world collection.
The best way to find out which methods and attributes of the various Log4j components are accessible
via JMX is to look at the Javadoc or by exploring directly in JConsole.
The screenshot below shows the Log4j MBeans in JConsole.
Log4j includes a basic client GUI that can be used to monitor the StatusLogger output and to remotely
modify the Log4j configuration. The client GUI can be run as a stand-alone application or as a
JConsole plug-in.
The configuration edit panel provides two ways to modify the Log4j configuration: specifying a
different configuration location URI, or modifying the configuration XML directly in the editor panel.
If you specify a different configuration location URI and click the "Reconfigure from Location"
button, the specified file or resource must exist and be readable by the application, or an error will
occur and the configuration will not change. If an error occurred while processing the contents of
the specified resource, Log4j will keep its original configuration, but the editor panel will show the
contents of the file you specified.
The text area showing the contents of the configuration file is editable, and you can directly modify
the configuration in this editor panel. Clicking the "Reconfigure with XML below" button will send
the configuration text to the remote application where it will be used to reconfigure Log4j on the fly.
This will not overwrite any configuration file. Reconfiguring with text from the editor happens in
memory only and the text is not permanently stored anywhere.
To run the Log4j JMX Client GUI as a stand-alone application, run the following command:
• <host>:<port>
• service:jmx:rmi:///jndi/rmi://<host>:<port>/jmxrmi
• service:jmx:rmi://<host>:<port>/jndi/rmi://<host>:<port>/jmxrmi
The port number must be the same as the portNum specified when you started the application you
want to monitor.
For example, if you started your application with these options:
com.sun.management.jmxremote.port=33445
com.sun.management.jmxremote.authenticate=false
com.sun.management.jmxremote.ssl=false
(Note that this disables all security so this is not recommended for production environments.
Oracle's documentation on Remote Monitoring and Management provides details on how to
configure JMX more securely with password authentication and SSL.)
Then you can run the client with this command:
$JAVA_HOME/bin/java -cp /path/to/log4j-api-${Log4jReleaseVersion}.jar:/
path/to/log4j-core-${Log4jReleaseVersion}.jar:/path/to/log4j-jmx-gui-
${Log4jReleaseVersion}.jar org.apache.logging.log4j.jmx.gui.ClientGui
localhost:33445
or on Windows:
%JAVA_HOME%\bin\java -cp \path\to\log4j-api-${Log4jReleaseVersion}.jar;
\path\to\log4j-core-${Log4jReleaseVersion}.jar;\path\to\log4j-jmx-gui-
${Log4jReleaseVersion}.jar org.apache.logging.log4j.jmx.gui.ClientGui
localhost:33445
The screenshot below shows the StatusLogger panel of the client GUI when running as a stand-alone
application.
The screenshot below shows the configuration editor panel of the client GUI when running as a stand-
alone application.
15 Logging Separation
.......................................................................................................................................
This section describes some of the use cases where Log4j could be used and what its desired behavior
might be.
15.1.2 Approaches
16 Extending Log4j
.......................................................................................................................................
16.1.1 LoggerContextFactory
The LoggerContextFactory binds the Log4j API to its implementation. The Log4j LogManager
locates a LoggerContextFactory by using java.util.ServiceLoader to locate all instances of
org.apache.logging.log4j.spi.Provider. Each implementation must provide a class that
extends org.apache.logging.log4j.spi.Provider and should have a no-arg constructor
that delegates to Provider's constructor passing the Priority, the API versions it is compatible with,
and the class that implements org.apache.logging.log4j.spi.LoggerContextFactory.
Log4j will compare the current API version and if it is compatible the implementation will be
added to the list of providers. The API version in org.apache.logging.log4j.LogManager
is only changed when a feature is added to the API that implementations need to be aware
of. If more than one valid implementation is located the value for the Priority will be
used to identify the factory with the highest priority. Finally, the class that implements
org.apache.logging.log4j.spi.LoggerContextFactory will be instantiated and bound to
the LogManager. In Log4j 2 this is provided by Log4jContextFactory.
Applications may change the LoggerContextFactory that will be used by
16.1.2 ContextSelector
ContextSelectors are called by the Log4j LoggerContext factory. They perform the actual
work of locating or creating a LoggerContext, which is the anchor for Loggers and their
configuration. ContextSelectors are free to implement any mechanism they desire to manage
LoggerContexts. The default Log4jContextFactory checks for the presence of a System Property
named "Log4jContextSelector". If found, the property is expected to contain the name of the Class
that implements the ContextSelector to be used.
Log4j provides five ContextSelectors:
BasicContextSelector
16.1.3 ConfigurationFactory
Modifying the way in which logging can be configured is usually one of the areas with the most
interest. The primary method for doing that is by implementing or extending a ConfigurationFactory.
Log4j provides two ways of adding new ConfigurationFactories. The first is by defining the system
property named "log4j.configurationFactory" to the name of the class that should be searched first for
a configuration. The second method is by defining the ConfigurationFactory as a Plugin.
All the ConfigurationFactories are then processed in order. Each factory is called on its
getSupportedTypes method to determine the file extensions it supports. If a configuration file is
located with one of the specified file extensions then control is passed to that ConfigurationFactory to
load the configuration and create the Configuration object.
Most Configuration extend the BaseConfiguration class. This class expects that the subclass will
process the configuration file and create a hierarchy of Node objects. Each Node is fairly simple
in that it consists of the name of the node, the name/value pairs associated with the node, The
PluginType of the node and a List of all of its child Nodes. BaseConfiguration will then be passed the
Node tree and instantiate the configuration objects from that.
/**
* Valid file extensions for XML files.
*/
public static final String[] SUFFIXES = new String[] {".xml", "*"};
/**
* Returns the Configuration.
* @param loggerContext The logger context.
* @param source The InputSource.
* @return The Configuration.
*/
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source
return new XmlConfiguration(loggerContext, source);
}
/**
* Returns the file suffixes for XML files.
* @return An array of File extensions.
*/
public String[] getSupportedTypes() {
return SUFFIXES;
}
}
16.1.4 LoggerConfig
LoggerConfig objects are where Loggers created by applications tie into the configuration. The
Log4j implementation requires that all LoggerConfigs be based on the LoggerConfig class, so
applications wishing to make changes must do so by extending the LoggerConfig class. To declare
the new LoggerConfig, declare it as a Plugin of type "Core" and providing the name that applications
should specify as the element name in the configuration. The LoggerConfig should also define a
PluginFactory that will create an instance of the LoggerConfig.
The following example shows how the root LoggerConfig simply extends a generic LoggerConfig.
@PluginFactory
public static LoggerConfig createLogger(@PluginAttribute(value = "additivity", defaultBooleanValue = true
@PluginAttribute(value = "level", defaultStringValue = "ERROR") L
@PluginElement("AppenderRef") AppenderRef[] refs,
@PluginElement("Filters") Filter filter) {
List<AppenderRef> appenderRefs = Arrays.asList(refs);
return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additivity);
}
}
16.1.5 LogEventFactory
A LogEventFactory is used to generate LogEvents. Applications may replace the standard
LogEventFactory by setting the value of the system property Log4jLogEventFactory to the name of
the custom LogEventFactory class.
Note: When log4j is configured to have all loggers asynchronous, log events are pre-allocated in a
ring buffer and the LogEventFactory is not used.
16.1.6 MessageFactory
A MessageFactory is used to generate Message objects. Applications may replace the standard
ParameterizedMessageFactory (or ReusableMessageFactory in garbage-free mode) by setting the
value of the system property log4j2.messageFactory to the name of the custom MessageFactory class.
Flow messages for the Logger.entry() and Logger.exit() methods have a separate
FlowMessageFactory. Applications may replace the DefaultFlowMessageFactory by setting the value
of the system property log4j2.flowMessageFactory to the name of the custom FlowMessageFactory
class.
16.1.7 Lookups
Lookups are the means in which parameter substitution is performed. During Configuration
initialization an "Interpolator" is created that locates all the Lookups and registers them for use when
a variable needs to be resolved. The interpolator matches the "prefix" portion of the variable name to a
registered Lookup and passes control to it to resolve the variable.
A Lookup must be declared using a Plugin annotation with a type of "Lookup". The name specified
on the Plugin annotation will be used to match the prefix. Unlike other Plugins, Lookups do not use
a PluginFactory. Instead, they are required to provide a constructor that accepts no arguments. The
example below shows a Lookup that will return the value of a System Property.
The provided Lookups are documented here: Lookups
/**
* Lookup the value for the key.
* @param key the key to be looked up, may be null
* @return The value for the key.
*/
public String lookup(String key) {
return System.getProperty(key);
}
/**
* Lookup the value for the key using the data in the LogEvent.
* @param event The current LogEvent.
* @param key the key to be looked up, may be null
* @return The value associated with the key.
*/
public String lookup(LogEvent event, String key) {
return System.getProperty(key);
}
}
16.1.8 Filters
As might be expected, Filters are the used to reject or accept log events as they pass through the
logging system. A Filter is declared using a Plugin annotation of type "Core" and an elementType of
"filter". The name attribute on the Plugin annotation is used to specify the name of the element users
should use to enable the Filter. Specifying the printObject attribute with a value of "true" indicates
that a call to toString will format the arguments to the filter as the configuration is being processed.
The Filter must also specify a PluginFactory method that will be called to create the Filter.
The example below shows a Filter used to reject LogEvents based upon their logging level. Notice the
typical pattern where all the filter methods resolve to a single filter method.
public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
return filter(level);
}
public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
return filter(level);
}
public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
return filter(level);
}
@Override
public Result filter(LogEvent event) {
return filter(event.getLevel());
}
@Override
public String toString() {
return level.toString();
}
/**
* Create a ThresholdFilter.
* @param loggerLevel The log Level.
* @param match The action to take on a match.
* @param mismatch The action to take on a mismatch.
* @return The created ThresholdFilter.
*/
@PluginFactory
public static ThresholdFilter createFilter(@PluginAttribute(value = "level", defaultStringValue = "ERROR"
@PluginAttribute(value = "onMatch", defaultStringValue = "NEUT
@PluginAttribute(value = "onMismatch", defaultStringValue = "D
return new ThresholdFilter(level, onMatch, onMismatch);
}
}
16.1.9 Appenders
Appenders are passed an event, (usually) invoke a Layout to format the event, and then "publish"
the event in whatever manner is desired. Appenders are declared as Plugins with a type of "Core"
and an elementType of "appender". The name attribute on the Plugin annotation specifies the name
of the element users must provide in their configuration to use the Appender. Appenders should
specify printObject as "true" if the toString method renders the values of the attributes passed to the
Appender.
Appenders must also declare a PluginFactory method that will create the appender. The example
below shows an Appender named "Stub" that can be used as an initial template.
Most Appenders use Managers. A manager actually "owns" the resources, such as an OutputStream
or socket. When a reconfiguration occurs a new Appender will be created. However, if nothing
significant in the previous Manager has changed, the new Appender will simply reference it instead
of creating a new one. This insures that events are not lost while a reconfiguration is taking place
without requiring that logging pause while the reconfiguration takes place.
@PluginFactory
public static StubAppender createAppender(@PluginAttribute("name") String name,
@PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
@PluginElement("Layout") Layout layout,
@PluginElement("Filters") Filter filter) {
if (name == null) {
LOGGER.error("No name provided for StubAppender");
return null;
}
16.1.10 Layouts
Layouts perform the formatting of events into the printable text that is written by Appenders to some
destination. All Layouts must implement the Layout interface. Layouts that format the event into a
String should extend AbstractStringLayout, which will take care of converting the String into the
required byte array.
Every Layout must declare itself as a plugin using the Plugin annotation. The type must be "Core",
and the elementType must be "layout". printObject should be set to true if the plugin's toString
method will provide a representation of the object and its parameters. The name of the plugin must
match the value users should use to specify it as an element in their Appender configuration. The
plugin also must provide a static method annotated as a PluginFactory and with each of the methods
parameters annotated with PluginAttr or PluginElement as appropriate.
@PluginFactory
public static SampleLayout createLayout(@PluginAttribute("locationInfo") boolean locationInfo,
@PluginAttribute("properties") boolean properties,
@PluginAttribute("complete") boolean complete,
@PluginAttribute(value = "charset", defaultStringValue = "UTF-8")
return new SampleLayout(locationInfo, properties, complete, charset);
}
}
16.1.11 PatternConverters
PatternConverters are used by the PatternLayout to format the log event into a printable String. Each
Converter is responsible for a single kind of manipulation, however Converters are free to format the
event in complex ways. For example, there are several converters that manipulate Throwables and
format them in various ways.
A PatternConverter must first declare itself as a Plugin using the standard Plugin annotation but must
specify value of "Converter" on the type attribute. Furthermore, the Converter must also specify the
ConverterKeys attribute to define the tokens that can be specified in the pattern (preceded by a '%'
character) to identify the Converter.
Unlike most other Plugins, Converters do not use a PluginFactory. Instead, each Converter is required
to provide a static newInstance method that accepts an array of Strings as the only parameter. The
String array are the values that are specified within the curly braces that can follow the converter key.
The following shows the skeleton of a Converter plugin.
@PluginFactory
public static ListAppender createAppender(
@PluginAttribute("name") @Required(message = "No name provided for ListAppender") final String name,
@PluginAttribute("entryPerNewLine") final boolean newLine,
@PluginAttribute("raw") final boolean raw,
@PluginElement("Layout") final Layout<? extends Serializable> layout,
@PluginElement("Filter") final Filter filter) {
return new ListAppender(name, filter, layout, newLine, raw);
}
Here is that same factory using a builder pattern instead:
@PluginBuilderFactory
public static Builder newBuilder() {
return new Builder();
}
@PluginBuilderAttribute
@Required(message = "No name provided for ListAppender")
private String name;
@PluginBuilderAttribute
private boolean entryPerNewLine;
@PluginBuilderAttribute
private boolean raw;
@PluginElement("Layout")
private Layout<? extends Serializable> layout;
@PluginElement("Filter")
private Filter filter;
@Override
public ListAppender build() {
return new ListAppender(name, filter, layout, entryPerNewLine, raw);
}
}
16.1.15 Custom_Plugins
See the Plugins section of the manual.
ConfigurationFactories have the concept of "supported types", which basically maps to the file
extension of the configuration file that the ConfigurationFactory can handle. If a configuration
file location is specified, ConfigurationFactories whose supported type does not include "*" or the
matching file extension will not be used.
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source
return getConfiguration(loggerContext, source.toString(), null);
}
@Override
public Configuration getConfiguration(final LoggerContext loggerContext, final String name, final URI con
ConfigurationBuilder<BuiltConfiguration> builder = newConfigurationBuilder();
return createConfiguration(name, builder);
}
@Override
protected String[] getSupportedTypes() {
return new String[] {"*"};
}
}
As of version 2.7, the ConfigurationFactory.getConfiguration() methods take an
additional LoggerContext parameter.
builder.setStatusLevel( Level.ERROR);
builder.setConfigurationName("RollingBuilder");
// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Stdout", "CONSOLE").addAttribute("target",
ConsoleAppender.Target.SYSTEM_OUT);
appenderBuilder.add(builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"));
builder.add( appenderBuilder );
// create a rolling file appender
LayoutComponentBuilder layoutBuilder = builder.newLayout("PatternLayout")
.addAttribute("pattern", "%d [%t] %-5level: %msg%n");
ComponentBuilder triggeringPolicy = builder.newComponent("Policies")
.addComponent(builder.newComponent("CronTriggeringPolicy").addAttribute("schedule", "0 0 0 * * ?"))
.addComponent(builder.newComponent("SizeBasedTriggeringPolicy").addAttribute("size", "100M"));
appenderBuilder = builder.newAppender("rolling", "RollingFile")
.addAttribute("fileName", "target/rolling.log")
.addAttribute("filePattern", "target/archive/rolling-%d{MM-dd-yy}.log.gz")
.add(layoutBuilder)
.addComponent(triggeringPolicy);
builder.add(appenderBuilder);
/**
* Valid file extensions for XML files.
*/
public static final String[] SUFFIXES = new String[] {".xml", "*"};
/**
* Return the Configuration.
* @param source The InputSource.
* @return The Configuration.
*/
public Configuration getConfiguration(InputSource source) {
return new MyXMLConfiguration(source, configFile);
}
/**
* Returns the file suffixes for XML files.
* @return An array of File extensions.
*/
public String[] getSupportedTypes() {
return SUFFIXES;
}
}
@Override
protected void doConfigure() {
super.doConfigure();
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = context.getConfiguration();
final Layout layout = PatternLayout.createDefaultLayout(config);
final Appender appender = FileAppender.createAppender("target/test.log", "false", "false", "File", "t
"false", "false", "4000", layout, null, "false", null, config);
appender.start();
addAppender(appender);
LoggerConfig loggerConfig = LoggerConfig.createLogger("false", "info", "org.apache.logging.log4j",
"true", refs, null, config, null );
loggerConfig.addAppender(appender, null, null);
addLogger("org.apache.logging.log4j", loggerConfig);
}
}
1. If the configuration file is changed the configuration will be reloaded and the manual changes
will be lost.
2. Modification to the running configuration requires that all the methods being called
(addAppender and addLogger) be synchronized.
As such, the recommended approach for customizing a configuration is to extend one of the standard
Configuration classes, override the setup method to first do super.setup() and then add the custom
Appenders, Filters and LoggerConfigs to the configuration before it is registered for use.
The following example adds an Appender and a new LoggerConfig using that Appender to the current
configuration.
CustomLevel Parameters
The following example shows a configuration that defines some custom log levels and uses a custom
log level to filter log events sent to the console.
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d %-7level %logger{36} - %msg%n"/>
</Console>
<File name="MyFile" fileName="logs/app.log">
<PatternLayout pattern="%d %-7level %logger{36} - %msg%n"/>
</File>
</Appenders>
<Loggers>
<Root level="trace">
<!-- Only events at DIAG level or more specific are sent to the console. -->
<AppenderRef ref="Console" level="diag" />
<AppenderRef ref="MyFile" level="trace" />
</Root>
</Loggers>
</Configuration>
// nice to have: descriptive methods and no need to pass the level as a parameter
logger.verbose("a verbose message");
logger.diag("another message");
logger.diag("java 8 lambda expression: {}", () -> someMethod());
The standard Logger interface cannot provide convenience methods for custom levels, but the next
few sections introduce a code generation tool to create loggers that aim to make custom levels as easy
to use as built-in levels.
Under the bash shell on Unix/Mac/Linux the dollar character $ needs to be escaped, so the class name
should be between single quotes 'org.apache.logging.log4j.core.tools.Generate$CustomLogger’.