You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ma...@apache.org on 2018/04/08 21:03:43 UTC

[2/7] logging-log4j2 git commit: LOG4J2-1802: Convert extending Log4j manual page to asciidoc

LOG4J2-1802: Convert extending Log4j manual page to asciidoc

Also has some documentation fixes


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7b4493f2
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7b4493f2
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7b4493f2

Branch: refs/heads/master
Commit: 7b4493f2205b997741b0a3b06eca214dcbeee459
Parents: 77a3712
Author: Matt Sicker <bo...@gmail.com>
Authored: Sun Apr 8 15:46:28 2018 -0500
Committer: Matt Sicker <bo...@gmail.com>
Committed: Sun Apr 8 16:03:36 2018 -0500

----------------------------------------------------------------------
 src/site/asciidoc/manual/extending.adoc | 624 +++++++++++++++++++++++++++
 src/site/xdoc/manual/extending.xml      | 565 ------------------------
 2 files changed, 624 insertions(+), 565 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b4493f2/src/site/asciidoc/manual/extending.adoc
----------------------------------------------------------------------
diff --git a/src/site/asciidoc/manual/extending.adoc b/src/site/asciidoc/manual/extending.adoc
new file mode 100644
index 0000000..db5a6f9
--- /dev/null
+++ b/src/site/asciidoc/manual/extending.adoc
@@ -0,0 +1,624 @@
+////
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements. See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License. You may obtain a copy of the License at
+
+        https://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+////
+= Extending Log4j 2
+Ralph Goers <rg...@apache.org>
+
+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.
+
+[#LoggerContextFactory]
+== 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
+
+1.  Create a binding to the logging implementation.
+..  Implement a new `LoggerContextFactory`.
+..  Implement a class that extends `org.apache.logging.spi.Provider.`
+with a no-arg constructor that calls super-class's constructor with the
+Priority, the API version(s), `LoggerContextFactory` class, and
+optionally, a `ThreadContextMap` implementation class.
+..  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`.
+2.  Setting the system property log4j2.loggerContextFactory to the name
+of the `LoggerContextFactory` class to use.
+3.  Setting the property "log4j2.loggerContextFactory" in a properties
+file named "log4j2.LogManager.properties" to the name of the
+LoggerContextFactory class to use. The properties file must be on the
+classpath.
+
+[#ContextSelector]
+== ContextSelector
+
+ContextSelectors are called by the
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[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:
+
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/selector/BasicContextSelector.html[`BasicContextSelector`]::
+  Uses either a LoggerContext that has been stored in a ThreadLocal or a
+  common LoggerContext.
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html[`ClassLoaderContextSelector`]::
+  Associates LoggerContexts with the ClassLoader that created the caller
+  of the getLogger call. This is the default ContextSelector.
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/selector/JndiContextSelector.html[`JndiContextSelector`]::
+  Locates the LoggerContext by querying JNDI.
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html[`AsyncLoggerContextSelector`]::
+  Creates a LoggerContext that ensures that all loggers are
+  AsyncLoggers.
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/osgi/BundleContextSelector.html[`BundleContextSelector`]::
+  Associates LoggerContexts with the ClassLoader of the bundle that
+  created the caller of the getLogger call. This is enabled by default
+  in OSGi environments.
+
+[#ConfigurationFactory]
+== 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
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/config/ConfigurationFactory.html[`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.
+
+[source,java]
+----
+@Plugin(name = "XMLConfigurationFactory", category = "ConfigurationFactory")
+@Order(5)
+public class XMLConfigurationFactory extends ConfigurationFactory {
+
+    /**
+     * 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;
+    }
+}
+----
+
+[#LoggerConfig]
+== 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`.
+
+[source,java]
+----
+@Plugin(name = "root", category = "Core", printObject = true)
+public static class RootLogger extends LoggerConfig {
+
+    @PluginFactory
+    public static LoggerConfig createLogger(@PluginAttribute(value = "additivity", defaultBooleanValue = true) boolean additivity,
+                                            @PluginAttribute(value = "level", defaultStringValue = "ERROR") Level level,
+                                            @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);
+    }
+}
+----
+
+[#LogEventFactory]
+== LogEventFactory
+
+A `LogEventFactory` is used to generate LogEvents. Applications may
+replace the standard `LogEventFactory` by setting the value of the system
+property `log4j2.logEventFactory` to the name of the custom `LogEventFactory`
+class.
+
+Note: When log4j is configured to have link:async.html#AllAsync[all
+loggers asynchronous], log events are pre-allocated in a ring buffer and
+the `LogEventFactory` is not used.
+
+[#MessageFactory]
+== 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.
+
+[#Lookups]
+== 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: link:./lookups.html[Lookups]
+
+[source,java]
+----
+@Plugin(name = "sys", category = "Lookup")
+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);
+    }
+}
+----
+
+[#Filters]
+== 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
+or `@PluginFactoryBuilder` builder class and 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.
+
+[source,java]
+----
+@Plugin(name = "ThresholdFilter", category = "Core", elementType = "filter", 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 = "level", defaultStringValue = "ERROR") Level level,
+                                               @PluginAttribute(value = "onMatch", defaultStringValue = "NEUTRAL") Result onMatch,
+                                               @PluginAttribute(value = "onMismatch", defaultStringValue = "DENY") Result onMismatch) {
+        return new ThresholdFilter(level, onMatch, onMismatch);
+    }
+}
+----
+
+[#Appenders]
+== 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 or `@PluginFactoryBuilder`
+builder class and 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.
+
+[source,java]
+----
+@Plugin(name = "Stub", category = "Core", elementType = "appender", printObject = true)
+public final class StubAppender extends OutputStreamAppender {
+
+    private StubAppender(String name, Layout layout, Filter filter, StubManager manager,
+                         boolean ignoreExceptions) {
+    }
+
+    @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;
+        }
+
+        StubManager manager = StubManager.getStubManager(name);
+        if (manager == null) {
+            return null;
+        }
+        if (layout == null) {
+            layout = PatternLayout.createDefaultLayout();
+        }
+        return new StubAppender(name, layout, filter, manager, ignoreExceptions);
+    }
+}
+----
+
+[#Layouts]
+== 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 `@PluginAttribute` or `@PluginElement` as
+appropriate. The plugin can alternatively use the plugin builder notation.
+
+[source,java]
+----
+@Plugin(name = "SampleLayout", category = "Core", elementType = "layout", printObject = true)
+public class SampleLayout extends AbstractStringLayout {
+
+    protected SampleLayout(boolean locationInfo, boolean properties, boolean complete,
+                           Charset charset) {
+    }
+
+    @PluginFactory
+    public static SampleLayout createLayout(@PluginAttribute("locationInfo") boolean locationInfo,
+                                            @PluginAttribute("properties") boolean properties,
+                                            @PluginAttribute("complete") boolean complete,
+                                            @PluginAttribute(value = "charset", defaultStringValue = "UTF-8") Charset charset) {
+        return new SampleLayout(locationInfo, properties, complete, charset);
+    }
+}
+----
+
+[#PatternConverters]
+== 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` annotation 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 `String` as the only parameter. The
+`String[]` is the values that are specified within the curly braces
+that can follow the converter key.
+
+The following shows the skeleton of a Converter plugin.
+
+[source,java]
+----
+@Plugin(name = "query", category = "Converter")
+@ConverterKeys({"q", "query"})
+public final class QueryConverter extends LogEventPatternConverter {
+
+    public QueryConverter(String[] options) {
+    }
+
+    public static QueryConverter newInstance(final String[] options) {
+      return new QueryConverter(options);
+    }
+}
+----
+
+[#Plugin_Builders]
+== Plugin Builders
+
+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 _Item 2: Consider a builder when faced
+with many constructor parameters_ in _Effective Java_ by Joshua Bloch).
+There are some other advantages to using an annotated builder class over
+an annotated factory method:
+
+* Attribute names don't need to be specified if they match the field
+name.
+* 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).
+* Adding new optional parameters doesn't require existing programmatic
+configuration to be refactored.
+* Easier to write unit tests using builders rather than factory methods
+with optional parameters.
+* Default values are specified via code rather than relying on
+reflection and injection, so they work programmatically as well as in a
+configuration file.
+
+Here is an example of a plugin factory from `ListAppender`:
+
+[source,java]
+----
+@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:
+
+[source,java]
+----
+@PluginBuilderFactory
+public static Builder newBuilder() {
+    return new Builder();
+}
+
+public static class Builder implements org.apache.logging.log4j.core.util.Builder<ListAppender> {
+
+    @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;
+
+    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<? extends Serializable> 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);
+    }
+}
+----
+
+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`.
+// TODO: this will change with LOG4J2-1188
+
+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).
+
+Here is an example of using a plugin factory versus a plugin builder
+programmatically:
+
+[source,java]
+----
+ListAppender list1 = ListAppender.createAppender("List1", true, false, null, null);
+ListAppender list2 = ListAppender.newBuilder().setName("List1").setEntryPerNewLine(true).build();
+----
+
+[#Custom_ContextDataInjector]
+== Custom ContextDataInjector
+
+The `ContextDataInjector` (introduced in Log4j 2.7) is responsible for
+populating the LogEvent's
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextData()[context
+data] with key-value pairs or replacing it completely. The default
+implementation is `ThreadContextDataInjector`, which obtains context
+attributes from the ThreadContext.
+
+Applications may replace the default `ContextDataInjector` by setting the
+value of the system property `log4j2.contextDataInjector` to the name of
+the custom `ContextDataInjector` class.
+
+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
+link:../log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html[`ContextDataInjector`]
+javadoc for detail.
+
+== Custom ThreadContextMap implementations
+
+A garbage-free `StringMap`-based context map can be installed by setting
+system property `log4j2.garbagefreeThreadContextMap` to true. (Log4j
+must be link:garbagefree.html#Config[enabled] to use ThreadLocals.)
+
+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
+link:../log4j-api/apidocs/org/apache/logging/log4j/ThreadContext.html#getThreadContextMap()[`ThreadContext::getThreadContextMap`]
+method.
+
+[#Custom_Plugins]
+== Custom Plugins
+
+// TODO
+See the link:plugins.html[Plugins] section of the manual.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7b4493f2/src/site/xdoc/manual/extending.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/extending.xml b/src/site/xdoc/manual/extending.xml
deleted file mode 100644
index ee0dd01..0000000
--- a/src/site/xdoc/manual/extending.xml
+++ /dev/null
@@ -1,565 +0,0 @@
-<?xml version="1.0"?>
-<!--
-    Licensed to the Apache Software Foundation (ASF) under one or more
-    contributor license agreements.  See the NOTICE file distributed with
-    this work for additional information regarding copyright ownership.
-    The ASF licenses this file to You under the Apache License, Version 2.0
-    (the "License"); you may not use this file except in compliance with
-    the License.  You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-
-<document xmlns="http://maven.apache.org/XDOC/2.0"
-          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-          xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
-    <properties>
-        <title>Extending Log4j 2</title>
-        <author email="rgoers@apache.org">Ralph Goers</author>
-    </properties>
-<!-- TODO: add in documentation regarding typed attributes -->
-    <body>
-      <section name="Extending Log4j">
-        <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>
-          <subsection name="LoggerContextFactory">
-            <p>
-              The <code>LoggerContextFactory</code> binds the Log4j API to its implementation. The Log4j
-              <code>LogManager</code> locates a <code>LoggerContextFactory</code> by using java.util.ServiceLoader
-              to locate all instances of <code>org.apache.logging.log4j.spi.Provider</code>. Each implementation must
-              provide a class that extends<code>org.apache.logging.log4j.spi.Provider</code> 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
-              <code>org.apache.logging.log4j.spi.LoggerContextFactory</code>. 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 <code>org.apache.logging.log4j.LogManager</code> 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 <code>org.apache.logging.log4j.spi.LoggerContextFactory</code> will be
-              instantiated and bound to the LogManager. In Log4j 2 this is provided by <code>Log4jContextFactory</code>.
-            </p>
-            <p>
-              Applications may change the LoggerContextFactory that will be used by
-            </p>
-            <ol>
-              <li>Create a binding to the logging implementation.
-              <ol style="list-style-type: lower-alpha">
-                <li>Implement a new <code>LoggerContextFactory</code>.</li>
-                <li>Implement a class that extends <code>org.apache.logging.spi.Provider.</code> with a no-arg
-                  constructor that calls super-class's constructor with the <var>Priority</var>, the API version(s),
-                  <code>LoggerContextFactory</code> class, and optionally, a <code>ThreadContextMap</code>
-                  implementation class.</li>
-                <li>Create a <code>META-INF/services/org.apache.logging.spi.Provider</code> file that contains the
-                  name of the class that implements <code>org.apache.logging.spi.Provider</code>.
-                </li>
-              </ol></li>
-              <li>Setting the system property <var>log4j2.loggerContextFactory</var> to the name of the
-                <code>LoggerContextFactory</code> class to use.
-              </li>
-              <li>Setting the property "log4j2.loggerContextFactory" in a properties file named
-                "log4j2.LogManager.properties" to the name of the LoggerContextFactory class to use. The properties
-                file must be on the classpath.
-              </li>
-            </ol>
-          </subsection>
-          <subsection name="ContextSelector">
-            <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 "Log4jContextSelector".
-              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 class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/BasicContextSelector.html">BasicContextSelector</a></dt>
-              <dd>Uses either a LoggerContext that has been stored in a ThreadLocal or a common LoggerContext.</dd>
-              <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/ClassLoaderContextSelector.html">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 class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/selector/JndiContextSelector.html">JndiContextSelector</a></dt>
-              <dd>Locates the LoggerContext by querying JNDI.</dd>
-              <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html">AsyncLoggerContextSelector</a></dt>
-              <dd>Creates a LoggerContext that ensures that all loggers are AsyncLoggers.</dd>
-              <dt><a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/osgi/BundleContextSelector.html">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>
-          </subsection>
-          <subsection name="ConfigurationFactory">
-            <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 "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.
-            </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>
-            <pre class="prettyprint linenums">
-@Plugin(name = "XMLConfigurationFactory", category = "ConfigurationFactory")
-@Order(5)
-public class XMLConfigurationFactory extends ConfigurationFactory {
-
-    /**
-     * 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;
-    }
-}</pre>
-          </subsection>
-          <subsection name="LoggerConfig">
-            <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 "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.
-            </p>
-            <p>
-              The following example shows how the root LoggerConfig simply extends a generic LoggerConfig.
-            </p>
-            <pre class="prettyprint linenums"><![CDATA[
-@Plugin(name = "root", category = "Core", printObject = true)
-public static class RootLogger extends LoggerConfig {
-
-    @PluginFactory
-    public static LoggerConfig createLogger(@PluginAttribute(value = "additivity", defaultBooleanValue = true) boolean additivity,
-                                            @PluginAttribute(value = "level", defaultStringValue = "ERROR") Level level,
-                                            @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);
-    }
-}]]></pre>
-          </subsection>
-          <subsection name="LogEventFactory">
-            <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>
-          </subsection>
-        <subsection name="MessageFactory">
-          <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 <tt>Logger.entry()</tt> and <tt>Logger.exit()</tt> 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>
-        </subsection>
-          <subsection name="Lookups">
-            <p>
-              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.
-            </p>
-            <p>
-              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.
-            </p>
-            <p>The provided Lookups are documented here: <a href="./lookups.html">Lookups</a></p>
-            <pre class="prettyprint linenums">
-@Plugin(name = "sys", category = "Lookup")
-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>
-          </subsection>
-          <subsection name="Filters">
-            <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 "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.
-            </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>
-            <pre class="prettyprint linenums">
-@Plugin(name = "ThresholdFilter", category = "Core", elementType = "filter", 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 = "level", defaultStringValue = "ERROR") Level level,
-                                               @PluginAttribute(value = "onMatch", defaultStringValue = "NEUTRAL") Result onMatch,
-                                               @PluginAttribute(value = "onMismatch", defaultStringValue = "DENY") Result onMismatch) {
-        return new ThresholdFilter(level, onMatch, onMismatch);
-    }
-}</pre>
-          </subsection>
-          <subsection name="Appenders">
-            <p>
-              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.
-            </p>
-            <p>
-              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.
-            </p>
-            <p>
-              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.
-            </p>
-            <pre class="prettyprint linenums">
-@Plugin(name = "Stub", category = "Core", elementType = "appender", printObject = true)
-public final class StubAppender extends OutputStreamAppender {
-
-    private StubAppender(String name, Layout layout, Filter filter, StubManager manager,
-                         boolean ignoreExceptions) {
-    }
-
-    @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;
-        }
-
-        StubManager manager = StubManager.getStubManager(name);
-        if (manager == null) {
-            return null;
-        }
-        if (layout == null) {
-            layout = PatternLayout.createDefaultLayout();
-        }
-        return new StubAppender(name, layout, filter, manager, ignoreExceptions);
-    }
-}</pre>
-          </subsection>
-          <subsection name="Layouts">
-            <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 "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.
-            </p>
-            <pre class="prettyprint linenums">
-@Plugin(name = "SampleLayout", category = "Core", elementType = "layout", printObject = true)
-public class SampleLayout extends AbstractStringLayout {
-
-    protected SampleLayout(boolean locationInfo, boolean properties, boolean complete,
-                           Charset charset) {
-    }
-
-    @PluginFactory
-    public static SampleLayout createLayout(@PluginAttribute("locationInfo") boolean locationInfo,
-                                            @PluginAttribute("properties") boolean properties,
-                                            @PluginAttribute("complete") boolean complete,
-                                            @PluginAttribute(value = "charset", defaultStringValue = "UTF-8") Charset charset) {
-        return new SampleLayout(locationInfo, properties, complete, charset);
-    }
-}</pre>
-          </subsection>
-          <subsection name="PatternConverters">
-            <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 "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.
-            </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>
-            <pre class="prettyprint linenums">
-@Plugin(name = "query", category = "Converter")
-@ConverterKeys({"q", "query"})
-public final class QueryConverter extends LogEventPatternConverter {
-
-    public QueryConverter(String[] options) {
-    }
-
-    public static QueryConverter newInstance(final String[] options) {
-      return new QueryConverter(options);
-    }
-}</pre>
-          </subsection>
-          <subsection name="Plugin Builders">
-            <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 <code>ListAppender</code>:
-            </p>
-            <pre class="prettyprint linenums"><![CDATA[
-@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);
-}]]></pre>
-            <p>
-              Here is that same factory using a builder pattern instead:
-            </p>
-            <pre class="prettyprint linenums"><![CDATA[
-@PluginBuilderFactory
-public static Builder newBuilder() {
-    return new Builder();
-}
-
-public static class Builder implements org.apache.logging.log4j.core.util.Builder<ListAppender> {
-
-    @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;
-
-    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<? extends Serializable> 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>
-            <p>
-              The only difference in annotations is using <code>@PluginBuilderAttribute</code> instead of
-              <code>@PluginAttribute</code> 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 (<code>@PluginConfiguration</code>, <code>@PluginElement</code>, <code>@PluginNode</code>,
-              and <code>@PluginValue</code>) 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 <code>@PluginBuilderFactory</code>.
-              <!-- TODO: this will change with LOG4J2-1188 -->
-            </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>
-            <pre class="prettyprint linenums"><![CDATA[
-ListAppender list1 = ListAppender.createAppender("List1", true, false, null, null);
-ListAppender list2 = ListAppender.newBuilder().setName("List1").setEntryPerNewLine(true).build();
-]]></pre>
-          </subsection>
-        <subsection name="Custom ContextDataInjector">
-          <p>
-            The <code>ContextDataInjector</code> (introduced in Log4j 2.7) is responsible for
-            populating the LogEvent's
-            <a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/LogEvent.html#getContextData()">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
-          <tt>log4j2.contextDataInjector</tt> 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 class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/ContextDataInjector.html">ContextDataInjector</a>
-          javadoc for detail.
-        </p>
-        </subsection>
-        <subsection name="Custom ThreadContextMap implementations">
-          <p>
-            A garbage-free StringMap-based context map can be installed by setting system property <tt>log4j2.garbagefreeThreadContextMap</tt>
-            to true. (Log4j must be <a href="garbagefree.html#Config">enabled</a> to use ThreadLocals.)
-          </p><p>
-            Any custom <tt>ThreadContextMap</tt> implementation can be installed by setting system property
-            <tt>log4j2.threadContextMap</tt> to the fully qualified class name of the class implementing the
-            ThreadContextMap interface. By also implementing the <tt>ReadOnlyThreadContextMap</tt> 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>
-        </subsection>
-          <subsection name="Custom Plugins">
-            <p>See the <a href="plugins.html">Plugins</a> section of the manual.</p>
-<!-- TODO: some documentation here! -->
-          </subsection>
-      </section>
-
-    </body>
-</document>