blob: ac07ee3d465e2d7026d0d93b9bcd1d908c529f35 [file] [log] [blame]
////
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.
////
= Asynchronous loggers
Asynchronous logging is a technique to improve application logging performance by executing all I/O operations in a separate thread.
Log4j offers out-of-the-box two different asynchronous logging solutions:
Asynchronous appender::
A classical queue-based asynchronous appender, which is available since Log4j 1.
+
See xref:manual/appenders/delegating.adoc#AsyncAppender[Asynchronous appender] for more details.
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.
[WARNING]
====
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.
====
include::partial$manual/async-trade-offs.adoc[leveloffset=+1]
[#installation]
== Installation
In order to use async loggers, you need to add LMAX Disruptor to you application's dependencies, by adding the following dependency to your build tool:
include::partial$features/async-logger.adoc[]
[#configuration]
== Configuration
There are two ways asynchronous loggers can be used in Log4j.
You can:
** <<AllAsync>>, which gives a better performance,
** <<MixedSync-Async>>, which gives more flexibility.
Under the hood these methods use different Log4j plugins, but also share a
<<common-configuration-properties,set of common configuration properties>>.
[#AllAsync]
=== Making all loggers asynchronous
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#log4j2.contextSelector[`log4j2.contextSelector`]
property to one of the asynchronous logger context selectors:
link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/BasicAsyncLoggerContextSelector.html[`org.apache.logging.log4j.core.async.BasicAsyncLoggerContextSelector`]::
This will create a single logger context and disruptor for all the classes in the JVM,
link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncLoggerContextSelector.html[`org.apache.logging.log4j.core.async.AsyncLoggerContextSelector`]::
This will create a different logger context and disruptor for each classloader in the JVM.
[IMPORTANT]
====
When using an asynchronous logger context you should use only `Root` and `Logger` elements (cf.
xref:manual/configuration.adoc#configuring-loggers[Logger configuration]).
If you use `AsyncRoot` and `AsyncLogger` configuration elements, two asynchronous barriers will be created instead of one, which will impair performance.
====
[#SysPropsAllAsync]
=== Tuning a fully asynchronous configuration
Since Disruptor is initialized at the same time as the logger context and before any Log4j configuration file is loaded, tuning async loggers is only possible through configuration properties.
Beyond the <<common-configuration-properties,common configuration properties>>, the following additional elements are configurable:
include::partial$manual/systemproperties/properties-async-logger.adoc[leveloffset=+2]
* the generic behavior of asynchronous components, such as the queue full policy and message formatting.
+
See xref:manual/systemproperties.adoc#properties-async[common asynchronous logging configurations] for more details.
* the parameters of the disruptor, such as the size of the ring buffer and the wait strategy to use.
+
See xref:manual/systemproperties.adoc#properties-async-logger[asynchronous logger configuration] for more details.
[TIP]
====
You can place the selected value of the
xref:manual/systemproperties.adoc#log4j2.contextSelector[`log4j2.contextSelector`] and other configuration properties in a `log4j2.component.properties` file at the root of your application's classpath.
See xref:manual/systemproperties.adoc#property-sources[Property Sources] for more details.
====
[#MixedSync-Async]
=== Mixing synchronous and asynchronous loggers
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).
In order to use this configuration, you need to keep the
xref:manual/systemproperties.adoc#log4j2.contextSelector[`log4j2.contextSelector`] 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::
+
.Snippet from an example {antora-examples-url}/manual/async/mixed-async.xml[`log4j2.xml`]
[source,xml]
----
include::example$manual/async/mixed-async.xml[lines=31..40,indent=0]
----
JSON::
+
.Snippet from an example {antora-examples-url}/manual/async/mixed-async.json[`log4j2.json`]
[source,json]
----
include::example$manual/async/mixed-async.json[lines=17..36,indent=0]
----
YAML::
+
.Snippet from an example {antora-examples-url}/manual/async/mixed-async.yaml[`log4j2.yaml`]
[source,yaml]
----
include::example$manual/async/mixed-async.yaml[lines=27..-1,indent=0]
----
Properties::
+
.Snippet from an example {antora-examples-url}/manual/async/mixed-async.properties[`log4j2.properties`]
[source,properties]
----
include::example$manual/async/mixed-async.properties[lines=28..-1]
----
====
<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.
[[SysPropsMixedSync-Async]]
=== Tuning a mixed synchronous/asynchronous configuration
Since all `AsyncRoot` and `AsyncLogger` components share the same Disruptor instance, its configuration is available through configuration properties.
Beyond the <<common-configuration-properties,common configuration properties>>, the following additional elements are configurable:
include::partial$manual/systemproperties/properties-async-logger-config.adoc[leveloffset=+2]
[TIP]
====
You can place the values of configuration properties in a `log4j2.component.properties` file at the root of your application's classpath.
See xref:manual/systemproperties.adoc#property-sources[Property Sources] for more details.
====
[#common-configuration-properties]
=== Common configuration properties
Regardless of the way you configure asynchronous loggers in Log4j, you can use the following properties to further tune your installation:
include::partial$manual/systemproperties/properties-async.adoc[leveloffset=+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::
+
.Snippet from an example {antora-examples-url}/manual/async/custom-wait-strategy.xml[`log4j2.xml`]
[source,xml]
----
include::example$manual/async/custom-wait-strategy.xml[lines=23,indent=0]
----
JSON::
+
.Snippet from an example {antora-examples-url}/manual/async/custom-wait-strategy.json[`log4j2.json`]
[source,json]
----
include::example$manual/async/custom-wait-strategy.json[lines=3..5,indent=0]
----
YAML::
+
.Snippet from an example {antora-examples-url}/manual/async/custom-wait-strategy.yaml[`log4j2.yaml`]
[source,yaml]
----
include::example$manual/async/custom-wait-strategy.yaml[lines=18..-1]
----
Properties::
+
.Snippet from an example {antora-examples-url}/manual/async/custom-wait-strategy.properties[`log4j2.properties`]
[source,properties]
----
include::example$manual/async/custom-wait-strategy.properties[lines=17..-1]
----
====
[#Location]
== 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-core/org/apache/logging/log4j/core/async/RingBufferLogEvent.html[`ExceptionHandler<? super RingBufferLogEvent>`]
* set its fully qualified class name as value of the
xref:manual/systemproperties.adoc#log4j2.asyncLoggerExceptionHandler[`log4j2.asyncLoggerExceptionHandler`]
configuration property.
Mixed synchronous/asynchronous::
+
If you use a mix of synchronous and asynchronous loggers you need to:
+
* implement a
link:../javadoc/log4j-core/org/apache/logging/log4j/core/async/AsyncLoggerConfigDisruptor.Log4jEventWrapper.html[`ExceptionHandler<? super AsyncLoggerConfigDisruptor.Log4jEventWrapper>`]
* set its fully qualified class name as value of the
xref:manual/systemproperties.adoc#log4j2.asyncLoggerConfigExceptionHandler[`log4j2.asyncLoggerConfigExceptionHandler`]
configuration property.