"Fossies" - the Fresh Open Source Software Archive

Member "apache-log4j-2.12.4-src/src/site/xdoc/manual/extending.xml" (20 Dec 2021, 31443 Bytes) of package /linux/misc/apache-log4j-2.12.4-src.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) XML source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. See also the last Fossies "Diffs" side-by-side code changes report for "extending.xml": 2.18.0_vs_2.19.0.

    1 <?xml version="1.0"?>
    2 <!--
    3     Licensed to the Apache Software Foundation (ASF) under one or more
    4     contributor license agreements.  See the NOTICE file distributed with
    5     this work for additional information regarding copyright ownership.
    6     The ASF licenses this file to You under the Apache License, Version 2.0
    7     (the "License"); you may not use this file except in compliance with
    8     the License.  You may obtain a copy of the License at
    9 
   10          http://www.apache.org/licenses/LICENSE-2.0
   11 
   12     Unless required by applicable law or agreed to in writing, software
   13     distributed under the License is distributed on an "AS IS" BASIS,
   14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15     See the License for the specific language governing permissions and
   16     limitations under the License.
   17 -->
   18 
   19 <document xmlns="http://maven.apache.org/XDOC/2.0"
   20           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   21           xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
   22     <properties>
   23         <title>Extending Log4j 2</title>
   24         <author email="rgoers@apache.org">Ralph Goers</author>
   25     </properties>
   26 <!-- TODO: add in documentation regarding typed attributes -->
   27     <body>
   28       <section name="Extending Log4j">
   29         <p>
   30           Log4j 2 provides numerous ways that it can be manipulated and extended. This section includes an
   31           overview of the various ways that are directly supported by the Log4j 2 implementation.
   32         </p>
   33           <subsection name="LoggerContextFactory">
   34             <p>
   35               The <code>LoggerContextFactory</code> binds the Log4j API to its implementation. The Log4j
   36               <code>LogManager</code> locates a <code>LoggerContextFactory</code> by using java.util.ServiceLoader
   37               to locate all instances of <code>org.apache.logging.log4j.spi.Provider</code>. Each implementation must
   38               provide a class that extends<code>org.apache.logging.log4j.spi.Provider</code> and should have a
   39               no-arg constructor that delegates to Provider's constructor passing the <var>Priority</var>,
   40               the API versions it is compatible with, and the class that implements
   41               <code>org.apache.logging.log4j.spi.LoggerContextFactory</code>. Log4j will compare the current API
   42               version and if it is compatible the implementation will be added to the list of providers. The
   43               API version in <code>org.apache.logging.log4j.LogManager</code> is only changed when a feature is added
   44               to the API that implementations need to be aware of. If more than one valid implementation is located
   45               the value for the <var>Priority</var> will be used to identify the factory with the highest priority.
   46               Finally, the class that implements <code>org.apache.logging.log4j.spi.LoggerContextFactory</code> will be
   47               instantiated and bound to the LogManager. In Log4j 2 this is provided by <code>Log4jContextFactory</code>.
   48             </p>
   49             <p>
   50               Applications may change the LoggerContextFactory that will be used by
   51             </p>
   52             <ol>
   53               <li>Create a binding to the logging implementation.
   54               <ol style="list-style-type: lower-alpha">
   55                 <li>Implement a new <code>LoggerContextFactory</code>.</li>
   56                 <li>Implement a class that extends <code>org.apache.logging.spi.Provider.</code> with a no-arg
   57                   constructor that calls super-class's constructor with the <var>Priority</var>, the API version(s),
   58                   <code>LoggerContextFactory</code> class, and optionally, a <code>ThreadContextMap</code>
   59                   implementation class.</li>
   60                 <li>Create a <code>META-INF/services/org.apache.logging.spi.Provider</code> file that contains the
   61                   name of the class that implements <code>org.apache.logging.spi.Provider</code>.
   62                 </li>
   63               </ol></li>
   64               <li>Setting the system property <var>log4j2.loggerContextFactory</var> to the name of the
   65                 <code>LoggerContextFactory</code> class to use.
   66               </li>
   67               <li>Setting the property "log4j2.loggerContextFactory" in a properties file named
   68                 "log4j2.LogManager.properties" to the name of the LoggerContextFactory class to use. The properties
   69                 file must be on the classpath.
   70               </li>
   71             </ol>
   72           </subsection>
   73           <subsection name="ContextSelector">
   74             <p>
   75               ContextSelectors are called by the
   76               <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/impl/Log4jContextFactory.html">Log4j
   77               LoggerContext factory</a>. They perform the actual work of
   78               locating or creating a LoggerContext, which is the anchor for Loggers and their configuration.
   79               ContextSelectors are free to implement any mechanism they desire to manage LoggerContexts. The
   80               default Log4jContextFactory checks for the presence of a System Property named "Log4jContextSelector".
   81               If found, the property is expected to contain the name of the Class that implements the
   82               ContextSelector to be used.
   83             </p>
   84             <p>
   85               Log4j provides five ContextSelectors:
   86             </p>
   87             <dl>
   88               <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/BasicContextSelector.html">BasicContextSelector</a></dt>
   89               <dd>Uses either a LoggerContext that has been stored in a ThreadLocal or a common LoggerContext.</dd>
   90               <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html">ClassLoaderContextSelector</a></dt>
   91               <dd>Associates LoggerContexts with the ClassLoader that created the caller of the getLogger call. This is
   92               the default ContextSelector.</dd>
   93               <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/JndiContextSelector.html">JndiContextSelector</a></dt>
   94               <dd>Locates the LoggerContext by querying JNDI.</dd>
   95               <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html">AsyncLoggerContextSelector</a></dt>
   96               <dd>Creates a LoggerContext that ensures that all loggers are AsyncLoggers.</dd>
   97               <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/osgi/BundleContextSelector.html">BundleContextSelector</a></dt>
   98               <dd>Associates LoggerContexts with the ClassLoader of the bundle that created the caller of the getLogger
   99               call. This is enabled by default in OSGi environments.</dd>
  100             </dl>
  101           </subsection>
  102           <subsection name="ConfigurationFactory">
  103             <p>
  104               Modifying the way in which logging can be configured is usually one of the areas with the most
  105               interest. The primary method for doing that is by implementing or extending a
  106               <a href="../log4j-core/apidocs/org/apache/logging/log4j/core/config/ConfigurationFactory.html">ConfigurationFactory</a>.
  107               Log4j provides two ways of adding new ConfigurationFactories. The first is by defining the system
  108               property named "log4j.configurationFactory" to the name of the class that should be searched first
  109               for a configuration. The second method is by defining the ConfigurationFactory as a Plugin.
  110             </p>
  111             <p>
  112               All the ConfigurationFactories are then processed in order. Each factory is called on its
  113               getSupportedTypes method to determine the file extensions it supports. If a configuration file
  114               is located with one of the specified file extensions then control is passed to that
  115               ConfigurationFactory to load the configuration and create the Configuration object.
  116             </p>
  117             <p>
  118               Most Configuration extend the BaseConfiguration class. This class expects that the subclass will
  119               process the configuration file and create a hierarchy of Node objects. Each Node is fairly simple
  120               in that it consists of the name of the node, the name/value pairs associated with the node, The
  121               PluginType of the node and a List of all of its child Nodes. BaseConfiguration will then be
  122               passed the Node tree and instantiate the configuration objects from that.
  123             </p>
  124             <pre class="prettyprint linenums">
  125 @Plugin(name = "XMLConfigurationFactory", category = "ConfigurationFactory")
  126 @Order(5)
  127 public class XMLConfigurationFactory extends ConfigurationFactory {
  128 
  129     /**
  130      * Valid file extensions for XML files.
  131      */
  132     public static final String[] SUFFIXES = new String[] {".xml", "*"};
  133 
  134     /**
  135      * Returns the Configuration.
  136      * @param loggerContext The logger context.
  137      * @param source The InputSource.
  138      * @return The Configuration.
  139      */
  140     @Override
  141     public Configuration getConfiguration(final LoggerContext loggerContext, final ConfigurationSource source) {
  142         return new XmlConfiguration(loggerContext, source);
  143     }
  144 
  145     /**
  146      * Returns the file suffixes for XML files.
  147      * @return An array of File extensions.
  148      */
  149     public String[] getSupportedTypes() {
  150         return SUFFIXES;
  151     }
  152 }</pre>
  153           </subsection>
  154           <subsection name="LoggerConfig">
  155             <p>
  156               LoggerConfig objects are where Loggers created by applications tie into the configuration. The Log4j
  157               implementation requires that all LoggerConfigs be based on the LoggerConfig class, so applications
  158               wishing to make changes must do so by extending the LoggerConfig class. To declare the new
  159               LoggerConfig, declare it as a Plugin of type "Core" and providing the name that applications
  160               should specify as the element name in the configuration. The LoggerConfig should also define
  161               a PluginFactory that will create an instance of the LoggerConfig.
  162             </p>
  163             <p>
  164               The following example shows how the root LoggerConfig simply extends a generic LoggerConfig.
  165             </p>
  166             <pre class="prettyprint linenums"><![CDATA[
  167 @Plugin(name = "root", category = "Core", printObject = true)
  168 public static class RootLogger extends LoggerConfig {
  169 
  170     @PluginFactory
  171     public static LoggerConfig createLogger(@PluginAttribute(value = "additivity", defaultBooleanValue = true) boolean additivity,
  172                                             @PluginAttribute(value = "level", defaultStringValue = "ERROR") Level level,
  173                                             @PluginElement("AppenderRef") AppenderRef[] refs,
  174                                             @PluginElement("Filters") Filter filter) {
  175         List<AppenderRef> appenderRefs = Arrays.asList(refs);
  176         return new LoggerConfig(LogManager.ROOT_LOGGER_NAME, appenderRefs, filter, level, additivity);
  177     }
  178 }]]></pre>
  179           </subsection>
  180           <subsection name="LogEventFactory">
  181             <p>A LogEventFactory is used to generate LogEvents. Applications may replace the standard LogEventFactory
  182               by setting the value of the system property Log4jLogEventFactory to the name of the custom
  183               LogEventFactory class. </p>
  184             <p>Note: When log4j is configured to have <a href="async.html#AllAsync">all loggers asynchronous</a>,
  185               log events are pre-allocated in a ring buffer and the LogEventFactory is not used.</p>
  186           </subsection>
  187         <subsection name="MessageFactory">
  188           <p>A MessageFactory is used to generate Message objects. Applications may replace the standard
  189             ParameterizedMessageFactory (or ReusableMessageFactory in garbage-free mode)
  190             by setting the value of the system property log4j2.messageFactory to the name of the custom
  191             MessageFactory class. </p>
  192           <p>Flow messages for the <tt>Logger.entry()</tt> and <tt>Logger.exit()</tt> methods have a separate FlowMessageFactory.
  193             Applications may replace the DefaultFlowMessageFactory by setting the value of the system property
  194             log4j2.flowMessageFactory to the name of the custom FlowMessageFactory class.
  195           </p>
  196         </subsection>
  197           <subsection name="Lookups">
  198             <p>
  199               Lookups are the means in which parameter substitution is performed. During Configuration initialization
  200               an "Interpolator" is created that locates all the Lookups and registers them for use when a variable
  201               needs to be resolved. The interpolator matches the "prefix" portion of the variable name to a
  202               registered Lookup and passes control to it to resolve the variable.
  203             </p>
  204             <p>
  205               A Lookup must be declared using a Plugin annotation with a type of "Lookup". The name specified on
  206               the Plugin annotation will be used to match the prefix.  Unlike other Plugins, Lookups do not
  207               use a PluginFactory. Instead, they are required to provide a constructor that accepts no arguments.
  208               The example below shows a Lookup that will return the value of a System Property.
  209             </p>
  210             <p>The provided Lookups are documented here: <a href="./lookups.html">Lookups</a></p>
  211             <pre class="prettyprint linenums">
  212 @Plugin(name = "sys", category = "Lookup")
  213 public class SystemPropertiesLookup implements StrLookup {
  214 
  215     /**
  216      * Lookup the value for the key.
  217      * @param key  the key to be looked up, may be null
  218      * @return The value for the key.
  219      */
  220     public String lookup(String key) {
  221         return System.getProperty(key);
  222     }
  223 
  224     /**
  225      * Lookup the value for the key using the data in the LogEvent.
  226      * @param event The current LogEvent.
  227      * @param key  the key to be looked up, may be null
  228      * @return The value associated with the key.
  229      */
  230     public String lookup(LogEvent event, String key) {
  231         return System.getProperty(key);
  232     }
  233 }</pre>
  234           </subsection>
  235           <subsection name="Filters">
  236             <p>
  237               As might be expected, Filters are the used to reject or accept log events as they pass through the
  238               logging system. A Filter is declared using a Plugin annotation of type "Core" and an elementType of
  239               "filter". The name attribute on the Plugin annotation is used to specify the name of the element
  240               users should use to enable the Filter. Specifying the printObject attribute with a value of "true"
  241               indicates that a call to toString will format the arguments to the filter as the configuration
  242               is being processed. The Filter must also specify a PluginFactory method that will be called to
  243               create the Filter.
  244             </p>
  245             <p>
  246               The example below shows a Filter used to reject LogEvents based upon their logging level. Notice the
  247               typical pattern where all the filter methods resolve to a single filter method.
  248             </p>
  249             <pre class="prettyprint linenums">
  250 @Plugin(name = "ThresholdFilter", category = "Core", elementType = "filter", printObject = true)
  251 public final class ThresholdFilter extends AbstractFilter {
  252 
  253     private final Level level;
  254 
  255     private ThresholdFilter(Level level, Result onMatch, Result onMismatch) {
  256         super(onMatch, onMismatch);
  257         this.level = level;
  258     }
  259 
  260     public Result filter(Logger logger, Level level, Marker marker, String msg, Object[] params) {
  261         return filter(level);
  262     }
  263 
  264     public Result filter(Logger logger, Level level, Marker marker, Object msg, Throwable t) {
  265         return filter(level);
  266     }
  267 
  268     public Result filter(Logger logger, Level level, Marker marker, Message msg, Throwable t) {
  269         return filter(level);
  270     }
  271 
  272     @Override
  273     public Result filter(LogEvent event) {
  274         return filter(event.getLevel());
  275     }
  276 
  277     private Result filter(Level level) {
  278         return level.isAtLeastAsSpecificAs(this.level) ? onMatch : onMismatch;
  279     }
  280 
  281     @Override
  282     public String toString() {
  283         return level.toString();
  284     }
  285 
  286     /**
  287      * Create a ThresholdFilter.
  288      * @param loggerLevel The log Level.
  289      * @param match The action to take on a match.
  290      * @param mismatch The action to take on a mismatch.
  291      * @return The created ThresholdFilter.
  292      */
  293     @PluginFactory
  294     public static ThresholdFilter createFilter(@PluginAttribute(value = "level", defaultStringValue = "ERROR") Level level,
  295                                                @PluginAttribute(value = "onMatch", defaultStringValue = "NEUTRAL") Result onMatch,
  296                                                @PluginAttribute(value = "onMismatch", defaultStringValue = "DENY") Result onMismatch) {
  297         return new ThresholdFilter(level, onMatch, onMismatch);
  298     }
  299 }</pre>
  300           </subsection>
  301           <subsection name="Appenders">
  302             <p>
  303               Appenders are passed an event, (usually) invoke a Layout to format the event, and then "publish"
  304               the event in whatever manner is desired. Appenders are declared as Plugins with a type of "Core"
  305               and an elementType of "appender". The name attribute on the Plugin annotation specifies the name
  306               of the element users must provide in their configuration to use the Appender. Appenders should
  307               specify printObject as "true" if the toString method renders the values of the attributes passed
  308               to the Appender.
  309             </p>
  310             <p>
  311               Appenders must also declare a PluginFactory method that will create the appender. The example
  312               below shows an Appender named "Stub" that can be used as an initial template.
  313             </p>
  314             <p>
  315               Most Appenders use Managers. A manager actually "owns" the resources, such as an OutputStream or
  316               socket. When a reconfiguration occurs a new Appender will be created. However, if nothing significant
  317               in the previous Manager has changed, the new Appender will simply reference it instead of creating a
  318               new one. This insures that events are not lost while a reconfiguration is taking place without
  319               requiring that logging pause while the reconfiguration takes place.
  320             </p>
  321             <pre class="prettyprint linenums"><![CDATA[
  322 @Plugin(name = "Stub", category = "Core", elementType = "appender", printObject = true)
  323 public final class StubAppender extends AbstractOutputStreamAppender<StubManager> {
  324 
  325     private StubAppender(String name,
  326                          Layout<? extends Serializable> layout,
  327                          Filter filter,
  328                          boolean ignoreExceptions,
  329                          StubManager  manager) {
  330         super(name, layout, filter, ignoreExceptions, true, manager);
  331     }
  332 
  333     @PluginFactory
  334     public static StubAppender createAppender(@PluginAttribute("name") String name,
  335                                               @PluginAttribute("ignoreExceptions") boolean ignoreExceptions,
  336                                               @PluginElement("Layout") Layout layout,
  337                                               @PluginElement("Filters") Filter filter) {
  338 
  339         if (name == null) {
  340             LOGGER.error("No name provided for StubAppender");
  341             return null;
  342         }
  343 
  344         StubManager manager = StubManager.getStubManager(name);
  345         if (manager == null) {
  346             return null;
  347         }
  348         if (layout == null) {
  349             layout = PatternLayout.createDefaultLayout();
  350         }
  351         return new StubAppender(name, layout, filter, ignoreExceptions, manager);
  352     }
  353 }]]></pre>
  354           </subsection>
  355           <subsection name="Layouts">
  356             <p>
  357               Layouts perform the formatting of events into the printable text that is written by Appenders to
  358               some destination. All Layouts must implement the Layout interface. Layouts that format the
  359               event into a String should extend AbstractStringLayout, which will take care of converting the
  360               String into the required byte array.
  361             </p>
  362             <p>
  363               Every Layout must declare itself as a plugin using the Plugin annotation. The type must be "Core",
  364               and the elementType must be "layout". printObject should be set to true if the plugin's toString
  365               method will provide a representation of the object and its parameters. The name of the plugin must
  366               match the value users should use to specify it as an element in their Appender configuration.
  367               The plugin also must provide a static method annotated as a PluginFactory and with each of the
  368               methods parameters annotated with PluginAttr or PluginElement as appropriate.
  369             </p>
  370             <pre class="prettyprint linenums">
  371 @Plugin(name = "SampleLayout", category = "Core", elementType = "layout", printObject = true)
  372 public class SampleLayout extends AbstractStringLayout {
  373 
  374     protected SampleLayout(boolean locationInfo, boolean properties, boolean complete,
  375                            Charset charset) {
  376     }
  377 
  378     @PluginFactory
  379     public static SampleLayout createLayout(@PluginAttribute("locationInfo") boolean locationInfo,
  380                                             @PluginAttribute("properties") boolean properties,
  381                                             @PluginAttribute("complete") boolean complete,
  382                                             @PluginAttribute(value = "charset", defaultStringValue = "UTF-8") Charset charset) {
  383         return new SampleLayout(locationInfo, properties, complete, charset);
  384     }
  385 }</pre>
  386           </subsection>
  387           <subsection name="PatternConverters">
  388             <p>
  389               PatternConverters are used by the PatternLayout to format the log event into a printable String. Each
  390               Converter is responsible for a single kind of manipulation, however Converters are free to format
  391               the event in complex ways. For example, there are several converters that manipulate Throwables and
  392               format them in various ways.
  393             </p>
  394             <p>
  395               A PatternConverter must first declare itself as a Plugin using the standard Plugin annotation but
  396               must specify value of "Converter" on the type attribute. Furthermore, the Converter must also
  397               specify the ConverterKeys attribute to define the tokens that can be specified in the pattern
  398               (preceded by a '%' character) to identify the Converter.
  399             </p>
  400             <p>
  401               Unlike most other Plugins, Converters do not use a PluginFactory. Instead, each Converter is
  402               required to provide a static newInstance method that accepts an array of Strings as the only
  403               parameter. The String array are the values that are specified within the curly braces that can
  404               follow the converter key.
  405             </p>
  406             <p>
  407               The following shows the skeleton of a Converter plugin.
  408             </p>
  409             <pre class="prettyprint linenums">
  410 @Plugin(name = "query", category = "Converter")
  411 @ConverterKeys({"q", "query"})
  412 public final class QueryConverter extends LogEventPatternConverter {
  413 
  414     public QueryConverter(String[] options) {
  415     }
  416 
  417     public static QueryConverter newInstance(final String[] options) {
  418       return new QueryConverter(options);
  419     }
  420 }</pre>
  421           </subsection>
  422           <subsection name="Plugin Builders">
  423             <p>
  424               Some plugins take a lot of optional configuration options. When a plugin takes many options, it is more
  425               maintainable to use a builder class rather than a factory method (see <i>Item 2: Consider a builder when
  426               faced with many constructor parameters</i> in <i>Effective Java</i> by Joshua Bloch). There are some other
  427               advantages to using an annotated builder class over an annotated factory method:
  428             </p>
  429             <ul>
  430               <li>Attribute names don't need to be specified if they match the field name.</li>
  431               <li>Default values can be specified in code rather than through an annotation (also allowing a
  432               runtime-calculated default value which isn't allowed in annotations).</li>
  433               <li>Adding new optional parameters doesn't require existing programmatic configuration to be refactored.</li>
  434               <li>Easier to write unit tests using builders rather than factory methods with optional parameters.</li>
  435               <li>Default values are specified via code rather than relying on reflection and injection, so they work
  436               programmatically as well as in a configuration file.</li>
  437             </ul>
  438             <p>
  439               Here is an example of a plugin factory from <code>ListAppender</code>:
  440             </p>
  441             <pre class="prettyprint linenums"><![CDATA[
  442 @PluginFactory
  443 public static ListAppender createAppender(
  444         @PluginAttribute("name") @Required(message = "No name provided for ListAppender") final String name,
  445         @PluginAttribute("entryPerNewLine") final boolean newLine,
  446         @PluginAttribute("raw") final boolean raw,
  447         @PluginElement("Layout") final Layout<? extends Serializable> layout,
  448         @PluginElement("Filter") final Filter filter) {
  449     return new ListAppender(name, filter, layout, newLine, raw);
  450 }]]></pre>
  451             <p>
  452               Here is that same factory using a builder pattern instead:
  453             </p>
  454             <pre class="prettyprint linenums"><![CDATA[
  455 @PluginBuilderFactory
  456 public static Builder newBuilder() {
  457     return new Builder();
  458 }
  459 
  460 public static class Builder implements org.apache.logging.log4j.core.util.Builder<ListAppender> {
  461 
  462     @PluginBuilderAttribute
  463     @Required(message = "No name provided for ListAppender")
  464     private String name;
  465 
  466     @PluginBuilderAttribute
  467     private boolean entryPerNewLine;
  468 
  469     @PluginBuilderAttribute
  470     private boolean raw;
  471 
  472     @PluginElement("Layout")
  473     private Layout<? extends Serializable> layout;
  474 
  475     @PluginElement("Filter")
  476     private Filter filter;
  477 
  478     public Builder setName(final String name) {
  479         this.name = name;
  480         return this;
  481     }
  482 
  483     public Builder setEntryPerNewLine(final boolean entryPerNewLine) {
  484         this.entryPerNewLine = entryPerNewLine;
  485         return this;
  486     }
  487 
  488     public Builder setRaw(final boolean raw) {
  489         this.raw = raw;
  490         return this;
  491     }
  492 
  493     public Builder setLayout(final Layout<? extends Serializable> layout) {
  494         this.layout = layout;
  495         return this;
  496     }
  497 
  498     public Builder setFilter(final Filter filter) {
  499         this.filter = filter;
  500         return this;
  501     }
  502 
  503     @Override
  504     public ListAppender build() {
  505         return new ListAppender(name, filter, layout, entryPerNewLine, raw);
  506     }
  507 }]]></pre>
  508             <p>
  509               The only difference in annotations is using <code>@PluginBuilderAttribute</code> instead of
  510               <code>@PluginAttribute</code> so that default values and reflection can be used instead of specifying
  511               them in the annotation. Either annotation can be used in a builder, but the former is better suited
  512               for field injection while the latter is better suited for parameter injection. Otherwise, the same
  513               annotations (<code>@PluginConfiguration</code>, <code>@PluginElement</code>, <code>@PluginNode</code>,
  514               and <code>@PluginValue</code>) are all supported on fields. Note that a factory method is still required
  515               to supply a builder, and this factory method should be annotated with <code>@PluginBuilderFactory</code>.
  516               <!-- TODO: this will change with LOG4J2-1188 -->
  517             </p>
  518             <p>
  519               When plugins are being constructed after a configuration has been parsed, a plugin builder will be used
  520               if available, otherwise a plugin factory method will be used as a fallback. If a plugin contains neither
  521               factory, then it cannot be used from a configuration file (it can still be used programmatically of
  522               course).
  523             </p>
  524             <p>
  525               Here is an example of using a plugin factory versus a plugin builder programmatically:
  526             </p>
  527             <pre class="prettyprint linenums"><![CDATA[
  528 ListAppender list1 = ListAppender.createAppender("List1", true, false, null, null);
  529 ListAppender list2 = ListAppender.newBuilder().setName("List1").setEntryPerNewLine(true).build();
  530 ]]></pre>
  531           </subsection>
  532         <subsection name="Custom ContextDataInjector">
  533           <p>
  534             The <code>ContextDataInjector</code> (introduced in Log4j 2.7) is responsible for
  535             populating the LogEvent's
  536             <a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextData()">context data</a>
  537             with key-value pairs or replacing it completely.
  538             The default implementation is ThreadContextDataInjector, which obtains context attributes from the ThreadContext.
  539           </p><p>
  540           Applications may replace the default ContextDataInjector by setting the value of the system property
  541           <tt>log4j2.contextDataInjector</tt> to the name of the custom ContextDataInjector class.
  542         </p><p>
  543           Implementors should be aware there are some subtleties related to thread-safety and implementing a
  544           context data injector in a garbage-free manner.
  545           See the <a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html">ContextDataInjector</a>
  546           javadoc for detail.
  547         </p>
  548         </subsection>
  549         <subsection name="Custom ThreadContextMap implementations">
  550           <p>
  551             A garbage-free StringMap-based context map can be installed by setting system property <tt>log4j2.garbagefreeThreadContextMap</tt>
  552             to true. (Log4j must be <a href="garbagefree.html#Config">enabled</a> to use ThreadLocals.)
  553           </p><p>
  554             Any custom <tt>ThreadContextMap</tt> implementation can be installed by setting system property
  555             <tt>log4j2.threadContextMap</tt> to the fully qualified class name of the class implementing the
  556             ThreadContextMap interface. By also implementing the <tt>ReadOnlyThreadContextMap</tt> interface, your custom
  557             ThreadContextMap implementation will be accessible to applications via the
  558           <a href="../log4j-api/apidocs/org/apache/logging/log4j/ThreadContext.html#getThreadContextMap()">ThreadContext::getThreadContextMap</a>
  559             method.
  560           </p>
  561         </subsection>
  562           <subsection name="Custom Plugins">
  563             <p>See the <a href="plugins.html">Plugins</a> section of the manual.</p>
  564 <!-- TODO: some documentation here! -->
  565           </subsection>
  566       </section>
  567 
  568     </body>
  569 </document>