////
    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 <rgoers@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 link:../log4j-core/apidocs/org/apache/logging/log4j/core/impl/Log4jContextFactory.html[`LoggerContextFactory`].
..  Implement a class that extends link:../log4j-core/apidocs/org/apache/logging/spi/Provider.html[`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 link:../log4j-core/apidocs/org/apache/logging/log4j/spi/ThreadContextMap.html[`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 link:../log4j-core/apidocs/org/apache/logging/log4j/core/config/Configuration.html[`Configuration`] object.

Most `Configuration` extend the link:../log4j-core/apidocs/org/apache/logging/log4j/core/config/AbstractConfiguration.html[`AbstractConfiguration`] 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. `Configuration` 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 are 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(defaultBooleanValue = true) boolean additivity,
                                            @PluginAttribute(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 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(defaultStringValue = "ERROR") Level level,
                                               @PluginAttribute(defaultStringValue = "NEUTRAL") Result onMatch,
                                               @PluginAttribute(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 that returns an instance
of the appender or a builder class used to 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 AbstractOutputStreamAppender<StubManager> {

    private StubAppender(String name,
                         Layout<? extends Serializable> layout,
                         Filter filter,
                         boolean ignoreExceptions,
                         StubManager  manager) {
        super(name, layout, filter, ignoreExceptions, true, manager);
    }

    @PluginFactory
    public static StubAppender createAppender(@PluginAttribute @Required(message = "No name provided for StubAppender") String name,
                                              @PluginAttribute boolean ignoreExceptions,
                                              @PluginElement("Layout") Layout layout,
                                              @PluginElement("Filters") Filter filter) {

        StubManager manager = StubManager.getStubManager(name);
        if (manager == null) {
            return null;
        }
        if (layout == null) {
            layout = PatternLayout.createDefaultLayout();
        }
        return new StubAppender(name, layout, filter, ignoreExceptions, manager);
    }
}
----

[#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) {
        super(charset);
        // handle the boolean parameters
    }

    @PluginFactory
    public static SampleLayout createLayout(@PluginAttribute boolean locationInfo,
                                            @PluginAttribute boolean properties,
                                            @PluginAttribute boolean complete,
                                            @PluginAttribute(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);
    }
    
    @Override
    public void format(LogEvent event, StringBuilder toAppendTo) {
        // get the data from 'event', to the work and append the result to 'toAppendTo'.
    }    
}
----

A pattern to use this converter could be specified as `... %q ...` or `... %q{argument} ...`. 
The "argument" will be passed as first (and only) value to the `options` parameter of the 
`newInstance(...)` method.

[#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 or the method name with `set` or `with` prefixes stripped.
* 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]
----
@PluginFactory
public static Builder newBuilder() {
    return new Builder();
}

public static class Builder implements org.apache.logging.log4j.plugins.util.Builder<ListAppender> {

    private String name;
    private boolean entryPerNewLine;
    private boolean raw;
    private Layout<? extends Serializable> layout;
    private Filter filter;

    @PluginAttribute
    @Required(message = "No name provided for ListAppender")
    public Builder setName(final String name) {
        this.name = name;
        return this;
    }

    @PluginAttribute
    public Builder setEntryPerNewLine(final boolean entryPerNewLine) {
        this.entryPerNewLine = entryPerNewLine;
        return this;
    }

    @PluginAttribute
    public Builder setRaw(final boolean raw) {
        this.raw = raw;
        return this;
    }

    @PluginElement
    public Builder setLayout(final Layout<? extends Serializable> layout) {
        this.layout = layout;
        return this;
    }

    @PluginElement
    public Builder setFilter(final Filter filter) {
        this.filter = filter;
        return this;
    }

    @Override
    public ListAppender build() {
        return new ListAppender(name, filter, layout, entryPerNewLine, raw);
    }
}
----

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).
// TODO: this will be simplified

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_ContextDataProvider]
== Custom ContextDataProvider

The link:../log4j-core/apidocs/org/apache/logging/log4j/core/util/ContextDataProvider.html[`ContextDataProvider`] 
(introduced in Log4j 2.13.2) is an interface applications and libraries can use to inject
additional key-value pairs into the LogEvent's context data. Log4j's 
link:../log4j-core/apidocs/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.html[`ThreadContextDataInjector`] 
uses `java.util.ServiceLoader` to locate and load `ContextDataProvider` instances.
Log4j itself adds the ThreadContext data to the LogEvent using 
`org.apache.logging.log4j.core.impl.ThreadContextDataProvider`. Custom implementations
should implement the `org.apache.logging.log4j.core.util.ContextDataProvider` interface and 
declare it as a service by defining the implmentation class in a file named
`META-INF/services/org.apache.logging.log4j.core.util.ContextDataProvider`.

== 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 link:../log4j-core/apidocs/org/apache/logging/log4j/spi/ThreadContextMap.html[`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.
