blob: 180f5d1bd77d71ceb33cfb7562e8e5f3518962e1 [file] [log] [blame]
<?xml version="1.0"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
license agreements. See the NOTICE file distributed with this work for additional
information regarding copyright ownership. The ASF licenses this file to
You under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of
the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
by applicable law or agreed to in writing, software distributed under the
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, either express or implied. See the License for the specific
language governing permissions and limitations under the License. -->
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
<properties>
<title>Garbage-free Steady State Logging</title>
<author email="rpopma@apache.org">Remko Popma</author>
</properties>
<body>
<section name="Garbage-free Steady State Logging">
<!--
<p>
Different applications have different performance requirements.
Some only need to worry about throughput, but for many
the most important performance consideration is latency (response time).
Users of such applications would consider it a serious problem
if the system becomes unresponsive for more than a few seconds, or even milliseconds in some cases.
In financial trading for example predictable low latency is so important that it is often considered
worthwhile to trade off some throughput in return for a consistent response time.
</p>
-->
<p>
Garbage collection pauses are a common cause of latency spikes and for many systems
significant effort is spent on controlling these pauses.
</p>
<p>
Many logging libraries, including previous versions of Log4j, allocate temporary objects like
log event objects, Strings, char arrays, byte arrays and more during steady state logging.
This contributes to pressure on the garbage collector and increases the frequency with which GC pauses occur.
</p>
<p>
From version 2.6, Log4j runs in "garbage free" mode by default
where objects and buffers are reused and no temporary objects are allocated as much as possible.
There is also a "low garbage" mode which is not completely garbage free but does not use ThreadLocal fields.
This is the default mode when Log4j <a href="#Config">detects</a> it is running in a web application.
<!--
</p>
<p>
-->
Finally, it is possible to switch off all garbage-free logic and run in "classic mode" instead.
For details, see the <a href="#Config">Configuration</a> section below.
</p>
<a name="jfr" />
<subsection name="A Contrived Example">
<p>
To highlight the difference that garbage-free logging can make, we used Java Flight Recorder
to measure a simple application that does nothing but log a simple string as often as possible
for about 12 seconds.
</p>
<p>
The application was configured to use Async Loggers, a RandomAccessFile appender and a
"%d %p %c{1.} [%t] %m %ex%n" pattern layout. (Async Loggers used the Yield WaitStrategy.)
</p>
<p>
Mission Control shows that with Log4j 2.5 this application allocates memory at a rate of about 809 MB/sec,
resulting in 141 minor collections.
Log4j 2.6 does not allocate temporary objects in this configuration, and as a result
the same application with Log4j 2.6 has a memory allocation rate of 1.6 MB/sec and
was GC-free with 0 (zero) garbage collections.
</p>
<table>
<tr>
<td>
<a href="../images/log4j-2.5-FlightRecording.png"><img
src="../images/log4j-2.5-FlightRecording-thumbnail40pct.png" /></a><br />
With Log4j 2.5: memory allocation rate 809 MB/sec, 141 minor collections.
</td>
<td>
<a href="../images/log4j-2.6-FlightRecording.png"><img
src="../images/log4j-2.6-FlightRecording-thumbnail40pct.png" /></a>
<br />
Log4j 2.6 did not allocate temporary objects: 0 (zero) garbage collections.
</td>
</tr>
</table>
</subsection>
<a name="Config" />
<subsection name="Configuration">
<p>Garbage-free logging in Log4j 2.6 is partially implemented by reusing objects in ThreadLocal fields,
and partially by reusing buffers when converting text to bytes.
</p>
<p>
ThreadLocal fields holding non-JDK classes can cause memory leaks in
web applications when the application server's thread pool continues to reference
these fields after the web application is undeployed.
To avoid causing memory leaks, Log4j will not use these ThreadLocals when
it detects that it is used in a web application
(when the <tt>javax.servlet.Servlet</tt> class is in the classpath,
or when system property <tt>log4j2.isWebapp</tt> is set to "true").
</p>
<p>
Some garbage-reducing functionality does not rely on ThreadLocals and is
enabled by default for all applications:
in Log4j 2.6, converting log events to text and text to bytes can be done by directly encoding text
into a reused ByteBuffer without creating intermediary Strings, char arrays and byte arrays.
So while logging is not completely garbage-free for web applications yet,
the pressure on the garbage collector can still be significantly reduced.
</p>
<table><tr><td><p>
<b>Note 1:</b> as of version 2.6, a Log4j configuration containing a <tt>&lt;Properties&gt;</tt> section
will result in temporary objects being created during steady-state logging.
</p>
<p>
<b>Note 2:</b> the Async Logger Timeout wait strategy (the default) and the Block wait strategy
cause <tt>java.util.concurrent.locks.AbstractQueuedSynchronizer$Node</tt> objects to be created.
The Yield and Sleep wait strategies are garbage-free. (See
<a href="async.html#SysPropsAllAsync">here</a> and
<a href="async.html#SysPropsMixedSync-Async">here</a>.)
</p>
</td></tr></table>
<h4>Disabling Garbage-free Logging</h4>
<p>
There are two separate system properties for manually controlling the mechanisms Log4j uses to avoid
creating temporary objects:
</p>
<ul>
<li><tt>log4j2.enableThreadlocals</tt> - if "true" (the default for non-web applications)
objects are stored in ThreadLocal fields and reused, otherwise new
objects are created for each log event.</li>
<li><tt>log4j2.enableDirectEncoders</tt> - if "true" (the default) log events are converted to text and this
text is converted to bytes without creating temporary objects. Note:
<em>synchronous</em> logging performance may be worse for multi-threaded applications in this mode due to
synchronization on the shared buffer. If your application is multi-threaded and logging performance
is important, consider using Async Loggers.
</li>
<li>The ThreadContext map is <em>not</em> garbage-free by default, but from Log4j 2.7 it can be configured
to be garbage-free by setting system property <tt>log4j2.garbagefreeThreadContextMap</tt> to "true".</li>
</ul>
<p>
Instead of system properties, the above properties can also be specified in a file named
<tt>log4j2.component.properties</tt> by including this file in the classpath of the application.
See the <a href="configuration.html#SystemProperties">manual regarding system properties</a> for more info.
</p>
<a name="Appenders" />
<h4>Supported Appenders</h4>
<p>
The following <a href="appenders.html">appenders</a> are garbage-free during steady-state logging:
</p>
<ul>
<li>Console</li>
<li>File</li>
<li>RollingFile (some temporary objects are created during file rollover)</li>
<li>RandomAccessFile</li>
<li>RollingRandomAccessFile (some temporary objects are created during file rollover)</li>
<li>MemoryMappedFile</li>
</ul>
<p>
Any other appenders not in the above list (including AsyncAppender) create temporary objects
during steady-state logging. Instead of AsyncAppender, use <a href="async.html">Async Loggers</a>
to log asynchronously in a garbage-free manner.
</p>
<a name="Filters" />
<h4>Supported Filters</h4>
<p>
The following <a href="filters.html">filters</a> are garbage-free during steady-state logging:
</p>
<ul>
<li>CompositeFilter (adding and removing element filters creates temporary objects for thread safety)</li>
<li>DynamicThresholdFilter</li>
<li>LevelRangeFilter (garbage free since 2.8)</li>
<li>MapFilter (garbage free since 2.8)</li>
<li>MarkerFilter (garbage free since 2.8)</li>
<li>StructuredDataFilter (garbage free since 2.8)</li>
<li>ThreadContextMapFilter (garbage free since 2.8)</li>
<li>ThresholdFilter (garbage free since 2.8)</li>
<li>TimeFilter (garbage free since 2.8 except when range must be recalculated once per day)</li>
</ul>
<p>
Other filters like BurstFilter, RegexFilter and ScriptFilter are not trivial to make garbage free,
and there is currently no plan to change them.
</p>
<a name="Layouts" />
<h4>Supported Layouts</h4>
<h5>GelfLayout</h5>
<p>GelfLayout is garbage-free when used with compressionType="OFF",
as long as no additional field contains '${' (variable substitution).</p>
<h5>PatternLayout</h5>
<p>
PatternLayout with the following limited set of conversion patterns is garbage-free.
Format modifiers to control such things as field width, padding, left and right justification will not
generate garbage.
</p>
<table style="width: 80%">
<tr>
<th>Conversion Pattern</th>
<th>Description</th>
</tr>
<tr>
<td>%c{precision}, %logger{precision}</td>
<td>Logger name</td>
</tr>
<tr>
<td>%d, %date</td>
<td>Note: Only the predefined date formats are garbage-free: (millisecond separator may be either
a comma ',' or a period '.')
<table>
<tr>
<th>Pattern</th>
<th>Example</th>
</tr>
<tr>
<td>%d{DEFAULT}</td>
<td>2012-11-02 14:34:02,781</td>
</tr>
<tr>
<td>%d{ISO8601}</td>
<td>2012-11-02T14:34:02,781</td>
</tr>
<tr>
<td>%d{ISO8601_BASIC}</td>
<td>20121102T143402,781</td>
</tr>
<tr>
<td>%d{ABSOLUTE}</td>
<td>14:34:02,781</td>
</tr>
<tr>
<td>%d{DATE}</td>
<td>02 Nov 2012 14:34:02,781</td>
</tr>
<tr>
<td>%d{COMPACT}</td>
<td>20121102143402781</td>
</tr>
<tr>
<td>%d{HH:mm:ss,SSS}</td>
<td>14:34:02,781</td>
</tr>
<tr>
<td>%d{dd MMM yyyy HH:mm:ss,SSS}</td>
<td>02 Nov 2012 14:34:02,781</td>
</tr>
<tr>
<td>%d{HH:mm:ss}{GMT+0}</td>
<td>18:34:02</td>
</tr>
<tr>
<td>%d{UNIX}</td>
<td>1351866842</td>
</tr>
<tr>
<td>%d{UNIX_MILLIS}</td>
<td>1351866842781</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>%enc{pattern},
%encode{pattern}</td>
<td>Encodes special characters such as '\n' and HTML characters to help prevent
log forging and some XSS attacks that could occur when displaying logs in
a web browser - garbage-free since 2.8</td>
</tr>
<tr>
<td>%equals{pattern}{test}{substitution},
%equalsIgnoreCase{pattern}{test}{substitution}</td>
<td>Replaces occurrences of 'test', a string, with its replacement 'substitution'
in the string resulting from evaluation of the pattern - garbage-free since 2.8</td>
</tr>
<tr>
<td>%highlight{pattern}{style}</td>
<td>Adds ANSI colors - garbage-free since 2.7 (unless nested pattern is not garbage free)</td>
</tr>
<tr>
<td>K{key}, map{key}, MAP{key}
</td>
<td>Outputs the entries in a
<a class="javadoc" href="../log4j-api/apidocs/org/apache/logging/log4j/message/MapMessage.html">MapMessage</a>,
if one is present in the event - garbage-free since 2.8.</td>
</tr>
<tr>
<td>%m, %msg, %message</td>
<td>Log message (garbage-free unless message text contains '${')</td>
</tr>
<tr>
<td>%marker</td>
<td>The full name of the marker (including parents) - garbage-free since 2.8</td>
</tr>
<tr>
<td>%markerSimpleName</td>
<td>The simple name of the marker (not including parents)</td>
</tr>
<tr>
<td>%maxLen, %maxLength</td>
<td>Truncates another pattern to some max number of characters - garbage-free since 2.8</td>
</tr>
<tr>
<td>%n</td>
<td>The platform dependent line separator</td>
</tr>
<tr>
<td>%N, %nano</td>
<td>System.nanoTime() when the event was logged</td>
</tr>
<tr>
<td>%notEmpty{pattern},
%varsNotEmpty{pattern},
%variablesNotEmpty{pattern}
</td>
<td>Outputs the result of evaluating the pattern if and only if
all variables in the pattern are not empty - garbage-free since 2.8</td>
</tr>
<tr>
<td>%p, %level</td>
<td>The level of the logging event</td>
</tr>
<tr>
<td>%r,
%relative</td>
<td>The number of milliseconds elapsed since the JVM was started until the creation of the logging event
- garbage-free since 2.8</td>
</tr>
<tr>
<td>%sn, %sequenceNumber</td>
<td>A sequence number that will be incremented in every event - garbage-free since 2.8</td>
</tr>
<tr>
<td>%style{pattern}{ANSI style}</td>
<td>Style the message - garbage-free since 2.7 (unless nested pattern is not garbage free)</td>
</tr>
<tr>
<td>%T, %tid, %threadId</td>
<td>The ID of the thread that generated the logging event</td>
</tr>
<tr>
<td>%t, %tn, %thread, %threadName</td>
<td>The name of the thread that generated the logging event</td>
</tr>
<tr>
<td>%tp</td>
<td>The priority of the thread that generated the logging event</td>
</tr>
<tr>
<td>%X{key[,key2...]},
%mdc{key[,key2...]},
%MDC{key[,key2...]}</td>
<td>Outputs the Thread Context Map (also known as the Mapped Diagnostic Context or MDC)
associated with the thread that generated the logging event - garbage-free since 2.8</td>
</tr>
<tr>
<td>literal text</td>
<td>Garbage-free unless literal contains '${' (variable substitution)</td>
</tr>
</table>
<p>
Other PatternLayout conversion patterns, and other Layouts may be updated
to avoid creating temporary objects in future releases. (Patches welcome!)
</p>
<p>
<em>Note</em>: Logging exceptions and stack traces will create temporary objects with any layout.
(However, Layouts will only create these temporary objects when an exception actually occurs.)
We haven't figured out a way to log exceptions and stack traces without creating temporary objects.
That is unfortunate, but you probably still want to log them when they happen.
</p>
<table><tr><td><b>Note:</b> patterns containing regular expressions and lookups for property substitution
will result in temporary objects being created during steady-state logging.
<p>
Including location information is done by walking the stacktrace of an exception, which creates temporary
objects, so the following patterns are not garbage-free:
</p>
<ul>
<li>%C, %class - Class Name</li>
<li>%F, %file - File Location</li>
<li>%l, %location - Location</li>
<li>%L, %line - Line Location</li>
<li>%M, %method - Method Location</li>
</ul>
Also, the pattern converters for formatting Throwables are not garbage-free:
<ul>
<li>%ex, %exception, %throwable - The Throwable trace bound to the LoggingEvent</li>
<li>%rEx, %rException %rThrowable - Same as %ex but with wrapping exceptions</li>
<li>%xEx, %xException, %xThrowable - Same as %ex but with class packaging information</li>
<li>%u, %uuid - Creates a new random or time-based UUID while formatting</li>
</ul>
</td></tr></table>
<a name="api" />
<h4>API Changes</h4>
<p>
Methods have been added to the <tt>Logger</tt> interface so that no vararg array objects are created
when logging messages with up to ten parameters.
</p>
<p>
Also, methods have been added to the <tt>Logger</tt> interface to log <tt>java.lang.CharSequence</tt> messages.
User-defined objects that implement the <tt>CharSequence</tt> interface can be logged without creating
temporary objects: Log4j will try to turn CharSequence messages,
Object messages and message parameters
into text by appending them to a StringBuilder as a CharSequence.
This avoids calling <tt>toString()</tt> on these objects.
</p>
<p>
An alternative is to implement the
<a href="http://logging.apache.org/log4j/2.x/log4j-api/xref/org/apache/logging/log4j/util/StringBuilderFormattable.html"><tt>org.apache.logging.log4j.util.StringBuilderFormattable</tt></a>
interface.
If an object is logged that implements this interface, its <tt>formatTo</tt> method is called instead of
<tt>toString()</tt>.
</p>
<p>
Log4j may call <tt>toString()</tt> on message and parameter objects when garbage-free logging
is disabled (when system property <tt>log4j2.enableThreadlocals</tt> is set to "false".)
</p>
<a name="codeImpact" />
<h4>Impact on Application Code: Autoboxing</h4>
<p>
We made an effort to make logging garbage-free without requiring code changes in existing applications,
but there is one area where this was not possible.
When logging primitive values (i.e. int, double, boolean, etc.) the JVM
autoboxes these primitive values to their Object wrapper equivalents, creating garbage.
</p>
<p>
Log4j provides an <tt>Unbox</tt> utility to prevent autoboxing of primitive parameters.
This utility contains a thread-local pool of reused <tt>StringBuilder</tt>s.
The <tt>Unbox.box(primitive)</tt> methods write directly into a StringBuilder, and
the resulting text will be copied into the final log message text without creating temporary objects.
</p>
<pre class="prettyprint linenums">import static org.apache.logging.log4j.util.Unbox.box;
...
public void garbageFree() {
logger.debug("Prevent primitive autoboxing {} {}", box(10L), box(2.6d));
}
</pre>
<table><tr><td>
<p>
<b>Note:</b> not all logging is garbage free. Specifically:
</p>
<ul>
<li>The ThreadContext map is not garbage-free by default, but can be configured to be garbage-free
by setting system property <tt>log4j2.garbagefreeThreadContextMap</tt> to "true".</li>
<li>The ThreadContext stack is not garbage-free.</li>
<li>Logging more than 10 parameters creates vararg arrays.</li>
<li>Logging very large messages (more than 518 characters) when all loggers are Async Loggers
will cause the internal StringBuilder in the RingBuffer to be trimmed back to their max size.
</li>
<li>Logging messages containing '${': substituting a ${variable} creates temporary objects.</li>
<li>Logging a lambda <em>as a parameter</em>
(<tt>logger.info("lambda value is {}", () -> callExpensiveMethod())</tt>) creates a vararg array.
Logging a lambda expression by itself is garbage-free:
<tt>logger.debug(() -> callExpensiveMethod())</tt>.
</li>
<li>The <tt>Logger.traceEntry</tt> and <tt>Logger.traceExit</tt> methods create temporary objects.</li>
</ul>
</td></tr></table>
<p>
</p>
<p>
</p>
</subsection>
<a name="Performance" />
<subsection name="Performance">
<a name="Latency" />
<h4>Response Time Latency</h4>
<p>Response time is how long it takes to log a message under a certain load.
What is often reported as latency is actually <em>service time</em>: how long it took to perform the operation.
This hides the fact that a single spike in service time adds queueing delay for many of the subsequent operations.
Service time is easy to measure (and often looks good on paper) but is irrelevant for users since it
omits the time spent waiting for service.
For this reason we report response time: service time plus wait time.
See the <a href="../performance.html#responseTime">response time section</a> of the performance page for more detail.
</p>
<p>The response time test results below were all derived from running the ResponseTimeTest class
which can be found in the Log4j 2 unit test source directory. If you want to run these tests yourself,
here are the command line options we used:
</p>
<ul>
<li>-Xms1G -Xmx1G (prevent heap resizing during the test)</li>
<!--
<li>-XX:+UnlockDiagnosticVMOptions -XX:GuaranteedSafepointInterval=500000 (by default Hotspot schedules a
safepoint pause every second. Reduce jitter by postponing this for the duration of the test.)</li>
-->
<li>-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
-DAsyncLogger.WaitStrategy=busyspin (to use Async Loggers. The BusySpin wait strategy reduces some jitter.)</li>
<li><b>classic mode: </b>-Dlog4j2.enable.threadlocals=false -Dlog4j2.enable.direct.encoders=false<br />
<b>garbage-free mode: </b>-Dlog4j2.enable.threadlocals=true -Dlog4j2.enable.direct.encoders=true</li>
<li>-XX:CompileCommand=dontinline,org.apache.logging.log4j.core.async.perftest.NoOpIdleStrategy::idle</li>
<li>-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution
-XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime (to eyeball GC and safepoint pauses)</li>
</ul>
<!--
<pre style="overflow: auto; white-space: pre-wrap; word-wrap: normal;">java -Xms1G -Xmx1G -XX:+UnlockDiagnosticVMOptions -verbose:gc -XX:+PrintGCDetails
-XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime -XX:GuaranteedSafepointInterval=500000
-XX:CompileCommand=dontinline,org.apache.logging.log4j.core.async.perftest.NoOpIdleStrategy::idle
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
-Dlog4j2.enable.threadlocals=false -Dlog4j2.enable.direct.encoders=false -DAsyncLogger.WaitStrategy=busyspin
-cp .:HdrHistogram-2.1.8.jar:disruptor-3.3.4.jar:log4j-1.2.17.jar:slf4j-api-1.7.13.jar:slf4j-ext-1.7.13.jar:
logback-core-1.1.3.jar:logback-classic-1.1.3.jar:log4j-api-2.6-SNAPSHOT.jar:log4j-core-2.6-SNAPSHOT.jar:
log4j-core-2.6-SNAPSHOT-tests.jar org.apache.logging.log4j.core.async.perftest.ResponseTimeTest 1 50000</pre>
-->
<h4>Async Loggers</h4>
<p>The graph below compares "classic" logging to
garbage-free logging response time behaviour for Log4j's Async Loggers.
In the graph, "100k" means logging at a sustained load of 100,000 messages/second, "800k" is
a sustained load of 800,000 messages/second.
</p>
<p><img src="../images/ResponseTimeAsyncClassicVsGcFree-label.png" /></p>
<p>In <b>classic</b> mode we see numerous minor garbage collections which pause the application threads
for 3 milliseconds or more. This quickly adds up to response time delays of almost 10
milliseconds.
As you can see in the graph, increasing the load shifts the curve to the left (there are more spikes).
This makes sense: logging more means more pressure on the garbage collector resulting in more minor GC pauses.
We experimented a little with reducing the load to 50,000 or even 5000 messages/second,
but this did not eliminate the 3 millisecond pauses, it just made them occur less frequently.
Note that all GC pauses in this test are minor GC pauses. We did not see any full garbage collections.</p>
<p>In <b>garbage-free</b> mode, maximum response time remains well below 1 millisecond under a wide range of loads.
(Max 780 us at 800,000 messages/sec, max 407 us at 600,000 messages/sec, with the 99% around 5 us for
all loads up to 800,000 messages/sec.) Increasing or decreasing the load does not change the response time
behaviour. We did not investigate the cause of the 200-300 microsecond pauses we saw in these tests.
</p>
<p>
When we increased the load further we begin to see larger response time pauses for both classic and
garbage-free logging.
At sustained loads of 1 million messages/second or more we start to approach the maximum throughput of
the underlying RandomAccessFile Appender (see the synchronous logging throughput chart below).
At these loads the ringbuffer starts to fill up and backpressure kicks in: attempting to add another message
when the ringbuffer is full will block until a free slot becomes available. We start to see response times
of tens of milliseconds or more; and attempting to increase the load even more results in larger and larger
response time spikes.
</p>
<h4>Synchronous File Logging</h4>
<p>With synchronous file logging, garbage-free logging still performs better than classic logging,
but the difference is less pronounced.
</p>
<p>At a workload of 100,000 messages/second, classic logging max response time was a little over 2 milliseconds
where garbage-free logging was a little over 1 millisecond.
When the workload is increased to 300,000 messages/second, classic logging shows response time pauses of 6
milliseconds where the garbage-free response times were less than 3 milliseconds.
It may be possible to improve on this, we did not investigate further yet.</p>
<p><img src="../images/ResponseTimeSyncClassicVsGcFree.png" /></p>
<p>The above results are obtained with the ResponseTimeTest class which can be found in the Log4j 2
unit test source directory, running on JDK 1.8.0_45 on RHEL 6.5 (Linux 2.6.32-573.1.1.el6.x86_64)
with 10-core Xeon CPU E5-2660 v3 @2.60GHz with hyperthreading switched on (20 virtual cores).</p>
<a name="Throughput" />
<h4>Classic Logging has Slightly Higher Throughput</h4>
<p>Throughput is slightly worse for garbage-free logging, compared to classic logging.
This is true for both synchronous and asynchronous logging.
The graph below compares the sustained throughput of synchronous logging to a file with Log4j 2.6 in
garbage-free mode, classic mode and Log4j 2.5.</p>
<p><img src="../images/garbage-free2.6-SyncThroughputLinux.png"
alt="Throughput of Log4j 2.6 in garbage-free mode is slightly worse than in classic mode, but on par with 2.5 and much better than alternatives logging libraries" /></p>
<p>The results above are obtained with the
<a href="http://openjdk.java.net/projects/code-tools/jmh/">JMH</a> Java benchmark harness.
See the FileAppenderBenchmark source code in the log4j-perf module.</p>
</subsection>
<a name="UnderTheHood" />
<subsection name="Under the Hood">
<p>
Custom Message implementations that implement <tt>org.apache.logging.log4j.util.StringBuilderFormattable</tt>
can be converted to text by garbage-free Layouts without creating temporary objects.
PatternLayout uses this mechanism and other layouts that convert LogEvents to text
will likely also look for this interface.
</p>
<p>
Custom Layouts that want to be garbage-free should implement the <tt>Encoder&lt;LogEvent&gt;</tt> interface.
For custom Layouts that convert a LogEvent to a text representation,
the <tt>org.apache.logging.log4j.core.layout.StringBuilderEncoder</tt> class may be useful to convert this
text to bytes in a garbage-free manner.
</p>
<p>
Custom Appenders that want to be garbage-free should provide their Layout with a
<tt>ByteBufferDestination</tt> implementation that the Layout can directly write into.
</p>
<p>
<tt>AbstractOutputStreamAppender</tt> has been modified to make the ConsoleAppender, (Rolling)FileAppender,
(Rolling)RandomAccessFileAppender and MemoryMappedFileAppender garbage-free.
An effort has been made to minimize impact on custom Appenders that extend
<tt>AbstractOutputStreamAppender</tt>, but it is impossible to guarantee that changing the superclass
will not impact any and all subclasses. Custom Appenders that extend
<tt>AbstractOutputStreamAppender</tt> should verify that they still function correctly.
In case there is a problem, system property <tt>log4j2.enable.direct.encoders</tt> can be set to "false"
to revert to the pre-Log4j 2.6 behaviour.
</p>
<!--
<p>
TODO Applications that wish to reuse custom Message instances with Async Loggers should let
their Message classes implement the <tt>org.apache.logging.log4j.message.ReusableMessage</tt> interface.
TODO This is not sufficient: see LOG4J2-1342, would be nice if we could solve this in a generic way.
</p>
-->
</subsection>
</section>
</body>
</document>