It’s been almost six months since we released Log4j 2.5, and we have a bunch of neat things added since then. The biggest change is that now you can operate Log4j in a garbage-free mode during steady state logging. Sounds a bit jargony? The basic idea here is that once your application is initialized and doing its thing (the steady state), logging no longer contributes towards memory pressure, thus you have more control over memory allocation and gargabe collection. Various Java performance gurus point out that logging tends to add a lot of overhead to applications, and one major reason is due to garbage generated by the logging framework. The less garbage objects generated by the framework, the less time your application needs to spend collecting said garbage.
In prior versions of Log4j (and every other major logging framework), various
temporary objects are created with each call to
Logger.log(). For instance,
Logger.info(String message, Object... args) would allocate a
temporary array to hold the arguments passed to the method. In Log4j 2.6, we’ve
added unrolled versions of these methods up to 10 arguments. In contrast,
SLF4J 1.7.21 only provides up to two unrolled arguments.
Another source of garbage is the boxing of primitive values into their object
forms. For certain primitives and small values, these boxed values are already
cached by the JVM and don’t really add any overhead, but in general, you might
not want your application to allocate new
Long instances just to log user IDs.
A helper class has been added called
Unbox which can be used to convert a
primitive directly into a
StringBuilder that can be used (and re-used) by the
Logger methods. For example:
That particular change is only the tip of the iceberg, but it is something
that was added to log4j-api. Do note that if you implement the
ExtendedLogger interfaces manually instead of inheriting from
you will need to update your code. There were a large number of method additions
to these interfaces to accomodate garbage-free logging, so I encourage the use
of the abstract base classes. In order to take advantage of the new unrolled
methods, you’ll have to recompile your code, but I’m sure you do that all the
time anyways. Existing compiled code will still work (we take semantic
versioning of log4j-api seriously), but it will still use the varargs versions
of methods as expected.
One other important API addition to support garbage-free logging is the addition
Logger.log(CharSequence) style methods. For example, suppose you have code
that builds a
StringBuilder to format your own log message. Previously, this
would be converted to a
String which is an unnecessary allocation before it was
further used by another
StringBuilder later when formatting the log message to
Layout. Now you can log the
StringBuilder (or any
and no intermediary
String is created to hold it.
When it comes to log4j-core, most of the commonly used appenders, layouts,
filters, lookups, etc., have been also made garbage-free. The primary technique
used to make this garbage-free is to re-use objects as much as possible as well
as caching these objects in
ThreadLocals usually. However, this has major
implications to traditional web applications due to the use of thread pools and
the subsequent memory leaks caused by naively using
ThreadLocal in a web app.
Because of this, the use of
ThreadLocals is disabled by default when deployed
in a servlet container. This can be overridden via the system propery
log4j2.is.webapp with the value
false. Note that if you enable this in a web
app, you cannot undeploy or redeploy your web app without introducing memory
leaks. Instead, you’ll have to take down your whole servlet container and bring
it back up. When using projects like Spring Boot, this is a perfectly good
scenario to override the safe defaults. Another alternative is to deploy Log4j
directly to your server’s global libraries so that it isn’t part of any WAR
deployments (similar to how you should be using JDBC drivers).
Another API addition is the
LogManager.shutdown() method to manually
terminate Log4j. To support this in a custom Log4j provider, your
implementation must also implement
Terminable (only needed if your
LoggerContext needs to have a
One last thing of note is that we’ve improved the properties file syntax and support quite a bit in this release. This includes simplifications to the syntax as well as some bugfixes that only affected the properties format. There has been some experimental work done towards supporting log4j 1.x style properties files, but that particular feature hasn’t made it to a release yet. Despite the XML, JSON, and YAML formats being objectively better configuration file formats than the properties format, we’ll continue to improve properties support over time.
One last thing about configuration files: you can now merge multiple config files together to form a composite configuration!