This is an automated email from the ASF dual-hosted git repository.

vy pushed a commit to branch doc/2.x/extending
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f9deaaf961726256099e0449af8d33544a2b0a77
Author: Volkan Yazıcı <[email protected]>
AuthorDate: Tue Jun 11 10:30:06 2024 +0200

    Move extending appenders/filters/lookups to their own pages
---
 .../modules/ROOT/pages/manual/appenders.adoc       | 166 +++++++++++++-------
 .../modules/ROOT/pages/manual/extending.adoc       | 170 ---------------------
 .../antora/modules/ROOT/pages/manual/filters.adoc  |  66 ++++++--
 .../antora/modules/ROOT/pages/manual/lookups.adoc  |  83 +++++++---
 src/site/resources/.htaccess                       |   3 +
 5 files changed, 225 insertions(+), 263 deletions(-)

diff --git a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc 
b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc
index aad5a661a3..be44a32d4d 100644
--- a/src/site/antora/modules/ROOT/pages/manual/appenders.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/appenders.adoc
@@ -14,8 +14,8 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 ////
+
 = Appenders
-Ralph Goers; Gary Gregory; Nick Williams; Matt Sicker
 
 Appenders are responsible for delivering LogEvents to their destination.
 Every Appender must implement the
@@ -70,8 +70,14 @@ This setting only guarantees that a byte representation of 
the log event is pass
 It does not ensure that the operating system writes the event to the 
underlying storage.
 ====
 
