This is an automated email from the ASF dual-hosted git repository.
pkarwasz pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/main by this push:
new 1659e1c7d6 Port "Asynchronous loggers" page to `main`
1659e1c7d6 is described below
commit 1659e1c7d6240acfc5c2956c0f3cc177b7290c96
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Tue May 28 13:57:15 2024 +0200
Port "Asynchronous loggers" page to `main`
---
.../manual/configuration/custom-wait-strategy.json | 7 +
.../configuration/custom-wait-strategy.properties | 18 ++
.../manual/configuration/custom-wait-strategy.xml | 24 ++
.../manual/configuration/custom-wait-strategy.yaml | 19 ++
.../examples/manual/configuration/mixed-async.json | 37 +++
.../manual/configuration/mixed-async.properties | 38 +++
.../examples/manual/configuration/mixed-async.xml | 41 +++
.../examples/manual/configuration/mixed-async.yaml | 40 +++
.../antora/modules/ROOT/pages/manual/async.adoc | 359 ++++++++++-----------
.../ROOT/partials/manual/async-trade-offs.adoc | 6 +-
.../manual/dependencies-log4j-async-logger.adoc | 37 +++
11 files changed, 429 insertions(+), 197 deletions(-)
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.json
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.json
new file mode 100644
index 0000000000..04f82de485
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.json
@@ -0,0 +1,7 @@
+{
+ "Configuration": {
+ "AsyncWaitStrategyFactor": {
+ "class": "com.example.AsyncWaitStrategyFactory"
+ }
+ }
+}
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.properties
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.properties
new file mode 100644
index 0000000000..44180c3064
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.properties
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+strategy.type = AsyncWaitStrategyFactory
+strategy.class = com.exampleAsyncWaitStrategyFactory
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.xml
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.xml
new file mode 100644
index 0000000000..fa26cdb7c8
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-config-2.xsd">
+ <AsyncWaitStrategyFactory class="com.example.AsyncWaitStrategyFactory"/>
+</Configuration>
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.yaml
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.yaml
new file mode 100644
index 0000000000..423d5152ac
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/custom-wait-strategy.yaml
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+Configuration:
+ AsyncWaitStrategyFactory:
+ class: "com.example.AsyncWaitStrategyFactory"
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.json
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.json
new file mode 100644
index 0000000000..87d5a16b82
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.json
@@ -0,0 +1,37 @@
+{
+ "Configuration": {
+ "Appenders": [
+ {
+ "name": "AUDIT",
+ "fileName": "logs/audit.log",
+ "ignoreExceptions": false,
+ "JsonTemplateLayout": {}
+ },
+ {
+ "name": "DEBUG_LOG",
+ "fileName": "logs/debug.log",
+ "PatternLayout": {}
+ }
+ ]
+ },
+ "Loggers": {
+ "Root": {
+ "level": "INFO",
+ "AppenderRef": { // <1>
+ "ref": "AUDIT",
+ "MarkerFilter": {
+ "marker": "AUDIT",
+ "onMatch": "ACCEPT",
+ "onMismatch": "DENY"
+ }
+ }
+ },
+ "AsyncLogger": { // <2>
+ "name": "com.example",
+ "level": "TRACE",
+ "AppenderRef": {
+ "ref": "DEBUG_LOG"
+ }
+ }
+ }
+}
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.properties
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.properties
new file mode 100644
index 0000000000..5d5ef95000
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.properties
@@ -0,0 +1,38 @@
+#
+# 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.
+#
+appender.0.type = File
+appender.0.name = AUDIT
+appender.0.fileName = logs/audit.log
+appender.0.ignoreExceptions = false
+appender.0.layout.type = JsonTemplateLayout
+
+appender.1.type = File
+appender.1.name = DEBUG_LOG
+appender.1.fileName = logs/debug.log
+appender.1.layout.type = PatternLayout
+
+rootLogger.level = INFO
+rootLogger.appenderRef.0.ref = AUDIT # <1>
+rootLogger.appenderRef.0.filter.0.type = MarkerFilter
+rootLogger.appenderRef.0.filter.0.marker = AUDIT
+rootLogger.appenderRef.0.filter.0.onMatch = ACCEPT
+rootLogger.appenderRef.0.filter.0.onMismatch = DENY
+
+logger.0.type = AsyncLogger
+logger.0.name = com.example
+logger.0.level = TRACE
+logger.0.appenderRef.0.ref = DEBUG_LOG # <2>
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.xml
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.xml
new file mode 100644
index 0000000000..d0ac5d22a5
--- /dev/null
+++ b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ 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.
+ -->
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ https://logging.apache.org/xml/ns
+ https://logging.apache.org/xml/ns/log4j-config-2.xsd">
+ <Appenders>
+ <File name="AUDIT" fileName="logs/audit.log" ignoreExceptions="false">
+ <JsonTemplateLayout/>
+ </File>
+ <File name="DEBUG_LOG" fileName="logs/debug.log">
+ <PatternLayout/>
+ </File>
+ </Appenders>
+ <Loggers>
+ <Root level="INFO">
+ <AppenderRef ref="AUDIT"> <!--1-->
+ <MarkerFilter marker="AUDIT" onMatch="ACCEPT" onMimatch="DENY"/>
+ </AppenderRef>
+ </Root>
+ <AsyncLogger name="com.example" level="TRACE">
+ <AppenderRef ref="DEBUG_LOG"/> <!--2-->
+ </AsyncLogger>
+ </Loggers>
+</Configuration>
diff --git
a/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.yaml
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.yaml
new file mode 100644
index 0000000000..4402814317
--- /dev/null
+++
b/src/site/antora/modules/ROOT/examples/manual/configuration/mixed-async.yaml
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+Configuration:
+ Appenders:
+ File:
+ - name: "AUDIT"
+ fileName: "logs/audit.log"
+ ignoreExceptions: false
+ JsonTemplateLayout: {}
+ - name: "DEBUG_LOG"
+ fileName: "logs/debug.log"
+ PatternLayout: {}
+ Loggers:
+ Root:
+ level: "INFO"
+ AppenderRef: # <1>
+ ref: "AUDIT"
+ MarkerFilter:
+ marker: "AUDIT"
+ onMatch: "ACCEPT"
+ onMismatch: "DENY"
+ AsyncLogger:
+ name: "com.example"
+ level: "TRACE"
+ AppenderRef: # <2>
+ ref: "DEBUG_LOG"
diff --git a/src/site/antora/modules/ROOT/pages/manual/async.adoc
b/src/site/antora/modules/ROOT/pages/manual/async.adoc
index 054e414482..9e89baf2c5 100644
--- a/src/site/antora/modules/ROOT/pages/manual/async.adoc
+++ b/src/site/antora/modules/ROOT/pages/manual/async.adoc
@@ -16,243 +16,214 @@
////
= Asynchronous loggers
-Asynchronous logging can improve your application's performance by executing
the I/O operations in a separate thread.
-Log4j 2 makes a number of improvements in this area.
+Asynchronous logging is a technique to improve application logging performance
by executing all I/O operations in a separate thread.
-* *Asynchronous Loggers* are a new addition in Log4j 2. Their aim is to return
from the call to Logger.log to the application as soon as possible.
-You can choose between making all Loggers asynchronous or using a mixture of
synchronous and asynchronous Loggers.
-Making all Loggers asynchronous will give the best performance, while mixing
gives you more flexibility.
-* *LMAX Disruptor technology*.
-Asynchronous Loggers internally use the
-link:#UnderTheHood[Disruptor], a lock-free inter-thread communication library,
instead of queues, resulting in higher throughput and lower latency.
-* As part of the work for Async Loggers, *Asynchronous Appenders* have been
enhanced to flush to disk at the end of a batch (when the queue is empty).
-This produces the same result as configuring "immediateFlush=true", that is,
all received log events are always available on disk, but is more efficient
because it does not need to touch the disk on each and every log event.
-(Async Appenders use ArrayBlockingQueue internally and do not need the
disruptor jar on the classpath.)
+Log4j offers out-of-the-box two different asynchronous logging solutions:
-[#Trade-offs]
-== Trade-offs
+Asynchronous appender::
+A classical queue-based asynchronous appender, which is available since Log4j
1.
++
+See xref:manual/appenders.adoc#AsyncAppender[Asynchronous appender] for more
details.
-Although asynchronous logging can give significant performance benefits, there
are situations where you may want to choose synchronous logging.
-This section describes some of the trade-offs of asynchronous logging.
+Asynchronous loggers::
+Asynchronous loggers are a new feature available since Log4j 2.
+They are based on
+{lmax-disruptor-url}[LMAX Disruptor],
+a lock-free inter-thread communication library, instead of queues, resulting
in higher throughput and lower latency.
++
+The rest of this chapter is dedicated to this new component.
-=== Benefits
+[CAUTION]
+====
+Logging performance depends greatly on the architecture of your application
and the way you use logging.
+The solutions offered by this chapter should be evaluated using benchmarks
against your own application.
+If benchmarks and profiling don't show a statistically significant difference
between asynchronous and synchronous logging solutions, the latter one is
recommended, since it is the simplest one.
+====
-* Higher peak performance throughput.
-With an asynchronous logger your application can log messages at 6 - 68 times
the rate of a synchronous logger.
-+
-This is especially interesting for applications that occasionally need to log
bursts of messages.
-Async logging can help prevent or dampen latency spikes by shortening the wait
time until the next message can be logged.
-If the queue size is configured large enough to handle the burst, asynchronous
logging will help prevent your application from falling behind (as much) during
a sudden increase of activity.
-* Lower logging response time link:#Latency[latency].
-Response time latency is the time it takes for a call to Logger.log to return
under a given workload.
-Asynchronous Loggers have consistently lower latency than synchronous loggers
or even queue-based asynchronous appenders.
+include::partial$manual/async-trade-offs.adoc[leveloffset=+1]
-=== Drawbacks
+[#installation]
+== Installation
-There are certain drawbacks associated with asynchronous logging:
+In order to use async loggers, you need to add `log4j-async-logger` to you
application's dependencies, by adding the
+following dependency to your build tool:
-include::partial$manual/async-drawbacks.adoc[]
+include::partial$manual/dependencies-log4j-async-logger.adoc[]
-[#AllAsync]
-== Making All Loggers Asynchronous
+[#configuration]
+== Configuration
-NOTE: _Log4j-2.9 and higher require disruptor-3.3.4.jar or higher on the
classpath.
-Prior to Log4j-2.9, disruptor-3.0.0.jar or higher was required._
+There are two ways asynchronous loggers can be used in Log4j.
+You can:
-This is simplest to configure and gives the best performance.
-To make all loggers asynchronous, add the disruptor jar to the classpath and
set the system property `log4j2.contextSelector` to
-`org.apache.logging.log4j.core.async.AsyncLoggerContextSelector` or
-`org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector`.
+** <<AllAsync>>, which gives a better performance,
+** <<MixedSync-Async>>, which gives more flexibility.
-By default, link:#Location[location] is not passed to the I/O thread by
asynchronous loggers.
-If one of your layouts or custom filters needs location information, you need
to set "includeLocation=true" in the configuration of all relevant loggers,
including the root logger.
+Under the hood these methods use different Log4j plugins, but also share a
+<<common-configuration-properties,set of common configuration properties>>.
-A configuration that does not require location might look like:
+[#AllAsync]
+=== Making all loggers asynchronous
-[source,xml]
-----
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- Don't forget to set system property
--Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
-or
--Dlog4j2.contextSelector=org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector
- to make all loggers asynchronous. -->
-
-<Configuration status="WARN">
- <Appenders>
- <!-- Async Loggers will auto-flush in batches, so switch off
immediateFlush. -->
- <RandomAccessFile name="RandomAccessFile" fileName="async.log"
immediateFlush="false" append="false">
- <PatternLayout>
- <Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern>
- </PatternLayout>
- </RandomAccessFile>
- </Appenders>
- <Loggers>
- <Root level="info" includeLocation="false">
- <AppenderRef ref="RandomAccessFile"/>
- </Root>
- </Loggers>
-</Configuration>
-----
+This is the simplest to configure and gives the best performance: to make all
logger asynchronous, **all** you need to set the
+xref:manual/systemproperties.adoc#log4j.loggerContext.selector[`log4j.loggerContext.selector`]
+property to one of the asynchronous logger context selectors:
-When `AsyncLoggerContextSelector` or
-`BasicAsyncLoggerContextSelector` is used to make all loggers asynchronous,
make sure to use normal `<root>` and `<logger>` elements in the configuration.
-The context selector will ensure that all loggers are asynchronous, using a
mechanism that is different from what happens when you configure `<asyncRoot>`
or `<asyncLogger>`.
-The latter elements are intended for mixing async with sync loggers.
-If you use both mechanisms together you will end up with two background
threads, where your application passes the log message to thread A, which
passes the message to thread B, which then finally logs the message to disk.
-This works, but there will be an unnecessary step in the middle.
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector[org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector]::
+This will create a single logger context and disruptor for all the classes in
the JVM,
-There are a few system properties you can use to control aspects of the
asynchronous logging subsystem.
-Some of these can be used to tune logging performance.
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector[org.apache.logging.log4j.core.async.AsyncLoggerContextSelector]::
+This will create a different logger context and disruptor for each classloader
in the JVM.
-The below properties can also be specified by creating a file named
-`log4j2.component.properties` and including this file in the classpath of the
application.
+[IMPORTANT]
+====
+When using an asynchronous logger context you should use only `Root` and
`Logger` elements (cf.
+xref:manual/configuration.adoc#configuring-loggers[Logger configuration]).
-[#MixedSync-Async]
-== Mixing Synchronous and Asynchronous Loggers
+If you use `AsyncRoot` and `AsyncLogger` configuration elements, two
asynchronous barriers will be created instead of one, which will impair
performance.
+====
-NOTE: _Log4j-2.9 and higher require disruptor-3.3.4.jar or higher on the
classpath.
-Prior to Log4j-2.9, disruptor-3.0.0.jar or higher was required.
-There is no need to set system property "Log4jContextSelector" to any value._
+[#MixedSync-Async]
+=== Mixing synchronous and asynchronous loggers
-Synchronous and asynchronous loggers can be combined in configuration.
+Synchronous and asynchronous loggers can be combined in a single configuration.
This gives you more flexibility at the cost of a slight loss in performance
(compared to making all loggers asynchronous).
-Use the
-`<asyncRoot>` or `<asyncLogger>` configuration elements to specify the loggers
that need to be asynchronous.
-A configuration can contain only one root logger (either a `<root>` or an
`<asyncRoot>` element), but otherwise async and non-async loggers may be
combined.
-For example, a configuration file containing `<asyncLogger>` elements can also
contain
-`<root>` and `<logger>` elements for the synchronous loggers.
-By default, link:#Location[location] is not passed to the I/O thread by
asynchronous loggers.
-If one of your layouts or custom filters needs location information, you need
to set "includeLocation=true" in the configuration of all relevant loggers,
including the root logger.
+In order to use this configuration, you need to keep the
+xref:manual/systemproperties.adoc#log4j.loggerContext.selector[`log4j.loggerContext.selector`]
+at its default value and use one of the
+`AsyncRoot` and `AsyncLogger` configuration elements to designate the loggers
that you want to be asynchronous.
A configuration that mixes asynchronous loggers might look like:
+[tabs]
+====
+XML::
++
[source,xml]
----
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- No need to set system property "log4j2.contextSelector" to any value
- when using <asyncLogger> or <asyncRoot>. -->
-
-<Configuration status="WARN">
- <Appenders>
- <!-- Async Loggers will auto-flush in batches, so switch off
immediateFlush. -->
- <RandomAccessFile name="RandomAccessFile" fileName="asyncWithLocation.log"
- immediateFlush="false" append="false">
- <PatternLayout>
- <Pattern>%d %p %class{1.} [%t] %location %m %ex%n</Pattern>
- </PatternLayout>
- </RandomAccessFile>
- </Appenders>
- <Loggers>
- <!-- pattern layout actually uses location, so we need to include it -->
- <AsyncLogger name="com.foo.Bar" level="trace" includeLocation="true">
- <AppenderRef ref="RandomAccessFile"/>
- </AsyncLogger>
- <Root level="info" includeLocation="true">
- <AppenderRef ref="RandomAccessFile"/>
- </Root>
- </Loggers>
-</Configuration>
+include::example$manual/configuration/mixed-async.xml[lines=1;18..-1]
+----
+
+JSON::
++
+[source,json]
+----
+include::example$manual/configuration/mixed-async.json[]
+----
+
+YAML::
++
+[source,yaml]
+----
+include::example$manual/configuration/mixed-async.yaml[lines=17..-1]
+----
+
+Java properties::
++
+[source,properties]
+----
+include::example$manual/configuration/mixed-async.properties[lines=17..-1]
----
+====
-There are a few system properties you can use to control aspects of the
asynchronous logging subsystem.
-Some of these can be used to tune logging performance.
+<1> All the appenders referenced by `Root` and `Logger` are called
synchronously.
+This is especially important for audit logging, since exceptions can be
forwarded to the caller.
+<2> All the appenders references by `AsyncRoot` and `AsyncLogger` are called
asynchronously.
+These log statements will cause a smaller latency for the caller.
-The below properties can also be specified by creating a file named
-`log4j2.component.properties` and including this file in the classpath of the
application.
+[#common-configuration-properties]
+=== Common configuration properties
-[#configuration-properties]
-== Configuration properties
+[TIP]
+====
+You can place the values of configuration properties in a
`log4j2.component.properties` file at the root of your application's classpath.
-include::partial$manual/systemproperties/properties-async-logger.adoc[leveloffset=+1]
+See xref:manual/systemproperties.adoc#property-sources[Property Sources] for
more details.
+====
-[#WaitStrategy]
-== Custom WaitStrategy
+Regardless of the way you configure asynchronous loggers in Log4j, you can use
the following properties to further tune your installation:
-The system properties mentioned above allow only choice from among a fixed set
of predefined WaitStrategies.
-There may be cases where you want to configure a custom WaitStrategy that is
not in this list.
-This is possible by using a `AsyncWaitStrategyFactory` element in the Log4j
configuration.
+include::partial$manual/systemproperties/properties-async.adoc[leveloffset=+2]
-A configuration that configures a custom WaitStrategy can look as follows:
+include::partial$manual/systemproperties/properties-async-logger.adoc[leveloffest=+2]
+[#custom-waitstrategy]
+== Custom `WaitStrategy`
+
+The system properties mentioned in the section above allow only to choose from
among a fixed set of wait strategies.
+
+In order to use a custom wait strategy you need to:
+
+. Use the <<MixedSync-Async,mixed sync/async configuration method>> above,
+. Implement the interface
+link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncWaitStrategyFactory.html[AsyncWaitStrategyFactory];
the implementation must have a public no-arg constructor,
+. Add an
xref:plugin-reference.adoc#org-apache-logging-log4j_log4j-core_org-apache-logging-log4j-core-async-AsyncWaitStrategyFactoryConfig[AsyncWaitStrategyFactory
Log4j plugin]
+to your configuration.
+
+[tabs]
+====
+XML::
++
[source,xml]
----
-<?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="WARN">
-
- <AsyncWaitStrategyFactory
- class="my.custom.AsyncWaitStrategyFactory" />
-
- <Appenders>
- <File name="MyFile" fileName="logs/app.log">
- <PatternLayout pattern="%d %p %c{1.} [%t] %m%n" />
- </File>
- </Appenders>
- <Loggers>
- <AsyncRoot level="info">
- <AppenderRef ref="MyFile"/>
- </AsyncRoot>
- </Loggers>
-</Configuration>
+include::example$manual/configuration/custom-wait-strategy.xml[lines=1;18..-1]
----
-The specified class must implement the
-`org.apache.logging.log4j.core.async.AsyncWaitStrategyFactory` interface,
which is defined as follows:
-
-[source,java]
+JSON::
++
+[source,json]
----
-public interface AsyncWaitStrategyFactory {
- /**
- * Returns a non-null implementation of the LMAX Disruptor's WaitStrategy
interface.
- * This WaitStrategy will be used by Log4j Async Loggers and Async
LoggerConfigs.
- *
- * @return the WaitStrategy instance to be used by Async Loggers and Async
LoggerConfigs
- */
- WaitStrategy createWaitStrategy();
-}
+include::example$manual/configuration/custom-wait-strategy.json[]
----
-The specified class must also have a public no-argument constructor; Log4j
will instantiate an instance of the specified factory class and use this
factory to create the WaitStrategy used by all Async Loggers.
+YAML::
++
+[source,yaml]
+----
+include::example$manual/configuration/custom-wait-strategy.yaml[lines=17..-1]
+----
-WaitStrategy-related system properties are ignored if a
`AsyncWaitStrategyFactory` is configured.
+Java properties::
++
+[source,properties]
+----
+include::example$manual/configuration/custom-wait-strategy.properties[lines=17..-1]
+----
+====
[#Location]
-== Location, location, location...
-
-If one of the layouts is configured with a location-related attribute like
HTML xref:manual/layouts.adoc#HtmlLocationInfo[locationInfo], or one of the
patterns xref:manual/layouts.adoc#PatternClass[%C or $class],
-xref:manual/layouts.adoc#PatternFile[%F or %file],
-xref:manual/layouts.adoc#PatternLocation[%l or %location],
-xref:manual/layouts.adoc#PatternLine[%L or %line],
-xref:manual/layouts.adoc#PatternMethod[%M or %method], Log4j will take a
snapshot of the stack, and walk the stack trace to find the location
information.
-
-This is an expensive operation: 1.3 - 5 times slower for synchronous loggers.
-Synchronous loggers wait as long as possible before they take this stack
snapshot.
-If no location is required, the snapshot will never be taken.
-
-However, asynchronous loggers need to make this decision before passing the
log message to another thread; the location information will be lost after that
point.
-The performance impact of taking a stack trace snapshot is even higher for
asynchronous loggers:
-logging with location is 30-100 times slower than without location.
-For this reason, asynchronous loggers and asynchronous appenders do not
include location information by default.
-
-You can override the default behaviour in your logger or asynchronous appender
configuration by specifying `includeLocation="true"`.
-
-[#UnderTheHood]
-== Under The Hood
-
-Asynchronous Loggers are implemented using the
-https://lmax-exchange.github.io/disruptor/[LMAX Disruptor] inter-thread
messaging library.
-From the LMAX web site:
-
-____
-...using queues to pass data between stages of the system was
-introducing latency, so we focused on optimising this area.
-The Disruptor is the result of our research and testing.
-We found that cache misses at the CPU-level, and locks requiring kernel
arbitration are both extremely costly, so we created a framework which has
"mechanical sympathy" for the hardware it's running on, and that's lock-free.
-____
-
-LMAX Disruptor internal performance comparisons with
-`java.util.concurrent.ArrayBlockingQueue` can be found
-https://github.com/LMAX-Exchange/disruptor/wiki/Performance-Results[here].
+== Location information
+
+xref:manual/layouts.adoc#LocationInformation[Computing the location
information (i.e., the caller class, method, file, and line number) of a log
event is an expensive operation.]
+The impact on asynchronous loggers and appenders is even higher, since the
component must decide whether to compute it or not **before** crossing the
asynchronous barrier.
+Hence, the location information is disabled by default for asynchronous
loggers and appenders.
+In order to enable it for a certain logger, set its
xref:manual/configuration.adoc#logger-attributes-includeLocation[`includeLocation`]
attribute to `true`.
+
+[id=exception-handler]
+== Exception handler
+
+In order to handle exceptions that occur on the asynchronous thread, you can
configure a custom
+https://lmax-exchange.github.io/disruptor/javadoc/com.lmax.disruptor/com/lmax/disruptor/ExceptionHandler.html[ExceptionHandler<T>].
+
+The exact type of handler depends on the configuration mode:
+
+Full asynchronous::
++
+If all the loggers are asynchronous you need to:
++
+* implement an
+link:../javadoc/log4j-async-logger/org/apache/logging/log4j/async/logger/AsyncLoggerExceptionHandler.html[`AsyncLoggerExceptionHandler`]
+* set its fully qualified class name as value of the
+xref:manual/systemproperties.adoc#log4j.async.logger.exceptionHandler[`log4j.async.logger.exceptionHandler`]
+configuration property.
+
+Mixed synchronous/asynchronous::
++
+If you use a mix of synchronous and asynchronous loggers you need to:
++
+* implement a
+link:../javadoc/log4j-async-logger/org/apache/logging/log4j/async/logger/AsyncLoggerConfigExceptionHandler.html[`AsyncLoggerConfigExceptionHandler`]
+* set its fully qualified class name as value of the
+xref:manual/systemproperties.adoc#log4j.async.logger.configExceptionHandler[`log4j.async.logger.configExceptionHandler`]
+configuration property.
diff --git a/src/site/antora/modules/ROOT/partials/manual/async-trade-offs.adoc
b/src/site/antora/modules/ROOT/partials/manual/async-trade-offs.adoc
index 5ec841013c..b048f0c2d0 100644
--- a/src/site/antora/modules/ROOT/partials/manual/async-trade-offs.adoc
+++ b/src/site/antora/modules/ROOT/partials/manual/async-trade-offs.adoc
@@ -56,13 +56,13 @@ Stateful messages::
Most
link:../javadoc/log4j-api/org/apache/logging/log4j/message/Message.html[`Message`]
implementations take a snapshot of the formatted message on the calling thread
(cf.
-xref:manual/systemproperties.adoc#log4j2.formatMsgAsync[`log4j2.formatMsgAsync`]).
+xref:manual/systemproperties.adoc#log4j.async.formatMessagesInBackground[`log4j.async.formatMessagesInBackground`]).
The log message will not change even if the arguments of the logging call are
modified later.
+
There are some exceptions to this rule.
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/MapMessage.html[`MapMessage`]
+{log4j2-url}/manual/messages.html#MapMessage[`MapMessage`]
and
-link:../javadoc/log4j-api/org/apache/logging/log4j/message/StructuredDataMessage.html[`StructuredDataMessage`]
+{log4j2-url}/manual/messages.html#StructuredDataMessage[`StructuredDataMessage`]
for example are mutable by design: fields can be added to these messages after
the message object was created.
These messages should not be modified after they are logged with asynchronous
loggers or asynchronous appenders.
+
diff --git
a/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-async-logger.adoc
b/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-async-logger.adoc
new file mode 100644
index 0000000000..9fd4cfb122
--- /dev/null
+++
b/src/site/antora/modules/ROOT/partials/manual/dependencies-log4j-async-logger.adoc
@@ -0,0 +1,37 @@
+////
+ 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.
+////
+
+[tabs]
+====
+Maven::
++
+[source,xml,subs="+attributes"]
+----
+<dependency>
+ <groupId>org.apache.logging.log4j</groupId>
+ <artifactId>log4j-async-logger</artifactId>
+ <scope>runtime</scope>
+</dependency>
+----
+
+Gradle::
++
+[source,groovy,subs="+attributes"]
+----
+runtimeOnly 'org.apache.logging.log4j:log4j-async-logger'
+----
+====