| <?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> |
| <a name="ContextSelector"/> |
| <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> |
| <a name="ConfigurationFactory"/> |
| <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> |
| <a name="LoggerConfig"/> |
| <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> |
| <a name="LogEventFactory"/> |
| <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> |
| <a name="MessageFactory"/> |
| <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> |
| <a name="Lookups"/> |
| <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> |
| <a name="Filters"/> |
| <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> |
| <a name="Appenders"/> |
| <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"><![CDATA[ |
| @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("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, ignoreExceptions, manager); |
| } |
| }]]></pre> |
| </subsection> |
| <a name="Layouts"/> |
| <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> |
| <a name="PatternConverters"/> |
| <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> |
| <a name="Plugin_Builders"/> |
| <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> |
| <a name="ContextDataProvider"/> |
| <subsection name="Custom ContextDataProvider"> |
| <p> |
| The <code>ContextDataProvider</code> (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 <code>ThreadContextDataInjector</code> uses <code>java.util.ServiceLoader</code> |
| to locate and load <code>ContextDataProvider</code> instances. Log4j itself adds the ThreadContextData to |
| the LogEvent using <code>org.apache.logging.log4j.core.impl.ThreadContextDataProvider</code>. Custom |
| implementations should implement the <code>org.apache.logging.log4j.core.util.ContextDataProvider</code> |
| interface and declare it as a service by defining the implmentation class in a file named |
| <code>META-INF/services/org.apache.logging.log4j.core.util.ContextDataProvider</code>. |
| </p> |
| </subsection> |
| <a name="ThreadContextMap"/> |
| <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> |