+[#collection]
+== Collection
+
+Log4j bundles several predefined appenders to assist in several common 
deployment use cases.
+Following sections explain all these in detail.
+
 [id=AsyncAppender]
-== [[asyncappender]] AsyncAppender
+=== [[asyncappender]] AsyncAppender
 
 The AsyncAppender accepts references to other Appenders and causes LogEvents 
to be written to them on a separate Thread.
 Note that exceptions while writing to those Appenders will be hidden from the 
application.
@@ -232,7 +238,7 @@ maximum capacity.
 |=======================================================================
 
 [#CassandraAppender]
-== CassandraAppender
+=== CassandraAppender
 
 The CassandraAppender writes its output to an 
https://cassandra.apache.org/[Apache Cassandra]
 database.
@@ -371,7 +377,7 @@ CREATE TABLE logs (
 ----
 
 [id=consoleappender]
-== [[ConsoleAppender]] ConsoleAppender
+=== [[ConsoleAppender]] ConsoleAppender
 
 As one might expect, the ConsoleAppender writes its output to either
 `System.out` or `System.err` with `System.out` being the default target.
@@ -434,7 +440,7 @@ A typical Console configuration might look like:
 ----
 
 [#FailoverAppender]
-== FailoverAppender
+=== FailoverAppender
 
 The FailoverAppender wraps a set of appenders.
 If the primary Appender fails the secondary appenders will be tried in order 
until one succeeds or there are no more secondaries to try.
@@ -497,7 +503,7 @@ A Failover configuration might look like:
 ----
 
 [id=fileappender]
-== [[FileAppender]] FileAppender
+=== [[FileAppender]] FileAppender
 
 The FileAppender is an OutputStreamAppender that writes to the File defined in 
the `fileName` parameter.
 The FileAppender uses a FileManager (which extends OutputStreamManager) to 
perform the file I/O.
@@ -625,7 +631,7 @@ Here is a sample File configuration:
 ----
 
 [#FlumeAppender]
-== FlumeAppender
+=== FlumeAppender
 
 _This is an optional component supplied in a separate jar._
 
@@ -857,7 +863,7 @@ A sample FlumeAppender configuration that is configured 
with a primary and a sec
 ----
 
 [#JDBCAppender]
-== JDBCAppender
+=== JDBCAppender
 
 As of Log4j 2.11.0, JDBC support has moved from the existing module
 `log4j-core` to the new module `log4j-jdbc`.
@@ -1251,7 +1257,7 @@ table based on a Log4j `MapMessage` instead of values 
from `LogEvent`.
 </Configuration>
 ----
 
-== JMS Appender
+=== JMS Appender
 
 The JMS Appender sends the formatted log event to a JMS Destination.
 
@@ -1384,7 +1390,7 @@ To map your Log4j `MapMessage` to JMS 
`javax.jms.MapMessage`, set the layout of
 ----
 
 [[JPAAppender]]
-== JPAAppender
+=== JPAAppender
 
 As of Log4j 2.11.0, JPA support has moved from the existing module 
`log4j-core` to the new module `log4j-jpa`.
 
@@ -1562,7 +1568,7 @@ public class JpaLogEntity extends 
AbstractLogEventWrapperEntity {
 ----
 
 [#HttpAppender]
-== HttpAppender
+=== HttpAppender
 
 The HttpAppender sends log events over HTTP.
 A Layout must be provided to format the LogEvent.
@@ -1636,7 +1642,7 @@ Here is a sample HttpAppender configuration snippet:
 ----
 
 [[KafkaAppender]]
-== KafkaAppender
+=== KafkaAppender
 
 The KafkaAppender logs events to an https://kafka.apache.org/[Apache Kafka] 
topic.
 Each log event is sent as a Kafka record.
@@ -1721,7 +1727,7 @@ _Note:_ Make sure to not let `org.apache.kafka` log to a 
Kafka appender on DEBUG
 ----
 
 [#MemoryMappedFileAppender]
-== MemoryMappedFileAppender
+=== MemoryMappedFileAppender
 
 _New since 2.1. Be aware that this is a new addition, and although it has been 
tested on several platforms, it does not have as much track record as the other 
file appenders._
 
@@ -1816,7 +1822,7 @@ Here is a sample MemoryMappedFile configuration:
 ----
 
 [#NoSQLAppender]
-== NoSQLAppender
+=== NoSQLAppender
 
 The NoSQLAppender writes log events to a NoSQL database using an internal 
lightweight provider interface.
 Provider implementations currently exist for MongoDB, and writing a custom 
provider is quite simple.
@@ -1907,10 +1913,10 @@ The following example demonstrates how log events are 
persisted in NoSQL databas
 ----
 
 [#NoSQLAppenderMongoDB]
-=== NoSQL providers for MongoDB
+==== NoSQL providers for MongoDB
 
 [#mongo-installation]
-==== Installation
+===== Installation
 
 Starting with version 2.11.0, Log4j supplies providers for the
 https://www.mongodb.com/[MongoDB]
@@ -1980,7 +1986,7 @@ If you are note sure, which implementation to choose, 
`log4j-mongodb` is the rec
 ====
 
 [#log4j-mongodb]
-==== NoSQL provider for MongoDB (current)
+===== NoSQL provider for MongoDB (current)
 
 This section details specializations of the
 link:#NoSQLAppender[NoSQLAppender] provider for MongoDB using the current 
MongoDB driver (version 5).
@@ -2069,7 +2075,7 @@ You can define additional fields to log using 
KeyValuePair elements, for example
 ----
 
 [#log4j-mongodb4]
-==== [[NoSQLAppenderMongoDB4]] NoSQL provider  for MongoDB 4 (deprecated)
+===== [[NoSQLAppenderMongoDB4]] NoSQL provider  for MongoDB 4 (deprecated)
 
 The `log4j-mongodb4` module is deprecated in favor of 
link:#log4j-mongodb[NoSQL provider for MongoDB].
 
@@ -2159,7 +2165,7 @@ You can define additional fields to log using 
KeyValuePair elements, for example
 ----
 
 [[NoSQLAppenderApacheCouchDB]]
-== NoSQLAppender for Apache CouchDB
+=== NoSQLAppender for Apache CouchDB
 
 This section details specializations of the link:#NoSQLAppender[NoSQLAppender] 
provider for CouchDB.
 The NoSQLAppender writes log events to a NoSQL database using an internal 
lightweight provider interface.
@@ -2222,7 +2228,7 @@ Here are a few sample configurations for the 
NoSQLAppender and CouchDB provider:
 ----
 
 [#OutputStreamAppender]
-== OutputStreamAppender
+=== OutputStreamAppender
 
 The OutputStreamAppender provides the base for many of the other Appenders 
such as the File and Socket appenders that write the event to an Output Stream.
 It cannot be directly configured.
@@ -2230,7 +2236,7 @@ Support for immediateFlush and buffering is provided by 
the OutputStreamAppender
 The OutputStreamAppender uses an OutputStreamManager to handle the actual I/O, 
allowing the stream to be shared by Appenders in multiple configurations.
 
 [#RandomAccessFileAppender]
-== RandomAccessFileAppender
+=== RandomAccessFileAppender
 
 The RandomAccessFileAppender is similar to the standard
 link:#FileAppender[FileAppender] except it is always buffered (this cannot be 
switched off) and internally it uses a
@@ -2310,7 +2316,7 @@ Here is a sample RandomAccessFile configuration:
 ----
 
 [#RewriteAppender]
-== RewriteAppender
+=== RewriteAppender
 
 The RewriteAppender allows the LogEvent to be manipulated before it is 
processed by another Appender.
 This can be used to mask sensitive information such as passwords or to inject 
information into each event.
@@ -2342,13 +2348,13 @@ Appender in a link:#FailoverAppender[FailoverAppender].
 |=======================================================================
 
 [#RewritePolicy]
-=== RewritePolicy
+==== RewritePolicy
 
 RewritePolicy is an interface that allows implementations to inspect and 
possibly modify LogEvents before they are passed to Appender.
 RewritePolicy declares a single method named rewrite that must be implemented.
 The method is passed the LogEvent and can return the same event or create a 
new one.
 
-==== MapRewritePolicy
+===== MapRewritePolicy
 
 MapRewritePolicy will evaluate LogEvents that contain a MapMessage and will 
add or update elements of the Map.
 
@@ -2384,7 +2390,7 @@ The following configuration shows a RewriteAppender 
configured to add a product
 </Configuration>
 ----
 
-==== PropertiesRewritePolicy
+===== PropertiesRewritePolicy
 
 PropertiesRewritePolicy will add properties configured on the policy to the 
ThreadContext Map being logged.
 The properties will not be added to the actual ThreadContext Map.
@@ -2423,7 +2429,7 @@ The following configuration shows a RewriteAppender 
configured to add a product
 </Configuration>
 ----
 
-==== LoggerNameLevelRewritePolicy
+===== LoggerNameLevelRewritePolicy
 
 You can use this policy to make loggers in third-party code less chatty by 
changing event levels.
 The LoggerNameLevelRewritePolicy will rewrite log event levels for a given 
logger name prefix.
@@ -2466,7 +2472,7 @@ The following configuration shows a RewriteAppender 
configured to map level INFO
 ----
 
 [id=rollingfileappender]
-== [[RollingFileAppender]] RollingFileAppender
+=== [[RollingFileAppender]] RollingFileAppender
 
 The RollingFileAppender is an OutputStreamAppender that writes to the file 
named in the fileName parameter and rolls the file over according to the 
`TriggeringPolicy` and the `RolloverPolicy`.
 The `RollingFileAppender`
@@ -2602,9 +2608,9 @@ file attribute view.
 |=======================================================================
 
 [#TriggeringPolicies]
-== TriggeringPolicies
+=== TriggeringPolicies
 
-=== Composite Triggering Policy
+==== Composite Triggering Policy
 
 The `CompositeTriggeringPolicy` combines multiple triggering policies and 
returns true if any of the configured policies return true.
 The
@@ -2621,7 +2627,7 @@ For example, the following XML fragment defines policies 
that rollover the log w
 </Policies>
 ----
 
-=== Cron Triggering Policy
+==== Cron Triggering Policy
 
 The `CronTriggeringPolicy` triggers rollover based on a cron expression.
 This policy is controlled by a timer and is asynchronous in processing log 
events, so it is possible that log events from the previous or next period may 
appear at the beginning or end of the log file.
@@ -2642,7 +2648,7 @@ expression indicates a rollover should have occurred 
between that time
 and the current time the file will be immediately rolled over.
 |=======================================================================
 
-=== OnStartup Triggering Policy
+==== OnStartup Triggering Policy
 
 The `OnStartupTriggeringPolicy` policy causes a rollover if the log file is 
older than the current JVM's start time and the minimum file size is met or 
exceeded.
 
@@ -2661,7 +2667,7 @@ When running in Google App Engine, the OnStartup policy 
causes a rollover if the
 `java.lang.management.ManagementFactory.getRuntimeMXBean().getStartTime()`
 and falls back to Log4J initialization time instead.)
 
-=== SizeBased Triggering Policy
+==== SizeBased Triggering Policy
 
 The `SizeBasedTriggeringPolicy` causes a rollover once the file has reached 
the specified size.
 The size can be specified in bytes, with the suffix KB, MB, GB, or TB for 
example `20MB`.
@@ -2672,7 +2678,7 @@ When combined with a time-based triggering policy the 
file pattern must contain
 Otherwise, the target file will be overwritten on every rollover as the 
SizeBased Triggering Policy will not cause the timestamp value in the file name 
to change.
 When used without a time-based triggering policy the SizeBased Triggering 
Policy will cause the timestamp value to change.
 
-=== TimeBased Triggering Policy
+==== TimeBased Triggering Policy
 
 The `TimeBasedTriggeringPolicy` causes a rollover once the date/time pattern 
no longer applies to the active file.
 This policy accepts an
@@ -2701,10 +2707,10 @@ load of doing so across time.
 |=======================================================================
 
 [#RolloverStrategies]
-== RolloverStrategies
+=== RolloverStrategies
 
 [#DefaultRolloverStrategy]
-=== DefaultRolloverStrategy
+==== DefaultRolloverStrategy
 
 Default Rollover Strategy
 
@@ -2798,7 +2804,7 @@ archived log file during compression.
 |=======================================================================
 
 [#DirectWriteRolloverStrategy]
-=== DirectWriteRolloverStrategy
+==== DirectWriteRolloverStrategy
 
 DirectWrite Rollover Strategy
 
@@ -2959,7 +2965,7 @@ This sample configuration is the same as the previous one 
but limits the number
 ----
 
 [#CustomDeleteOnRollover]
-=== CustomDeleteOnRollover
+==== CustomDeleteOnRollover
 
 Log Archive Retention Policy: Delete on Rollover
 
@@ -3046,7 +3052,7 @@ and must return a list with the paths to delete.
 |=======================================================================
 
 [#DeleteIfFileName]
-== DeleteIfFileName
+=== DeleteIfFileName
 
 .IfFileName Condition Parameters
 [cols="20%,20%,60%",options="header",]
@@ -3072,7 +3078,7 @@ the path name matches).
 |=======================================================================
 
 [#DeleteIfLastModified]
-== DeleteIfLastModified
+=== DeleteIfLastModified
 
 .IfLastModified Condition Parameters
 [cols="20%,20%,60%",options="header",]
@@ -3091,7 +3097,7 @@ the file is old enough).
 |=======================================================================
 
 [#DeleteIfAccumulatedFileCount]
-== DeleteIfAccumulatedFileCount
+=== DeleteIfAccumulatedFileCount
 
 .IfAccumulatedFileCount Condition Parameters
 [cols="20%,20%,60%",options="header",]
@@ -3108,7 +3114,7 @@ the threshold count has been exceeded).
 |=======================================================================
 
 [#DeleteIfAccumulatedFileSize]
-== DeleteIfAccumulatedFileSize
+=== DeleteIfAccumulatedFileSize
 
 .IfAccumulatedFileSize Condition Parameters
 [cols="20%,20%,60%",options="header",]
@@ -3202,7 +3208,7 @@ During every rollover, this configuration will delete 
files that match "*/app-*.
 ----
 
 [#ScriptCondition]
-== ScriptCondition
+=== ScriptCondition
 
 .ScriptCondition Parameters
 [cols="20%,20%,60%",options="header",]
@@ -3217,7 +3223,7 @@ how ScriptFiles and ScriptRefs can be configured.
 |=======================================================================
 
 [#ScriptParameters]
-== ScriptParameters
+=== ScriptParameters
 
 .Script Parameters
 [cols="20%,20%,60%",options="header",]
@@ -3307,7 +3313,7 @@ The Delete action will delete all files returned by the 
script.
 ----
 
 [#CustomPosixViewAttributeOnRollover]
-== CustomPosixViewAttributeOnRollover
+=== CustomPosixViewAttributeOnRollover
 
 Log Archive File Attribute View Policy: Custom file attribute on Rollover
 
@@ -3399,7 +3405,7 @@ Below is a sample configuration that uses a 
RollingFileAppender and defines diff
 ----
 
 [#RollingRandomAccessFileAppender]
-== RollingRandomAccessFileAppender
+=== RollingRandomAccessFileAppender
 
 The RollingRandomAccessFileAppender is similar to the standard
 link:#RollingFileAppender[RollingFileAppender] except it is always buffered 
(this cannot be switched off) and internally it uses a
@@ -3511,11 +3517,11 @@ file attribute view.
 
 |=======================================================================
 
-=== Triggering Policies
+==== Triggering Policies
 
 See xref:#TriggeringPolicies[RollingFileAppender Triggering Policies].
 
-=== Rollover Strategies
+==== Rollover Strategies
 
 See link:#RolloverStrategies[RollingFileAppender Rollover Strategies].
 
@@ -3599,7 +3605,7 @@ Below is a sample configuration that uses a 
RollingRandomAccessFileAppender with
 ----
 
 [#RoutingAppender]
-== RoutingAppender
+=== RoutingAppender
 
 The `RoutingAppender` evaluates LogEvents and then routes them to a 
subordinate Appender.
 The target Appender may be an appender previously configured and may be 
referenced by its name or the Appender can be dynamically created as needed.
@@ -3678,7 +3684,7 @@ Note that the List Appender is one of our test appenders, 
any appender can be us
 ----
 
 [#Routes]
-=== Routes
+==== Routes
 
 The `Routes` element accepts a single attribute named "pattern".
 The pattern is evaluated against all the registered Lookups and the result is 
used to select a `Route`.
@@ -3763,7 +3769,7 @@ In this example, the script runs for each log event and 
picks a route based on t
 ----
 
 [#Purge]
-=== Purge Policy
+==== Purge Policy
 
 The RoutingAppender can be configured with a PurgePolicy whose purpose is to 
stop and remove dormant Appenders that have been dynamically created by the 
RoutingAppender.
 Log4j currently provides the IdlePurgePolicy is the only PurgePolicy available 
for cleaning up the Appenders.
@@ -3807,7 +3813,7 @@ Note that the AuditAppender was predefined while the 
RollingFileAppenders are cr
 ----
 
 [[SMTPAppender]]
-== SMTPAppender
+=== SMTPAppender
 
 Sends an e-mail when a specific logging event occurs, typically on errors or 
fatal errors.
 
@@ -3916,7 +3922,7 @@ As with other Appenders, the formatting can be controlled 
by specifying a Layout
 ----
 
 [#ScriptAppenderSelector]
-== ScriptAppenderSelector
+=== ScriptAppenderSelector
 
 When the configuration is built, the `ScriptAppenderSelector` appender calls a 
`ScriptPlugin` to compute an appender name.
 Log4j then creates one of the appender named listed under `AppenderSet` using 
the name of the
@@ -3952,7 +3958,7 @@ The appender name is recorded under the name of the
 ----
 
 [#SocketAppender]
-== SocketAppender
+=== SocketAppender
 
 The `SocketAppender` is an OutputStreamAppender that writes its output to a 
remote destination specified by a host and port.
 The data can be sent over either TCP or UDP and can be sent in any format.
@@ -4062,7 +4068,7 @@ This is a secured link:#SSL[SSL] configuration:
 ----
 
 [#SSL]
-== SSL
+=== SSL
 
 Several appenders can be configured to use either a plain network connection 
or a Secure Socket Layer (SSL) connection.
 This section documents the parameters available for SSL configuration.
@@ -4085,7 +4091,7 @@ counterparty. Determines whether the remote 
authentication credentials
 |=======================================================================
 
 [#KeyStore]
-=== KeyStore
+==== KeyStore
 
 The Keystore is meant to contain your private keys and certificates, and 
determines which authentication credentials to send to the remote host.
 
@@ -4118,7 +4124,7 @@ algorithms].
 |=======================================================================
 
 [#TrustStore]
-=== TrustStore
+==== TrustStore
 
 The trust store is meant to contain the CA certificates you are willing to 
trust when a remote party presents its certificate.
 Determines whether the remote authentication credentials (and thus the 
connection) should be trusted.
@@ -4154,7 +4160,7 @@ algorithms].
 |=======================================================================
 
 [#Example]
-=== Example
+==== Example
 
 [source,xml]
 ----
@@ -4165,7 +4171,7 @@ algorithms].
 ----
 
 [#SyslogAppender]
-== SyslogAppender
+=== SyslogAppender
 
 The `SyslogAppender` is a `SocketAppender` that writes its output to a remote 
destination specified by a host and port in a format that conforms with either 
the BSD Syslog format or the RFC 5424 format.
 The data can be sent over either TCP or UDP.
@@ -4331,7 +4337,7 @@ For link:#SSL[SSL] this appender writes its output to a 
remote destination speci
 ----
 
 [[JeroMQAppender]]
-== ZeroMQ/JeroMQ Appender
+=== ZeroMQ/JeroMQ Appender
 
 The ZeroMQ appender uses the https://github.com/zeromq/jeromq[JeroMQ] library 
to send log events to one or more ZeroMQ endpoints.
 
@@ -4462,3 +4468,45 @@ Please consult the JeroMQ and ZeroMQ documentation for 
details.
 |boolean
 |The ZMQ_XPUB_VERBOSE option. Defaults to false.
 |===
+
+[#extending]
+== Extending
+
+Appenders are xref:manual/plugins.adoc[plugins] implementing 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[the 
`Appender` interface].
+This section will guide you on how to create custom ones.
+
+[WARNING]
+====
+*Implementing a reliable and efficient appender is a difficult task!*
+We strongly advise you to
+
+. Use existing appenders and/or managers whenever appropriate
+. Share your use case and ask for feedback in a 
{logging-services-url}/support.html[user support channel]
+====
+
+[#extending-plugins]
+=== Plugin preliminaries
+
+include::partial$manual/plugin-preliminaries.adoc[]
+
+[#extending-appenders]
+=== Extending appenders
+
+Appenders are xref:manual/plugins.adoc[plugins] implementing 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html[the 
`Appender` interface].
+We recommend users to extend from 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/appender/AbstractAppender.html[`AbstractAppender`],
 which provides implementation convenience.
+While annotating your appender with `@Plugin`, you need to make sure that
+
+* It has a unique `name` attribute across all available `Appender` plugins
+* The `category` attribute is set to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Node.html#CATEGORY[`Node.CATEGORY`]
+* The `elementType` attribute is set to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Appender.html#ELEMENT_TYPE[`Appender.ELEMENT_TYPE`]
+
+Most appender implementation use *managers*, which model an abstraction owning 
the resources, such as an `OutputStream` or a 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 ensures that events are not lost while a reconfiguration is taking place 
without requiring that logging pause while the reconfiguration takes place.
+You are strongly advised to study the manager concept in xref:#collection[the 
predefined appenders], and either use an existing manager, or create your own.
+
+You can check out following files for examples:
+
+* 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/HttpAppender.java[`HttpAppender.java`]
 – xref:#HttpAppender[] sends log events over HTTP using 
`HttpURLConnectionManager`
+* 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/ConsoleAppender.java[`ConsoleAppender.java`]
 – xref:#ConsoleAppender[Console Appender] writes log events to either 
`System.out` or `System.err` using `OutputStreamManager`
diff --git a/src/site/antora/modules/ROOT/pages/manual/extending.adoc 
b/src/site/antora/modules/ROOT/pages/manual/extending.adoc
index b8d6395681..6b3e67233e 100644
--- a/src/site/antora/modules/ROOT/pages/manual/extending.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/extending.adoc
@@ -208,176 +208,6 @@ a separate `FlowMessageFactory`. Applications may replace 
the
 `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 @Lookup` annotation. The `value` 
specified on the `@Plugin` annotation will be used to
-match the prefix. The example below shows a Lookup that will return
-the value of a System Property.
-
-The provided Lookups are documented here: xref:manual/lookups.adoc[Lookups]
-
-[source,java]
-----
-@Lookup
-@Plugin("sys")
-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 `@Configurable` annotation with an `elementType` of "filter".
-The `value` 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 level The log Level.
-     * @param onMatch The action to take on a match.
-     * @param onMismatch 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 `@Configurable` with an
-`elementType` of "appender". The `value` 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<?> 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,
-                                              @PluginElement 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);
-    }
-}
-----
-
 [#Plugin_Builders]
 == Plugin Builders
 
diff --git a/src/site/antora/modules/ROOT/pages/manual/filters.adoc 
b/src/site/antora/modules/ROOT/pages/manual/filters.adoc
index baea1d507b..88e10b79ac 100644
--- a/src/site/antora/modules/ROOT/pages/manual/filters.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/filters.adoc
@@ -14,6 +14,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 ////
+
 [id=filters]
 = Filters
 
@@ -85,8 +86,14 @@ Users migrating from Log4j 1 often replace the `threshold` 
property of a Log4j 1
 Using the `level` property of appender references will give a better 
performance.
 ====
 
+[#collection]
+== Collection
+
+Log4j bundles several predefined filters to assist in several common 
deployment use cases.
+Following sections explain all these in detail.
+
 [#BurstFilter]
-== BurstFilter
+=== BurstFilter
 
 The BurstFilter provides a mechanism to control the rate at which LogEvents 
are processed by silently discarding events after the maximum limit has been 
reached.
 
@@ -148,7 +155,7 @@ A configuration containing the BurstFilter might look like:
 ----
 
 [#CompositeFilter]
-== CompositeFilter
+=== CompositeFilter
 
 The CompositeFilter provides a way to specify more than one filter.
 It is added to the configuration as a filter element and contains other 
filters to be evaluated.
@@ -194,7 +201,7 @@ A configuration containing the CompositeFilter might look 
like:
 ----
 
 [#DynamicThresholdFilter]
-== DynamicThresholdFilter
+=== DynamicThresholdFilter
 
 The DynamicThresholdFilter allows filtering by log level based on specific 
attributes.
 For example, if the user's loginId is being captured in the ThreadContext Map 
then it is possible to enable debug logging for only that user.
@@ -262,7 +269,7 @@ Here is a sample configuration containing the 
DynamicThresholdFilter:
 ----
 
 [#LevelRangeFilter]
-== LevelRangeFilter
+=== LevelRangeFilter
 
 `LevelRangeFilter` allows filtering against a level range, where levels get 
compared by their associated integral values; `OFF` has an integral value of 0, 
`FATAL` 100, `ERROR` 200, and so on.
 
@@ -311,7 +318,7 @@ The filter will return `onMismatch` result (i.e., `DENY`, 
the default) for log e
 ----
 
 [#MapFilter]
-== MapFilter
+=== MapFilter
 
 The MapFilter allows filtering against data elements that are in a MapMessage.
 
@@ -431,7 +438,7 @@ This third sample configuration will exhibit the same 
behavior as the preceding
 ----
 
 [#MarkerFilter]
-== MarkerFilter
+=== MarkerFilter
 
 The MarkerFilter compares the configured Marker value against the Marker that 
is included in the LogEvent.
 A match occurs when the Marker name matches either the Log Event's Marker or 
one of its parents.
@@ -481,7 +488,7 @@ A sample configuration that only allows the event to be 
written by the appender
 ----
 
 [#MutableThreadContextMapFilter]
-== MutableThreadContextMapFilter
+=== MutableThreadContextMapFilter
 
 The MutableThreadContextMapFilter or MutableContextMapFilter allows filtering 
against data elements that are in the current context.
 By default, this is the ThreadContext Map.
@@ -555,7 +562,7 @@ The configuration file supplied to the filter should look 
similar to:
 ----
 
 [#NoMarkerFilter]
-== NoMarkerFilter
+=== NoMarkerFilter
 
 The NoMarkerFilter checks that there is no marker included in the LogEvent.
 A match occurs when there is no marker in the Log Event.
@@ -601,7 +608,7 @@ A sample configuration that only allows the event to be 
written by the appender
 ----
 
 [#RegexFilter]
-== RegexFilter
+=== RegexFilter
 
 The RegexFilter allows the formatted or unformatted message to be compared 
against a regular expression.
 
@@ -771,7 +778,7 @@ xref:manual/appenders.adoc#ScriptCondition[ScriptCondition] 
for an example of ho
 ----
 
 [#StructuredDataFilter]
-== StructuredDataFilter
+=== StructuredDataFilter
 
 The StructuredDataFilter is a MapFilter that also allows filtering on the 
event id, type and message.
 
@@ -836,7 +843,7 @@ As in this configuration, the StructuredDataFilter can be 
used to log particular
 ----
 
 [#ThreadContextMapFilter]
-== ThreadContextMapFilter
+=== ThreadContextMapFilter
 
 The ThreadContextMapFilter or ContextMapFilter allows filtering against data 
elements that are in the current context.
 By default, this is the ThreadContext Map.
@@ -928,7 +935,7 @@ The ContextMapFilter can also be applied to a logger for 
filtering:
 ----
 
 [#ThresholdFilter]
-== ThresholdFilter
+=== ThresholdFilter
 
 This filter returns the onMatch result if the level in the LogEvent is the 
same or more specific than the configured level and the `onMismatch`
 value otherwise.
@@ -980,7 +987,7 @@ A sample configuration that only allows the event to be 
written by the appender
 ----
 
 [#TimeFilter]
-== TimeFilter
+=== TimeFilter
 
 The time filter can be used to restrict the filter to only a certain portion 
of the day.
 
@@ -1037,3 +1044,36 @@ A sample configuration that only allows the event to be 
written by the appender
   </Loggers>
 </Configuration>
 ----
+
+[#extending]
+== Extending
+
+Filters are xref:manual/plugins.adoc[plugins] implementing 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[the 
`Filter` interface].
+This section will guide you on how to create custom ones.
+
+[NOTE]
+====
+While xref:#collection[the predefined filter collection] should address most 
common use cases, you might find yourself needing to implement a custom one.
+If this is the case, we really appreciate it if you can *share your use case 
in a {logging-services-url}/support.html[user support channel]*.
+====
+
+[#extending-plugins]
+=== Plugin preliminaries
+
+include::partial$manual/plugin-preliminaries.adoc[]
+
+[#extending-filters]
+=== Extending filters
+
+Filter are xref:manual/plugins.adoc[plugins] implementing 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html[the 
`Filter` interface].
+We recommend users to extend from 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/filter/AbstractFilter.html[`AbstractFilter`],
 which provides implementation convenience.
+While annotating your filter with `@Plugin`, you need to make sure that
+
+* It has a unique `name` attribute across all available `Filter` plugins
+* The `category` attribute is set to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/config/Node.html#CATEGORY[`Node.CATEGORY`]
+* The `elementType` attribute is set to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/Filter.html#ELEMENT_TYPE[`Filter.ELEMENT_TYPE`]
+
+You can check out following files for examples:
+
+* 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/MarkerFilter.java[`MarkerFilter.java`]
 – xref:#MarkerFilter[] matching on markers associated with the effective 
`LogEvent` in the context
+* 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/RegexFilter.java[`RegexFilter.java`]
 – xref:#RegexFilter[] matching on the message associated with the effective 
`LogEvent` in the context
diff --git a/src/site/antora/modules/ROOT/pages/manual/lookups.adoc 
b/src/site/antora/modules/ROOT/pages/manual/lookups.adoc
index 6eea0d2afe..33e9749801 100644
--- a/src/site/antora/modules/ROOT/pages/manual/lookups.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/lookups.adoc
@@ -25,8 +25,14 @@ be found in the 
xref:manual/configuration.adoc#PropertySubstitution[Property
 Substitution] section of the xref:manual/configuration.adoc[Configuration]
 page.
 
+[#collection]
+== Collection
+
+Log4j bundles several predefined lookups to assist in several common 
deployment use cases.
+Following sections explain all these in detail.
+
 [#ContextMapLookup]
-== Context Map Lookup
+=== Context Map Lookup
 
 The ContextMapLookup allows applications to store data in the Log4j
 ThreadContext Map and then retrieve the values in the Log4j
@@ -47,7 +53,7 @@ resolve the variable for each event. Note that the pattern
 ----
 
 [#DateLookup]
-== Date Lookup
+=== Date Lookup
 
 The DateLookup is somewhat unusual from the other lookups as it doesn't
 use the key to locate an item. Instead, the key can be used to specify a
@@ -67,7 +73,7 @@ be formatted as specified.
 ----
 
 [#DockerLookup]
-== Docker Lookup
+=== Docker Lookup
 
 The DockerLookup can be used to lookup attributes from the Docker container 
the application is running in.
 
@@ -107,7 +113,7 @@ Log4j Docker provides access to the following container 
attributes:
 This Lookup is subject to the requirements listed at 
xref:log4j-docker.adoc[Log4j Docker Support]
 
 [id=environment-lookup]
-== [[EnvironmentLookup]] Environment Lookup
+=== [[EnvironmentLookup]] Environment Lookup
 
 The EnvironmentLookup allows systems to configure environment variables,
 either in global files such as /etc/profile or in the startup scripts
@@ -136,8 +142,9 @@ when the `USER` environment variable is undefined, the 
default value
   </PatternLayout>
 </File>
 ----
+
 [#EventLookup]
-== Event Lookup
+=== Event Lookup
 
 The EventLookup provides access to fields within the log event from the 
configuration.
 
@@ -212,7 +219,7 @@ present in the log event.
 ----
 
 [#JavaLookup]
-== Java Lookup
+=== Java Lookup
 
 The JavaLookup allows Java environment information to be retrieved in
 convenient preformatted strings using the `java:` prefix.
@@ -265,7 +272,7 @@ For example:
 ----
 
 [#JndiLookup]
-== JNDI Lookup
+=== JNDI Lookup
 
 As of Log4j 2.15.1 JNDI operations require that `log4j2.enableJndi=true` be 
set as a system property or the
 corresponding environment variable for this lookup to function. See the
@@ -295,7 +302,7 @@ or ip address are supported along with any hosts or ip 
addresses listed in the
 *Java's JNDI module is not available on Android.*
 
 [#JmxRuntimeInputArgumentsLookup]
-== JVM Input Arguments Lookup (JMX)
+=== JVM Input Arguments Lookup (JMX)
 
 Maps JVM input arguments -- but not _main_ arguments -- using JMX to
 acquire the JVM arguments.
@@ -308,7 +315,7 @@ 
https://docs.oracle.com/javase/8/docs/api/java/lang/management/RuntimeMXBean.htm
 *Java's JMX module is not available on Android or on Google App Engine.*
 
 [#KubernetesLookup]
-== Kubernetes Lookup
+=== Kubernetes Lookup
 
 For retrieving attributes using Fabric8's Kubernetes Client, see their 
https://github.com/fabric8io/kubernetes-client/blob/main/doc/KubernetesLog4j.md[Kubernetes
 Log4j Lookup].
 
@@ -333,7 +340,7 @@ relative to the log4j configuration file.
 ----
 
 [#LowerLookup]
-== Lower Lookup
+=== Lower Lookup
 
 The LowerLookup converts the passed in argument to lower case. Presumably the 
value will be the
 result of a nested lookup.
@@ -348,7 +355,7 @@ result of a nested lookup.
 ----
 
 [#AppMainArgsLookup]
-== Main Arguments Lookup (Application)
+=== Main Arguments Lookup (Application)
 
 This lookup requires that you manually provide the main arguments of the
 application to Log4j:
@@ -378,9 +385,10 @@ key must be followed by a backslash as an escape character 
as in `${main:\--file
 
 For example, suppose the static void main String[] arguments are:
 
-....
+[source,text]
+----
 --file foo.txt --verbose -x bar
-....
+----
 
 Then the following substitutions are possible:
 
@@ -428,7 +436,7 @@ Example usage:
 ----
 
 [#MapLookup]
-== Map Lookup
+=== Map Lookup
 
 The MapLookup serves several purposes.
 
@@ -469,7 +477,7 @@ page for information on how to set the default values.
 </Routing>
 ----
 
-== Marker Lookup
+=== Marker Lookup
 
 The marker lookup allows you to use markers in interesting
 configurations like a routing appender. Consider the following YAML
@@ -538,7 +546,8 @@ You can use the notation `"${marker:name}"` and 
`"$${marker:name}"` to
 check for the existence of a marker where `name` is the marker name. If
 the marker exists, the expression returns the name, otherwise `null`.
 
-== Resource Bundle Lookup
+=== Resource Bundle Lookup
+
 The resource bundle lookup retrieves values from Resource Bundles (see Java 
documentation). The format is `${bundle:BundleName:BundleKey}`. The bundle name 
follows package naming conventions, for example: 
`${bundle:com.domain.Messages:MyKey}`.
 
 [source, xml]
@@ -550,7 +559,8 @@ The resource bundle lookup retrieves values from Resource 
Bundles (see Java docu
 </File>
 ----
 
-== Spring Boot Lookup
+=== Spring Boot Lookup
+
 The Spring Boot Lookup retrieves the values of Spring properties from the 
Spring configuration as well as values of the active and default profiles. 
Specifying a key of "profiles.active" will return the active profiles while a 
key of "profiles.default" will return the default profiles. The default and 
active profiles can be an array. If more than one profile is present they will 
be returned as a comma separated list. To retrieve a single item from the array 
append "[\{index}]" to the key [...]
 
 This Lookup will return null values until Spring Boot initializes application 
logging. The Spring Boot Lookup requires the log4j-spring-boot jar be included 
as a dependency.
@@ -567,7 +577,7 @@ This Lookup will return null values until Spring Boot 
initializes application lo
 This Lookup requires log4j-spring-cloud-config-client be included in the 
application.
 
 [#StructuredDataLookup]
-== Structured Data Lookup
+=== Structured Data Lookup
 
 The StructuredDataLookup is very similar to the MapLookup in that it
 will retrieve values from StructuredDataMessages. In addition to the Map
@@ -596,7 +606,7 @@ while "type" would have to be an item in the Map in a 
MapMessage.
 ----
 
 [id=system-properties-lookup]
-== [[SystemPropertiesLookup]] System Properties Lookup
+=== [[SystemPropertiesLookup]] System Properties Lookup
 
 As it is quite common to define values inside and outside the
 application by using System Properties, it is only natural that they
@@ -623,7 +633,7 @@ when the `logPath` system property is undefined, the 
default value
 ----
 
 [#UpperLookup]
-== Upper Lookup
+=== Upper Lookup
 
 The LowerLookup converts the passed in argument to upper case. Presumably the 
value will be the
 result of a nested lookup.
@@ -638,7 +648,7 @@ result of a nested lookup.
 ----
 
 [#WebLookup]
-== Web Lookup
+=== Web Lookup
 
 The WebLookup allows applications to retrieve variables that are
 associated with the ServletContext. In addition to being able to
@@ -698,3 +708,34 @@ located then the corresponding value will be returned.
   <File name="ApplicationLog" fileName="${web:rootDir}/app.log"/>
 </Appenders>
 ----
+
+[#extending]
+== Extending
+
+Lookups are xref:manual/plugins.adoc[plugins] implementing 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[the
 `StrLookup` interface].
+This section will guide you on how to create custom ones.
+
+[NOTE]
+====
+While xref:#collection[the predefined lookup collection] should address most 
common use cases, you might find yourself needing to implement a custom one.
+If this is the case, we really appreciate it if you can *share your use case 
in a {logging-services-url}/support.html[user support channel]*.
+====
+
+[#extending-plugins]
+=== Plugin preliminaries
+
+include::partial$manual/plugin-preliminaries.adoc[]
+
+[#extending-lookups]
+=== Extending lookups
+
+Lookups are xref:manual/plugins.adoc[plugins] implementing 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html[the
 `StrLookup` interface].
+While annotating your lookup with `@Plugin`, you need to make sure that
+
+* It has a unique `name` attribute across all available `StrLookup` plugins
+* The `category` attribute is set to 
link:../javadoc/log4j-core/org/apache/logging/log4j/core/lookup/StrLookup.html#CATEGORY[`StrLookup.CATEGORY`]
+
+You can check out following files for examples:
+
+* 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/DateLookup.java[`LowerLookup.java`]
 – xref:#LowerLookup[] lower-cases its input
+* 
{project-github-url}/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/EventLookup.java[`EventLookup.java`]
 – xref:#EventLookup[] extracts specified fields from the effective `LogEvent` 
in the context
diff --git a/src/site/resources/.htaccess b/src/site/resources/.htaccess
index 708c2c5df7..6bef5ba191 100644
--- a/src/site/resources/.htaccess
+++ b/src/site/resources/.htaccess
@@ -54,7 +54,10 @@ RewriteRule "^log4j-slf4j-impl\.html$" 
"manual/installation.html#impl-core-bridg
 RewriteRule "^log4j-slf4j2-impl/index\.html$" 
"manual/installation.html#impl-core-bridge-slf4j" [R=permanent,NE]
 RewriteRule "^log4j-slf4j2-impl\.html$" 
"manual/installation.html#impl-core-bridge-slf4j" [R=permanent,NE]
 RewriteRule "^manual/api-separation\.html$" "manual/api.html" [R=permanent]
+RewriteRule "^manual/extending\.html#Appenders$" 
"manual/appenders.html#extending" [R=permanent]
+RewriteRule "^manual/extending\.html#Filters$" "manual/filters.html#extending" 
[R=permanent]
 RewriteRule "^manual/extending\.html#Layouts$" "manual/layouts.html#extending" 
[R=permanent]
+RewriteRule "^manual/extending\.html#Lookups$" "manual/lookups.html#extending" 
[R=permanent]
 RewriteRule "^manual/extending\.html#PatternConverters$" 
"manual/pattern-layout.html#extending-converters" [R=permanent]
 RewriteRule "^manual/layouts\.html#enable-jansi$" 
"manual/pattern-layout.html#jansi" [R=permanent]
 RewriteRule "^manual/layouts\.html#EndOfBatch$" 
"manual/pattern-layout.html#converter-end-of-batch" [R=permanent]


Reply via email to