blob: 9c70017061f8a0e4a44e9aa7dbd1ae3aa27563c5 [file] [log] [blame]
<!DOCTYPE html>
<!--
| Generated by Apache Maven Doxia Site Renderer 1.9.1 from src/site/xdoc/manual/extending.xml at 2020-02-25
| Rendered using Apache Maven Fluido Skin 1.8
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="generator" content="Apache Maven Doxia Site Renderer 1.9.1" />
<meta name="author" content="Ralph Goers" />
<title>Log4j &#x2013; Extending Log4j 2</title>
<link rel="stylesheet" href="../css/apache-maven-fluido-1.8.min.css" />
<link rel="stylesheet" href="../css/site.css" />
<link rel="stylesheet" href="../css/print.css" media="print" />
<script src="../js/apache-maven-fluido-1.8.min.js"></script>
</head>
<body class="topBarDisabled">
<div class="container-fluid">
<header>
<div id="banner">
<div class="pull-left"><a href="http://logging.apache.org" id="bannerLeft"><img src="../images/ls-logo.jpg" alt=""/></a></div>
<div class="pull-right"><a href="http://logging.apache.org/log4j/2.x" id="bannerRight"><img src="../images/logo.png" alt=""/></a></div>
<div class="clear"><hr/></div>
</div>
<div id="breadcrumbs">
<ul class="breadcrumb">
<li id="publishDate">Last Published: 2020-02-25<span class="divider">|</span>
</li>
<li id="projectVersion">Version: 2.13.1</li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://github.com/apache/logging-log4j2" class="externalLink" title="GitHub">GitHub</a></li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://analysis.apache.org/dashboard/index/org.apache.logging.log4j:log4j" class="externalLink" title="Sonar">Sonar</a></li>
<li class="pull-right"><span class="divider">|</span>
<a href="../../../" title="Logging Services">Logging Services</a></li>
<li class="pull-right"><span class="divider">|</span>
<a href="https://www.apache.org/" class="externalLink" title="Apache">Apache</a></li>
<li class="pull-right"><a href="https://cwiki.apache.org/confluence/display/LOGGING/Log4j" class="externalLink" title="Logging Wiki">Logging Wiki</a></li>
</ul>
</div>
</header>
<div class="row-fluid">
<header id="leftColumn" class="span2">
<nav class="well sidebar-nav">
<ul class="nav nav-list">
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/home.png" alt="Apache Log4j™ 2" border="0"/> Apache Log4j™ 2</li>
<li><a href="../index.html" title="About"><span class="none"></span>About</a></li>
<li><a href="../download.html" title="Download"><span class="none"></span>Download</a></li>
<li><a href="../javadoc.html" title="Javadoc"><span class="icon-chevron-right"></span>Javadoc</a></li>
<li><a href="../maven-artifacts.html" title="Maven, Ivy, Gradle Artifacts"><span class="icon-chevron-right"></span>Maven, Ivy, Gradle Artifacts</a></li>
<li><a href="../runtime-dependencies.html" title="Runtime Dependencies"><span class="none"></span>Runtime Dependencies</a></li>
<li><a href="../changelog.html" title="Changelog"><span class="none"></span>Changelog</a></li>
<li><a href="../faq.html" title="FAQ"><span class="none"></span>FAQ</a></li>
<li><a href="../performance.html" title="Performance"><span class="icon-chevron-right"></span>Performance</a></li>
<li><a href="../articles.html" title="Articles and Tutorials"><span class="none"></span>Articles and Tutorials</a></li>
<li><a href="../support.html" title="Support"><span class="none"></span>Support</a></li>
<li><a href="../thanks.html" title="Thanks"><span class="none"></span>Thanks</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/pencil.png" alt="For Contributors" border="0"/> For Contributors</li>
<li><a href="../build.html" title="Building Log4j from Source"><span class="none"></span>Building Log4j from Source</a></li>
<li><a href="../guidelines.html" title="Guidelines"><span class="none"></span>Guidelines</a></li>
<li><a href="../javastyle.html" title="Style Guide"><span class="none"></span>Style Guide</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/book.png" alt="Manual" border="0"/> Manual</li>
<li><a href="../manual/index.html" title="Introduction"><span class="none"></span>Introduction</a></li>
<li><a href="../manual/architecture.html" title="Architecture"><span class="none"></span>Architecture</a></li>
<li><a href="../manual/compatibility.html" title="Log4j 1.x Compatibility"><span class="none"></span>Log4j 1.x Compatibility</a></li>
<li><a href="../manual/migration.html" title="Log4j 1.x Migration"><span class="none"></span>Log4j 1.x Migration</a></li>
<li><a href="../manual/api.html" title="Java API"><span class="icon-chevron-right"></span>Java API</a></li>
<li><a href="../manual/scala-api.html" title="Scala API"><span class="none"></span>Scala API</a></li>
<li><a href="../manual/configuration.html" title="Configuration"><span class="icon-chevron-right"></span>Configuration</a></li>
<li><a href="../manual/usage.html" title="Usage"><span class="icon-chevron-right"></span>Usage</a></li>
<li><a href="../manual/webapp.html" title="Web Applications and JSPs"><span class="icon-chevron-right"></span>Web Applications and JSPs</a></li>
<li><a href="../manual/lookups.html" title="Lookups"><span class="icon-chevron-right"></span>Lookups</a></li>
<li><a href="../manual/appenders.html" title="Appenders"><span class="icon-chevron-right"></span>Appenders</a></li>
<li><a href="../manual/layouts.html" title="Layouts"><span class="icon-chevron-right"></span>Layouts</a></li>
<li><a href="../manual/filters.html" title="Filters"><span class="icon-chevron-right"></span>Filters</a></li>
<li><a href="../manual/async.html" title="Async Loggers"><span class="icon-chevron-right"></span>Async Loggers</a></li>
<li><a href="../manual/garbagefree.html" title="Garbage-free Logging"><span class="icon-chevron-right"></span>Garbage-free Logging</a></li>
<li><a href="../manual/jmx.html" title="JMX"><span class="none"></span>JMX</a></li>
<li><a href="../manual/logsep.html" title="Logging Separation"><span class="none"></span>Logging Separation</a></li>
<li class="active"><a href="#"><span class="icon-chevron-down"></span>Extending Log4j</a>
<ul class="nav nav-list">
<li><a href="../manual/extending.html#LoggerContextFactory" title="LoggerContextFactory"><span class="none"></span>LoggerContextFactory</a></li>
<li><a href="../manual/extending.html#ContextSelector" title="ContextSelector"><span class="none"></span>ContextSelector</a></li>
<li><a href="../manual/extending.html#ConfigurationFactory" title="ConfigurationFactory"><span class="none"></span>ConfigurationFactory</a></li>
<li><a href="../manual/extending.html#LoggerConfig" title="LoggerConfig"><span class="none"></span>LoggerConfig</a></li>
<li><a href="../manual/extending.html#LogEventFactory" title="LogEventFactory"><span class="none"></span>LogEventFactory</a></li>
<li><a href="../manual/extending.html#MessageFactory" title="MessageFactory"><span class="none"></span>MessageFactory</a></li>
<li><a href="../manual/extending.html#Lookups" title="Lookups"><span class="none"></span>Lookups</a></li>
<li><a href="../manual/extending.html#Filters" title="Filters"><span class="none"></span>Filters</a></li>
<li><a href="../manual/extending.html#Appenders" title="Appenders"><span class="none"></span>Appenders</a></li>
<li><a href="../manual/extending.html#Layouts" title="Layouts"><span class="none"></span>Layouts</a></li>
<li><a href="../manual/extending.html#PatternConverters" title="PatternConverters"><span class="none"></span>PatternConverters</a></li>
<li><a href="../manual/extending.html#Plugin_Builders" title="Plugin Builders"><span class="none"></span>Plugin Builders</a></li>
<li><a href="../manual/extending.html#Custom_ContextDataInjector" title="Custom ContextDataInjector"><span class="none"></span>Custom ContextDataInjector</a></li>
<li><a href="../manual/extending.html#Custom_Plugins" title="Custom Plugins"><span class="none"></span>Custom Plugins</a></li>
</ul></li>
<li><a href="../manual/plugins.html" title="Plugins"><span class="icon-chevron-right"></span>Plugins</a></li>
<li><a href="../manual/customconfig.html" title="Programmatic Log4j Configuration"><span class="icon-chevron-right"></span>Programmatic Log4j Configuration</a></li>
<li><a href="../manual/customloglevels.html" title="Custom Log Levels"><span class="icon-chevron-right"></span>Custom Log Levels</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/tag.png" alt="Related Projects" border="0"/> Related Projects</li>
<li><a href="http://logging.apache.org/log4j/scala/index.html" class="externalLink" title="Log4j-Scala"><span class="none"></span>Log4j-Scala</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/link.png" alt="Legacy Sites" border="0"/> Legacy Sites</li>
<li><a href="http://logging.apache.org/log4j/1.2/" class="externalLink" title="Log4j 1.2 - End of Life"><span class="none"></span>Log4j 1.2 - End of Life</a></li>
<li><a href="http://logging.apache.org/log4j/log4j-2.3/" class="externalLink" title="Log4j 2.3 - Java 6"><span class="none"></span>Log4j 2.3 - Java 6</a></li>
<li><a href="http://logging.apache.org/log4j/log4j-2.12.1" class="externalLink" title="Log4j 2.12.1 - Java 7"><span class="none"></span>Log4j 2.12.1 - Java 7</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/cog.png" alt="Components" border="0"/> Components</li>
<li><a href="../log4j-api/index.html" title="API"><span class="none"></span>API</a></li>
<li><a href="../log4j-core/index.html" title="Implementation"><span class="none"></span>Implementation</a></li>
<li><a href="../log4j-jcl/index.html" title="Commons Logging Bridge"><span class="none"></span>Commons Logging Bridge</a></li>
<li><a href="../log4j-1.2-api/index.html" title="Log4j 1.2 API"><span class="none"></span>Log4j 1.2 API</a></li>
<li><a href="../log4j-slf4j-impl/index.html" title="SLF4J Binding"><span class="none"></span>SLF4J Binding</a></li>
<li><a href="../log4j-jul/index.html" title="JUL Adapter"><span class="none"></span>JUL Adapter</a></li>
<li><a href="../log4j-to-slf4j/index.html" title="Log4j 2 to SLF4J Adapter"><span class="none"></span>Log4j 2 to SLF4J Adapter</a></li>
<li><a href="../log4j-flume-ng/index.html" title="Apache Flume Appender"><span class="none"></span>Apache Flume Appender</a></li>
<li><a href="../log4j-taglib/index.html" title="Log4j Tag Library"><span class="none"></span>Log4j Tag Library</a></li>
<li><a href="../log4j-jmx-gui/index.html" title="Log4j JMX GUI"><span class="none"></span>Log4j JMX GUI</a></li>
<li><a href="../log4j-web/index.html" title="Log4j Web Application Support"><span class="none"></span>Log4j Web Application Support</a></li>
<li><a href="../log4j-appserver/index.html" title="Log4j Application Server Integration"><span class="none"></span>Log4j Application Server Integration</a></li>
<li><a href="../log4j-couchdb/index.html" title="Log4j CouchDB appender"><span class="none"></span>Log4j CouchDB appender</a></li>
<li><a href="../log4j-mongodb2/index.html" title="Log4j MongoDB2 appender"><span class="none"></span>Log4j MongoDB2 appender</a></li>
<li><a href="../log4j-mongodb3/index.html" title="Log4j MongoDB3 appender"><span class="none"></span>Log4j MongoDB3 appender</a></li>
<li><a href="../log4j-cassandra/index.html" title="Log4j Cassandra appender"><span class="none"></span>Log4j Cassandra appender</a></li>
<li><a href="../log4j-iostreams/index.html" title="Log4j IO Streams"><span class="none"></span>Log4j IO Streams</a></li>
<li><a href="../log4j-liquibase/index.html" title="Log4j Liquibase Binding"><span class="none"></span>Log4j Liquibase Binding</a></li>
<li><a href="../log4j-docker/index.html" title="Log4j Docker Support"><span class="none"></span>Log4j Docker Support</a></li>
<li><a href="../log4j-spring-cloud-config/log4j-spring-cloud-config-client/index.html" title="Log4j Spring Cloud Config Client"><span class="none"></span>Log4j Spring Cloud Config Client</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/info.png" alt="Project Information" border="0"/> Project Information</li>
<li><a href="../dependency-convergence.html" title="Dependency Convergence"><span class="none"></span>Dependency Convergence</a></li>
<li><a href="../dependency-management.html" title="Dependency Management"><span class="none"></span>Dependency Management</a></li>
<li><a href="../team-list.html" title="Project Team"><span class="none"></span>Project Team</a></li>
<li><a href="../mail-lists.html" title="Mailing Lists"><span class="none"></span>Mailing Lists</a></li>
<li><a href="../issue-tracking.html" title="Issue Tracking"><span class="none"></span>Issue Tracking</a></li>
<li><a href="../license.html" title="Project License"><span class="none"></span>Project License</a></li>
<li><a href="../source-repository.html" title="Source Repository"><span class="none"></span>Source Repository</a></li>
<li><a href="../project-summary.html" title="Project Summary"><span class="none"></span>Project Summary</a></li>
<li class="nav-header"><img class="imageLink" src="../img/glyphicons/layers.png" alt="Project Reports" border="0"/> Project Reports</li>
<li><a href="../changes-report.html" title="Changes Report"><span class="none"></span>Changes Report</a></li>
<li><a href="../jira-report.html" title="JIRA Report"><span class="none"></span>JIRA Report</a></li>
<li><a href="../rat-report.html" title="RAT Report"><span class="none"></span>RAT Report</a></li>
</ul>
</nav>
<div class="well sidebar-nav">
<hr />
<div id="poweredBy">
<div class="clear"></div>
<div class="clear"></div>
<div class="clear"></div>
<a href="http://maven.apache.org/" title="Built by Maven" class="poweredBy"><img class="builtBy" alt="Built by Maven" src="../images/logos/maven-feather.png" /></a>
</div>
</div>
</header>
<main id="bodyColumn" class="span10" >
<section>
<h2><a name="Extending_Log4j"></a>Extending Log4j</h2>
<p>
Log4j 2 provides numerous ways that it can be manipulated and extended. This section includes an
overview of the various ways that are directly supported by the Log4j 2 implementation.
</p>
<section>
<h3><a name="LoggerContextFactory"></a>LoggerContextFactory</h3>
<p>
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 extendsorg.apache.logging.log4j.spi.Provider and should have a
no-arg constructor that delegates to Provider's constructor passing the <var>Priority</var>,
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 <var>Priority</var> 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.
</p>
<p>
Applications may change the LoggerContextFactory that will be used by
</p>
<ol style="list-style-type: decimal">
<li>Create a binding to the logging implementation.
<ol style="list-style-type: lower-alpha">
<li>Implement a new LoggerContextFactory.</li>
<li>Implement a class that extends org.apache.logging.spi.Provider. with a no-arg
constructor that calls super-class's constructor with the <var>Priority</var>, the API version(s),
LoggerContextFactory class, and optionally, a ThreadContextMap
implementation class.</li>
<li>Create a META-INF/services/org.apache.logging.spi.Provider file that contains the
name of the class that implements org.apache.logging.spi.Provider.
</li>
</ol></li>
<li>Setting the system property <var>log4j2.loggerContextFactory</var> to the name of the
LoggerContextFactory class to use.
</li>
<li>Setting the property &quot;log4j2.loggerContextFactory&quot; in a properties file named
&quot;log4j2.LogManager.properties&quot; to the name of the LoggerContextFactory class to use. The properties
file must be on the classpath.
</li>
</ol>
</section>
<section>
<h3><a name="ContextSelector"></a>ContextSelector</h3>
<p>
ContextSelectors are called by the
<a href="../log4j-core/apidocs/org/apache/logging/log4j/core/impl/Log4jContextFactory.html">Log4j
LoggerContext factory</a>. 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 &quot;Log4jContextSelector&quot;.
If found, the property is expected to contain the name of the Class that implements the
ContextSelector to be used.
</p>
<p>
Log4j provides five ContextSelectors:
</p>
<dl>
<dt><a href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/BasicContextSelector.html" class="javadoc">BasicContextSelector</a></dt>
<dd>Uses either a LoggerContext that has been stored in a ThreadLocal or a common LoggerContext.</dd>
<dt><a href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html" class="javadoc">ClassLoaderContextSelector</a></dt>
<dd>Associates LoggerContexts with the ClassLoader that created the caller of the getLogger call. This is
the default ContextSelector.</dd>
<dt><a href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/JndiContextSelector.html" class="javadoc">JndiContextSelector</a></dt>
<dd>Locates the LoggerContext by querying JNDI.</dd>
<dt><a href="../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html" class="javadoc">AsyncLoggerContextSelector</a></dt>
<dd>Creates a LoggerContext that ensures that all loggers are AsyncLoggers.</dd>
<dt><a href="../log4j-core/apidocs/org/apache/logging/log4j/core/osgi/BundleContextSelector.html" class="javadoc">BundleContextSelector</a></dt>
<dd>Associates LoggerContexts with the ClassLoader of the bundle that created the caller of the getLogger
call. This is enabled by default in OSGi environments.</dd>
</dl>
</section>
<section>
<h3><a name="ConfigurationFactory"></a>ConfigurationFactory</h3>
<p>
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
<a href="../log4j-core/apidocs/org/apache/logging/log4j/core/config/ConfigurationFactory.html">ConfigurationFactory</a>.
Log4j provides two ways of adding new ConfigurationFactories. The first is by defining the system
property named &quot;log4j.configurationFactory&quot; 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.
</p>
<p>
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.
</p>
<p>
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.
</p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;XMLConfigurationFactory&quot;, category = &quot;ConfigurationFactory&quot;)
@Order(5)
public class XMLConfigurationFactory extends ConfigurationFactory {
/**
* Valid file extensions for XML files.
*/
public static final String[] SUFFIXES = new String[] {&quot;.xml&quot;, &quot;*&quot;};
/**
* 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;
}
}</pre></div>
</section>
<section>
<h3><a name="LoggerConfig"></a>LoggerConfig</h3>
<p>
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 &quot;Core&quot; 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.
</p>
<p>
The following example shows how the root LoggerConfig simply extends a generic LoggerConfig.
</p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;root&quot;, category = &quot;Core&quot;, printObject = true)
public static class RootLogger extends LoggerConfig {
@PluginFactory
public static LoggerConfig createLogger(@PluginAttribute(value = &quot;additivity&quot;, defaultBooleanValue = true) boolean additivity,
@PluginAttribute(value = &quot;level&quot;, defaultStringValue = &quot;ERROR&quot;) Level level,
@PluginElement(&quot;AppenderRef&quot;) AppenderRef[] refs,
@PluginElement(&quot;Filters&quot;) Filter filter) {
List&lt;AppenderRef&gt; appenderRefs = Arrays.asList(refs);
return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additivity);
}
}</pre></div>
</section>
<section>
<h3><a name="LogEventFactory"></a>LogEventFactory</h3>
<p>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. </p>
<p>Note: When log4j is configured to have <a href="async.html#AllAsync">all loggers asynchronous</a>,
log events are pre-allocated in a ring buffer and the LogEventFactory is not used.</p>
</section>
<section>
<h3><a name="MessageFactory"></a>MessageFactory</h3>
<p>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. </p>
<p>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.
</p>
</section>
<section>
<h3><a name="Lookups"></a>Lookups</h3>
<p>
Lookups are the means in which parameter substitution is performed. During Configuration initialization
an &quot;Interpolator&quot; is created that locates all the Lookups and registers them for use when a variable
needs to be resolved. The interpolator matches the &quot;prefix&quot; portion of the variable name to a
registered Lookup and passes control to it to resolve the variable.
</p>
<p>
A Lookup must be declared using a Plugin annotation with a type of &quot;Lookup&quot;. 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.
</p>
<p>The provided Lookups are documented here: <a href="./lookups.html">Lookups</a></p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;sys&quot;, category = &quot;Lookup&quot;)
public class SystemPropertiesLookup implements StrLookup {
/**
* 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);
}
}</pre></div>
</section>
<section>
<h3><a name="Filters"></a>Filters</h3>
<p>
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 &quot;Core&quot; and an elementType of
&quot;filter&quot;. 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 &quot;true&quot;
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.
</p>
<p>
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.
</p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;ThresholdFilter&quot;, category = &quot;Core&quot;, elementType = &quot;filter&quot;, printObject = true)
public final class ThresholdFilter extends AbstractFilter {
private final Level level;
private ThresholdFilter(Level level, Result onMatch, Result onMismatch) {
super(onMatch, onMismatch);
this.level = level;
}
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());
}
private Result filter(Level level) {
return level.isAtLeastAsSpecificAs(this.level) ? onMatch : onMismatch;
}
@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 = &quot;level&quot;, defaultStringValue = &quot;ERROR&quot;) Level level,
@PluginAttribute(value = &quot;onMatch&quot;, defaultStringValue = &quot;NEUTRAL&quot;) Result onMatch,
@PluginAttribute(value = &quot;onMismatch&quot;, defaultStringValue = &quot;DENY&quot;) Result onMismatch) {
return new ThresholdFilter(level, onMatch, onMismatch);
}
}</pre></div>
</section>
<section>
<h3><a name="Appenders"></a>Appenders</h3>
<p>
Appenders are passed an event, (usually) invoke a Layout to format the event, and then &quot;publish&quot;
the event in whatever manner is desired. Appenders are declared as Plugins with a type of &quot;Core&quot;
and an elementType of &quot;appender&quot;. 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 &quot;true&quot; if the toString method renders the values of the attributes passed
to the Appender.
</p>
<p>
Appenders must also declare a PluginFactory method that will create the appender. The example
below shows an Appender named &quot;Stub&quot; that can be used as an initial template.
</p>
<p>
Most Appenders use Managers. A manager actually &quot;owns&quot; 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.
</p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;Stub&quot;, category = &quot;Core&quot;, elementType = &quot;appender&quot;, printObject = true)
public final class StubAppender extends AbstractOutputStreamAppender&lt;StubManager&gt; {
private StubAppender(String name,
Layout&lt;? extends Serializable&gt; layout,
Filter filter,
boolean ignoreExceptions,
StubManager manager) {
super(name, layout, filter, ignoreExceptions, true, manager);
}
@PluginFactory
public static StubAppender createAppender(@PluginAttribute(&quot;name&quot;) String name,
@PluginAttribute(&quot;ignoreExceptions&quot;) boolean ignoreExceptions,
@PluginElement(&quot;Layout&quot;) Layout layout,
@PluginElement(&quot;Filters&quot;) Filter filter) {
if (name == null) {
LOGGER.error(&quot;No name provided for StubAppender&quot;);
return null;
}
StubManager manager = StubManager.getStubManager(name);
if (manager == null) {
return null;
}
if (layout == null) {
layout = PatternLayout.createDefaultLayout();
}
return new StubAppender(name, layout, filter, ignoreExceptions, manager);
}
}</pre></div>
</section>
<section>
<h3><a name="Layouts"></a>Layouts</h3>
<p>
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.
</p>
<p>
Every Layout must declare itself as a plugin using the Plugin annotation. The type must be &quot;Core&quot;,
and the elementType must be &quot;layout&quot;. 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.
</p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;SampleLayout&quot;, category = &quot;Core&quot;, elementType = &quot;layout&quot;, printObject = true)
public class SampleLayout extends AbstractStringLayout {
protected SampleLayout(boolean locationInfo, boolean properties, boolean complete,
Charset charset) {
}
@PluginFactory
public static SampleLayout createLayout(@PluginAttribute(&quot;locationInfo&quot;) boolean locationInfo,
@PluginAttribute(&quot;properties&quot;) boolean properties,
@PluginAttribute(&quot;complete&quot;) boolean complete,
@PluginAttribute(value = &quot;charset&quot;, defaultStringValue = &quot;UTF-8&quot;) Charset charset) {
return new SampleLayout(locationInfo, properties, complete, charset);
}
}</pre></div>
</section>
<section>
<h3><a name="PatternConverters"></a>PatternConverters</h3>
<p>
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.
</p>
<p>
A PatternConverter must first declare itself as a Plugin using the standard Plugin annotation but
must specify value of &quot;Converter&quot; 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.
</p>
<p>
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.
</p>
<p>
The following shows the skeleton of a Converter plugin.
</p>
<div>
<pre class="prettyprint linenums">
@Plugin(name = &quot;query&quot;, category = &quot;Converter&quot;)
@ConverterKeys({&quot;q&quot;, &quot;query&quot;})
public final class QueryConverter extends LogEventPatternConverter {
public QueryConverter(String[] options) {
}
public static QueryConverter newInstance(final String[] options) {
return new QueryConverter(options);
}
}</pre></div>
</section>
<section>
<h3><a name="Plugin_Builders"></a>Plugin Builders</h3>
<p>
Some plugins take a lot of optional configuration options. When a plugin takes many options, it is more
maintainable to use a builder class rather than a factory method (see <i>Item 2: Consider a builder when
faced with many constructor parameters</i> in <i>Effective Java</i> by Joshua Bloch). There are some other
advantages to using an annotated builder class over an annotated factory method:
</p>
<ul>
<li>Attribute names don't need to be specified if they match the field name.</li>
<li>Default values can be specified in code rather than through an annotation (also allowing a
runtime-calculated default value which isn't allowed in annotations).</li>
<li>Adding new optional parameters doesn't require existing programmatic configuration to be refactored.</li>
<li>Easier to write unit tests using builders rather than factory methods with optional parameters.</li>
<li>Default values are specified via code rather than relying on reflection and injection, so they work
programmatically as well as in a configuration file.</li>
</ul>
<p>
Here is an example of a plugin factory from ListAppender:
</p>
<div>
<pre class="prettyprint linenums">
@PluginFactory
public static ListAppender createAppender(
@PluginAttribute(&quot;name&quot;) @Required(message = &quot;No name provided for ListAppender&quot;) final String name,
@PluginAttribute(&quot;entryPerNewLine&quot;) final boolean newLine,
@PluginAttribute(&quot;raw&quot;) final boolean raw,
@PluginElement(&quot;Layout&quot;) final Layout&lt;? extends Serializable&gt; layout,
@PluginElement(&quot;Filter&quot;) final Filter filter) {
return new ListAppender(name, filter, layout, newLine, raw);
}</pre></div>
<p>
Here is that same factory using a builder pattern instead:
</p>
<div>
<pre class="prettyprint linenums">
@PluginBuilderFactory
public static Builder newBuilder() {
return new Builder();
}
public static class Builder implements org.apache.logging.log4j.core.util.Builder&lt;ListAppender&gt; {
@PluginBuilderAttribute
@Required(message = &quot;No name provided for ListAppender&quot;)
private String name;
@PluginBuilderAttribute
private boolean entryPerNewLine;
@PluginBuilderAttribute
private boolean raw;
@PluginElement(&quot;Layout&quot;)
private Layout&lt;? extends Serializable&gt; layout;
@PluginElement(&quot;Filter&quot;)
private Filter filter;
public Builder setName(final String name) {
this.name = name;
return this;
}
public Builder setEntryPerNewLine(final boolean entryPerNewLine) {
this.entryPerNewLine = entryPerNewLine;
return this;
}
public Builder setRaw(final boolean raw) {
this.raw = raw;
return this;
}
public Builder setLayout(final Layout&lt;? extends Serializable&gt; layout) {
this.layout = layout;
return this;
}
public Builder setFilter(final Filter filter) {
this.filter = filter;
return this;
}
@Override
public ListAppender build() {
return new ListAppender(name, filter, layout, entryPerNewLine, raw);
}
}</pre></div>
<p>
The only difference in annotations is using @PluginBuilderAttribute instead of
@PluginAttribute so that default values and reflection can be used instead of specifying
them in the annotation. Either annotation can be used in a builder, but the former is better suited
for field injection while the latter is better suited for parameter injection. Otherwise, the same
annotations (@PluginConfiguration, @PluginElement, @PluginNode,
and @PluginValue) are all supported on fields. Note that a factory method is still required
to supply a builder, and this factory method should be annotated with @PluginBuilderFactory.
</p>
<p>
When plugins are being constructed after a configuration has been parsed, a plugin builder will be used
if available, otherwise a plugin factory method will be used as a fallback. If a plugin contains neither
factory, then it cannot be used from a configuration file (it can still be used programmatically of
course).
</p>
<p>
Here is an example of using a plugin factory versus a plugin builder programmatically:
</p>
<div>
<pre class="prettyprint linenums">
ListAppender list1 = ListAppender.createAppender(&quot;List1&quot;, true, false, null, null);
ListAppender list2 = ListAppender.newBuilder().setName(&quot;List1&quot;).setEntryPerNewLine(true).build();
</pre></div>
</section>
<section>
<h3><a name="Custom_ContextDataInjector"></a>Custom ContextDataInjector</h3>
<p>
The ContextDataInjector (introduced in Log4j 2.7) is responsible for
populating the LogEvent's
<a href="../log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextData" class="javadoc">context data</a>
with key-value pairs or replacing it completely.
The default implementation is ThreadContextDataInjector, which obtains context attributes from the ThreadContext.
</p>
<p>
Applications may replace the default ContextDataInjector by setting the value of the system property
log4j2.contextDataInjector to the name of the custom ContextDataInjector class.
</p>
<p>
Implementors should be aware there are some subtleties related to thread-safety and implementing a
context data injector in a garbage-free manner.
See the <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html" class="javadoc">ContextDataInjector</a>
javadoc for detail.
</p>
</section>
<section>
<h3><a name="Custom_ThreadContextMap_implementations"></a>Custom ThreadContextMap implementations</h3>
<p>
A garbage-free StringMap-based context map can be installed by setting system property log4j2.garbagefreeThreadContextMap
to true. (Log4j must be <a href="garbagefree.html#Config">enabled</a> to use ThreadLocals.)
</p>
<p>
Any custom ThreadContextMap implementation can be installed by setting system property
log4j2.threadContextMap to the fully qualified class name of the class implementing the
ThreadContextMap interface. By also implementing the ReadOnlyThreadContextMap interface, your custom
ThreadContextMap implementation will be accessible to applications via the
<a href="../log4j-api/apidocs/org/apache/logging/log4j/ThreadContext.html#getThreadContextMap">ThreadContext::getThreadContextMap</a>
method.
</p>
</section>
<section>
<h3><a name="Custom_Plugins"></a>Custom Plugins</h3>
<p>See the <a href="plugins.html">Plugins</a> section of the manual.</p>
</section>
</section>
</main>
</div>
</div>
<hr/>
<footer>
<div class="container-fluid">
<div class="row-fluid">
<p align="center">Copyright &copy; 1999-2020 <a class="external" href="http://www.apache.org">The Apache Software Foundation</a>. All Rights Reserved.<br>
Apache Logging, Apache Log4j, Log4j, Apache, the Apache feather logo, and the Apache Logging project logo are trademarks of The Apache Software Foundation.</p>
</div>
</div>
</footer>
</body>
</html>